1、mybatis插入一条数据,返回主键id,传入的参数可以是一个实体类,也可以是map。如下:
< insert id = “doSomething" parameterType = "map" useGeneratedKeys = "true" keyProperty = “yourId" > ... </ insert > 或 < insert id = “doSomething" parameterType = “com.xx.yy.zz.YourClass" useGeneratedKeys = "true" keyProperty = “yourId" > ... </ insert >
java代码:
public int doSomething(Map<String, Object> parameters); 或者 public int doSomething (YourClass c); 要在map或c中有一个字段名为yourId,Mybatis会自动把主键值赋给这个字段。 Map<String, Object> parameters = new HashMap<String, Object>(); parameters.put(“yourId”, 1234); ... mapper.doSomething(parameters); System.out.println(“id of the field that is primary key” + parameters.get(“yourId")); 或 YourClass c = new YourClass(); ... mapper.doSomething(c); System.out.println(“id of the field that is primary key” + c.yourId);
2、可以在xml中使用下面的方式配置:
<insert id="insertProduct-Mysql" parameterClass="com.domain.Product"> insert into PRODUCT(PRD_DESCRIPTION) values (#description#) <selectKey resultClass="int" keyProperty="id"> SELECT LAST_INSERT_ID() </selectKey> </insert>
3、注意:
在用Spring管理事务时,SelectKey和插入在同一事务当中,因而Mysql这样的情况由于数据未插入到数据库中,所以是得不到自动增长的Key。取消事务管理就不会有问题。
例如:
<insert id="insert" parameterType="com.xxx.Book" useGeneratedKeys="true" keyProperty="id"> insert into t_books(name) values (#{name,jdbcType=VARCHAR}) <selectKey resultType="java.lang.Long" order="AFTER" keyProperty="id" > SELECT LAST_INSERT_ID() </selectKey> </insert>
我使用的环境是struts2+spring3+mybatis3.2.2,很典型的三层开发架构,action,service,dao,事务控制在service层。
在action中执行以下代码,完全可获取id
bookService.insert(book); System.out.println("book id = "+book.getId()); //打出正确的id
bookDao.insert(book); System.out.println("book id = "+book.getId()); //打出null
神奇吧,我不知道你们的是不是这样,总之,我这个是了。
于是开始断点调试+追踪sql执行日志,发现了端倪。当执行完 bookDao.insert(book);这行代码后,控制台打出insert 语句,
但未见select last_insert_id()执行,再执行到下一行,打印book id时,结果为null
于是继续执行到action中的下一行(println()那一行),此时见控制台,神奇的出现了select last_insert_id()。
有点明白了,应该是当事务提交时,才会去执行select last_insert_id()。因为事务在service层,只要没有离开service,事务一直有效,一旦离开service,事务立即提交。此时select last_insert_id()才会执行,并将id填充进book对象中。
这个问题造成的后果就是,在service中插入主从表关联数据时,由于不能立即获取主表id,导致插入从表数据时,不能填充主表id(有点拗口,自己体会)。
这个也就是我现在项目遇到的问题,也就是我花时间写这篇文章分享的原因。
解决办法
1.将主从表插入操作分成两个service方法,一个方法插入主表,一个方法插入从表。这样在action中,先插入主表后,就能拿到id,再传给从表。这种解决方法其实将一个事务完成的操作,拆分成两个事务完成,有数据完整性风险。
2.照样是一个service方法,完成主从表操作,但不要为此service设置事务,mybatis默认为每条执行的sql都单独开一个事务,语句执行完后,事务就提交,select last_insert_id()也会立即执行。在我这里只要将service类的@Transactional注解去掉就可以了。
3.使用存储过程。