现在的位置: 首页 > 综合 > 正文

mybatis 返回主键

2018年05月07日 ⁄ 综合 ⁄ 共 2316字 ⁄ 字号 评论关闭

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

在service中执行以下代码,将获取不到id
BookServiceImpl:
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.使用存储过程。

抱歉!评论已关闭.