赞
踩
在《DM7与mybatis(一)——基本CRUD》中,我们介绍了dm7与mybatis的环境集成和基本配置,实现基本的CRUD操作。
在应用开发过程中,ID生成是一种常见的需求,通常基于数据库的自增列(如sqlserver、mysql)、序列(如Oracle)来自动生成。DM7同时支持自增列、序列,本文将介绍如何利用DM7和mybatis实现ID自动生成。
环境准备参见《DM7与mybatis(一)——基本CRUD》。
一、读取序列值生成ID
1、创建示例表和序列
-- 以test用户登录执行以下脚本 -- user_id序列 CREATESEQUENCE seq_user_id INCREMENTBY 1 STARTWITH 1 MAXVALUE 2147483647; -- 用户信息表 CREATETABLE t_user_seq ( id INTNOTNULL,--用户标识 name VARCHAR(20)NOTNULL,--姓名 phone VARCHAR(50),-- 手机 email VARCHAR(50),-- 邮箱 PRIMARYKEY(id) ); |
2、pojo对象
由于表t_user_seq和(一)当中表t_user的字段相同,我们可以复用原来的User对象以及对应的alias定义。
package org.dmstudy.mybatis.domain; publicclass User { private Integer id; private String name; private String phone; private String email; //getter/setter省略 } |
3、XML映射文件
在resources\mybatis-config.xml中,新增一个mapper配置,加载IdMapper.xml。
…… <mappers> <mapperresource="org/dmstudy/mybatis/crud/dao/UserMapper.xml"/> <mapperresource="org/dmstudy/mybatis/id/dao/IdMapper.xml"/> mappers> …… |
新增 org/dmstudy/mybatis/id/dao/IdMapper.xml文件,其内容如下:
xmlversion="1.0"encoding="UTF-8"?> DOCTYPEmapper PUBLIC"-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mappernamespace="org.dmstudy.mybatis.id.dao.IdMapper"> <selectid="getNextUserId"resultType="int"> select seq_user_id.nextval from dual select> <insertid="insert"parameterType="User"> insert into t_user_seq (id,name,phone,email) values (#{id},#{name},#{phone},#{email}) insert> mapper> |
注意namespace值对应为"org.dmstudy.mybatis.id.dao.IdMapper"。
其中id=getNextUserId的SELECT节点配置的sql语句是从序列seq_user_id中获取下一个序列值,该值根据定义从1开始,每次增量为1。
id=insert的INSERT节点配置了向表t_user_seq插入记录的语句。
4、Mapper接口
创建org.dmstudy.mybatis.id.dao.IdMapper.java文件,内容如下:
package org.dmstudy.mybatis.id.dao; import org.dmstudy.mybatis.domain.User; publicinterface IdMapper { int getNextUserId(); int insert(User user); } |
注意接口的全名org.dmstudy.mybatis.id.dao.IdMapper、接口方法getNextUserId、insert与IdMapper.xml中的namespace、语句映射节点id保持一致。
5、调用代码
package org.dmstudy.mybatis.id; …… publicclass IdApp { …… publicvoid insert() { System.out.println("--- insert ---"); // 新建user对象,注意未设置id值 User user = new User(); user.setName("dmtech"); user.setPhone("400-6489899"); user.setEmail("dmtech@dameng.com"); SqlSession sqlSession = sqlSessionFactory.openSession(); try { // 获取mapper对象 IdMapper mapper = sqlSession.getMapper(IdMapper.class); // 获取id值 Integer id = mapper.getNextUserId(); System.out.println("成功获取seq_user_id的nextval: " + id); // 设置id值 user.setId(id); // 将user插入数据库 intcnt = mapper.insert(user); sqlSession.commit(); System.out.println("成功插入 " + cnt + "条记录! "); } catch (Exception e) { System.out.println("insert执行失败 ,原因:" + e.getMessage()); e.printStackTrace(); sqlSession.rollback(); } finally { sqlSession.close(); } } } |
查看执行过程输出log4j日志信息
---insert --- DEBUG [main] - Opening JDBC Connection DEBUG [main] - Created connection 288994035. DEBUG [main] - Setting autocommit to false on JDBC Connection [dm.jdbc.driver.DmdbConnection@1139b2f3] DEBUG [main] - ==> Preparing: select seq_user_id.nextval from dual DEBUG [main] - ==> Parameters: DEBUG [main] - <== Total: 1 成功获取序列seq_user_id的nextval: 40 DEBUG [main] - ==> Preparing: insert into t_user_seq (id,name,phone,email) values (?,?,?,?) DEBUG [main] - ==> Parameters: 40(Integer), dmtech(String), 400-6489899(String), dmtech@dameng.com(String) DEBUG [main] - <== Updates: 1 DEBUG [main] - Committing JDBC Connection [dm.jdbc.driver.DmdbConnection@1139b2f3] 成功插入 1条记录! DEBUG [main] - Resetting autocommit to true on JDBC Connection [dm.jdbc.driver.DmdbConnection@1139b2f3] DEBUG [main] - Closing JDBC Connection [dm.jdbc.driver.DmdbConnection@1139b2f3] DEBUG [main] - Returned connection 288994035 to pool. |
当执行Integer id = mapper.getNextUserId()时,mybatis底层实际执行语句” selectseq_user_id.nextval from dual”,将返回值40(该值每次运行都会递增)作为ID值赋值给user参数,并插入到数据库表t_user_seq中。
二、直接插入序列表达式
1、XML映射文件
在IdMapper.xml文件中,新增一个语句映射节点“insertSeqExpr“,其内容如下:
<mappernamespace="org.dmstudy.mybatis.id.dao.IdMapper"> …… <insertid="insertSeqExpr"parameterType="User"> insert into t_user_seq (id,name,phone,email) values (seq_user_id.nextval,#{name},#{phone},#{email}) insert> mapper> |
2、Mapper接口
在IdMapper接口中,添加相应方法,内容如下:
package org.dmstudy.mybatis.id.dao; import org.dmstudy.mybatis.domain.User; publicinterface IdMapper { …… //直接用序列表达式作为id值插入 int insertSeqExpr(User user); } |
3、调用代码
package org.dmstudy.mybatis.id; …… publicclass IdApp { …… publicvoid insertSeqExpr() { System.out.println("--- insertSeqExpr ---"); // 新建user对象,不设置id值 User user = new User(); user.setName("dmtech"); user.setPhone("400-6489899"); user.setEmail("dmtech@dameng.com"); SqlSession sqlSession = sqlSessionFactory.openSession(); try { // 获取mapper对象 IdMapper mapper = sqlSession.getMapper(IdMapper.class); // 将user插入数据库 intcnt = mapper.insertSeqExpr(user); sqlSession.commit(); System.out.println("成功插入 " + cnt + "条记录! "); if (user.getId() == null) { System.out.println("无法获取插入后的id值: " + user.getId()); } else { System.out.println("成功获取插入后的id值: " + user.getId()); } } catch (Exception e) { System.out.println("insertSeqExpr执行失败 ,原因:" + e.getMessage()); e.printStackTrace(); sqlSession.rollback(); } finally { sqlSession.close(); } } } |
查看执行过程输出log4j日志信息
---insertSeqExpr --- DEBUG [main] - Opening JDBC Connection DEBUG [main] - Checked out connection 288994035 from pool. DEBUG [main] - Setting autocommit to false on JDBC Connection [dm.jdbc.driver.DmdbConnection@1139b2f3] DEBUG [main] - ==> Preparing: insert into t_user_seq (id,name,phone,email) values (seq_user_id.nextval,?,?,?) DEBUG [main] - ==> Parameters: dmtech(String), 400-6489899(String), dmtech@dameng.com(String) DEBUG [main] - <== Updates: 1 DEBUG [main] - Committing JDBC Connection [dm.jdbc.driver.DmdbConnection@1139b2f3] 成功插入 1条记录! 无法获取插入后的id值: null DEBUG [main] - Resetting autocommit to true on JDBC Connection [dm.jdbc.driver.DmdbConnection@1139b2f3] DEBUG [main] - Closing JDBC Connection [dm.jdbc.driver.DmdbConnection@1139b2f3] DEBUG [main] - Returned connection 288994035 to pool. |
注意该方法执行时,只有name、phone、email列是用输入参数user的属性值设置,而id列则直接使用表达式 seq_user_id.nextval 作为值。
在插入成功后,利用DM7管理工具可以在数据库中查看t_user_seq可以发现已经新增了记录并且id值也生成了。对于输入参数user对象,我们试图访问user的id属性,发现仍然是null。
相对于上一种方法,本方法只需定义一个节点和一个接口方法,程序相对简单。但本方法最大的不足在于id值是在数据库中执行sql语句时产生,我们没法马上知道该值具体是多少,对于不怎么关心ID值的场景(如插入新日志记录)问题不大,对于有些业务场景必须马上获取新增记录的ID(如新增记录ID需要传入到下一流程,主表记录ID需要作为字表记录外键等)则不合适。
三、使用SelectKey返回序列值
1、XML映射文件
Mybatis提供了标签,可以帮助用户在获取ID值后,一方面作为作为sql执行的参数,同时还会把ID值反写到输入对象参数中。
在IdMapper.xml文件中,新增一个语句映射节点“insertSequence“,其内容如下:
<mappernamespace="org.dmstudy.mybatis.id.dao.IdMapper"> …… <insertid="insertSequence"parameterType="User"> <selectKeyresultType="int"keyProperty="id"order="BEFORE"> select seq_user_id.nextval from dual selectKey> insert into t_user_seq (id,name,phone,email) values (#{id},#{name},#{phone},#{email}) insert> mapper> |
注意selectKey中的sql语句用来获取ID值,order="BEFORE"表示该语句会在主体的insert语句之前执行。
2、Mapper接口
在IdMapper接口中,添加相应方法,内容如下:
package org.dmstudy.mybatis.id.dao; import org.dmstudy.mybatis.domain.User; publicinterface IdMapper { …… //使用序列插入id int insertSequence(User user); } |
3、调用代码
package org.dmstudy.mybatis.id; …… publicclass IdApp { …… publicvoid insertSequence() { System.out.println("--- insertSequence ---"); // 新建user对象,不设置id值 User user = new User(); user.setName("dmtech"); user.setPhone("400-6489899"); user.setEmail("dmtech@dameng.com"); SqlSession sqlSession = sqlSessionFactory.openSession(); try { // 获取mapper对象 IdMapper mapper = sqlSession.getMapper(IdMapper.class); // 将user插入数据库 intcnt = mapper.insertSequence(user); sqlSession.commit(); System.out.println("成功插入 " + cnt + "条记录! "); if (user.getId() == null) { System.out.println("无法获取插入后的id值: " + user.getId()); } else { System.out.println("成功获取插入后的id值: " + user.getId()); } } catch (Exception e) { System.out.println("insertSequence执行失败 ,原因:" + e.getMessage()); e.printStackTrace(); sqlSession.rollback(); } finally { sqlSession.close(); } } } |
查看执行过程输出log4j日志信息
---insertSequence --- DEBUG [main] - Opening JDBC Connection DEBUG [main] - Checked out connection 288994035 from pool. DEBUG [main] - Setting autocommit to false on JDBC Connection [dm.jdbc.driver.DmdbConnection@1139b2f3] DEBUG [main] - ==> Preparing: select seq_user_id.nextval from dual DEBUG [main] - ==> Parameters: DEBUG [main] - <== Total: 1 DEBUG [main] - ==> Preparing: insert into t_user_seq (id,name,phone,email) values (?,?,?,?) DEBUG [main] - ==> Parameters: 42(Integer), dmtech(String), 400-6489899(String), dmtech@dameng.com(String) DEBUG [main] - <== Updates: 1 DEBUG [main] - Committing JDBC Connection [dm.jdbc.driver.DmdbConnection@1139b2f3] 成功插入 1条记录! 成功获取插入后的id值: 42 DEBUG [main] - Resetting autocommit to true on JDBC Connection [dm.jdbc.driver.DmdbConnection@1139b2f3] DEBUG [main] - Closing JDBC Connection [dm.jdbc.driver.DmdbConnection@1139b2f3] DEBUG [main] - Returned connection 288994035 to pool. |
从调用代码看,跟方法二直接插入序列表达式的调用代码一样。从实际执行情况看,本方法首先执行了中定义的语句,并将其返回值42作为id的参数,执行主体的sql语句。
执行成功后,我们试图获取输入参数user对象的id属性,发现其值已经被设置为42,即刚刚生成的ID值。
四、使用SelectKey返回自增列值
DM7不仅支持序列,也支持自增列,对原来习惯mysql、sqlserver的用户,可以参考下面的方法。
1、创建示例表
以test用户登录,执行以下脚本:
-- 以test用户登录执行脚本 -- 以test用户登录执行 -- 用户信息表 CREATETABLE t_user_ident ( id INTIDENTITY(1,1)NOTNULL,--用户标识 name VARCHAR(20)NOTNULL,--姓名 phone VARCHAR(50),-- 手机 email VARCHAR(50),-- 邮箱 PRIMARYKEY(id) ); |
创建表t_user_ident,其中id列使用了自增列,从1开始,每次增量为1。
2、XML映射文件
在IdMapper.xml文件中,新增一个语句映射节点“insertIdentity“,其内容如下:
<mappernamespace="org.dmstudy.mybatis.id.dao.IdMapper"> …… <insertid="insertIdentity"parameterType="User"> <selectKeyresultType="int"keyProperty="id"order="AFTER"> select @@identity selectKey> insert into t_user_ident (name,phone,email) values (#{name},#{phone},#{email}) insert> mapper> |
order=" AFTER "表示该语句会在主体的insert语句之后执行,而select @@identity语句则是返回刚刚插入的自增列的值。
2、Mapper接口
在IdMapper接口中,添加相应方法,内容如下:
package org.dmstudy.mybatis.id.dao; import org.dmstudy.mybatis.domain.User; publicinterface IdMapper { …… //使用自增列插入id int insertIdentity(User user); } |
3、调用代码
package org.dmstudy.mybatis.id; …… publicclass IdApp { …… publicvoid insertIdentity() { System.out.println("--- insertIdentity ---"); // 新建user对象,不设置id值 User user = new User(); user.setName("dmtech"); user.setPhone("400-6489899"); user.setEmail("dmtech@dameng.com"); SqlSession sqlSession = sqlSessionFactory.openSession(); try { // 获取mapper对象 IdMapper mapper = sqlSession.getMapper(IdMapper.class); // 将user插入数据库 intcnt = mapper.insertIdentity(user); sqlSession.commit(); System.out.println("成功插入 " + cnt + "条记录! "); if (user.getId() == null) { System.out.println("无法获取插入后的id值: " + user.getId()); } else { System.out.println("成功获取插入后的id值: " + user.getId()); } } catch (Exception e) { System.out.println("insertIdentity执行失败 ,原因:" + e.getMessage()); e.printStackTrace(); sqlSession.rollback(); } finally { sqlSession.close(); } } } |
查看执行过程输出log4j日志信息
---insertIdentity --- DEBUG [main] - Opening JDBC Connection DEBUG [main] - Checked out connection 288994035 from pool. DEBUG [main] - Setting autocommit to false on JDBC Connection [dm.jdbc.driver.DmdbConnection@1139b2f3] DEBUG [main] - ==> Preparing: insert into t_user_ident (name,phone,email) values (?,?,?) DEBUG [main] - ==> Parameters: dmtech(String), 400-6489899(String), dmtech@dameng.com(String) DEBUG [main] - <== Updates: 1 DEBUG [main] - ==> Preparing: select @@identity DEBUG [main] - ==> Parameters: DEBUG [main] - <== Total: 1 DEBUG [main] - Committing JDBC Connection [dm.jdbc.driver.DmdbConnection@1139b2f3] 成功插入 1条记录! 成功获取插入后的id值: 25 DEBUG [main] - Resetting autocommit to true on JDBC Connection [dm.jdbc.driver.DmdbConnection@1139b2f3] DEBUG [main] - Closing JDBC Connection [dm.jdbc.driver.DmdbConnection@1139b2f3] DEBUG [main] - Returned connection 288994035 to pool. |
从调用代码看,跟前面两种方法的调用代码一样,但底层sql实际执行情况不一样。本方法首先执行的是主体中的insert语句,而且id列也没有出现在insert列中,是由数据库自增列来产生值。随后执行了中定义的语句。最后检查输入参数user对象的id属性,发现其值也已经被设置,其值25跟数据库中刚插入的记录一致。
五、使用GeneratedKeys返回自增列值
对于刚刚插入的自增列的值,除了使用select@@identity 返回,还可以利用jdbc提供的RETURN_GENERATED_KEYS选项来获取,mybatis支持该方法。
1、XML映射文件
在IdMapper.xml文件中,新增一个语句映射节点“insertUseGeneratedKeys“,其内容如下:
<mappernamespace="org.dmstudy.mybatis.id.dao.IdMapper"> …… <insertid="insertUseGeneratedKeys" parameterType="User"useGeneratedKeys="true"keyProperty="id"> insert into t_user_ident (name,phone,email) values (#{name},#{phone},#{email}) insert> mapper> |
useGeneratedKeys="true"表示mybatis执行该语句时,会在创建PreparedStatement对象时添加PreparedStatement.RETURN_GENERATED_KEYS标记,这样jdbc驱动会在执行成功后额外返回一个结果集,其中包含了服务器端刚生成的ID值。
2、Mapper接口
在IdMapper接口中,添加相应方法,内容如下:
package org.dmstudy.mybatis.id.dao; import org.dmstudy.mybatis.domain.User; publicinterface IdMapper { …… int insertUseGeneratedKeys(User user); } |
3、调用代码
package org.dmstudy.mybatis.id; …… publicclass IdApp { …… publicvoid insertUseGeneratedKeys() { System.out.println("--- insertUseGeneratedKeys ---"); // 新建user对象,不设置id值 User user = new User(); user.setName("dmtech"); user.setPhone("400-6489899"); user.setEmail("dmtech@dameng.com"); SqlSession sqlSession = sqlSessionFactory.openSession(); try { // 获取mapper对象 IdMapper mapper = sqlSession.getMapper(IdMapper.class); // 将user插入数据库 intcnt = mapper.insertUseGeneratedKeys(user); sqlSession.commit(); System.out.println("成功插入 " + cnt + "条记录! "); if (user.getId() == null) { System.out.println("无法获取插入后的id值: " + user.getId()); } else { System.out.println("成功获取插入后的id值: " + user.getId()); } } catch (Exception e) { System.out.println("insertUseGeneratedKeys执行失败 ,原因:" + e.getMessage()); e.printStackTrace(); sqlSession.rollback(); } finally { sqlSession.close(); } } } |
查看执行过程输出log4j日志信息
---insertUseGeneratedKeys --- DEBUG [main] - Opening JDBC Connection DEBUG [main] - Checked out connection 288994035 from pool. DEBUG [main] - Setting autocommit to false on JDBC Connection [dm.jdbc.driver.DmdbConnection@1139b2f3] DEBUG [main] - ==> Preparing: insert into t_user_ident (name,phone,email) values (?,?,?) DEBUG [main] - ==> Parameters: dmtech(String), 400-6489899(String), dmtech@dameng.com(String) DEBUG [main] - <== Updates: 1 DEBUG [main] - Committing JDBC Connection [dm.jdbc.driver.DmdbConnection@1139b2f3] 成功插入 1条记录! 成功获取插入后的id值: 26 DEBUG [main] - Resetting autocommit to true on JDBC Connection [dm.jdbc.driver.DmdbConnection@1139b2f3] DEBUG [main] - Closing JDBC Connection [dm.jdbc.driver.DmdbConnection@1139b2f3] DEBUG [main] - Returned connection 288994035 to pool. |
从调用代码看,跟前面几种方法的调用代码一样,底层执行的sql语句只有主体中的insert语句,而最后检查输入参数user对象的id属性,发现其值也已经被正确设置,其值26跟数据库中刚插入的记录一致。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。