mybatis插入数据后返回主键

一、Mybatis在插入单条数据的时候有两种方式返回自增主键:

  • 对于支持生成自增主键的数据库,可以使用useGenerateKeys和keyProperty 来返回插入后的主键;
  • 不支持生成自增主键的数据库,使用<selectKey>(例如oracle不支持自增主键)。

1、使用useGenerateKeys和keyProperty 来返回插入后的主键:

在insert标签中,parameterType可以是一个实体类,也可以是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、使用selectKey返回主键:

<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>

二、批量插入返回主键:

Mybatis官网资料提供如下:

First, if your database supports auto-generated key fields (e.g. MySQL and SQL Server), then you can simply set useGeneratedKeys="true" and set the keyProperty to the target property and you're done. For example, if the Authortable above had used an auto-generated column type for the id, the statement would be modified as follows:

<insert id="insertAuthor" useGeneratedKeys="true"
    keyProperty="id">
  insert into Author (username,password,email,bio)
  values (#{username},#{password},#{email},#{bio})
</insert>

If your database also supports multi-row insert, you can pass a list or an array of Authors and retrieve the auto-generated keys.

<insert id="insertAuthor" useGeneratedKeys="true"
    keyProperty="id">
  insert into Author (username, password, email, bio) values
  <foreach item="item" collection="list" separator=",">
    (#{item.username}, #{item.password}, #{item.email}, #{item.bio})
  </foreach>
</insert>

从官网资料可以看出Mybatis是支持批量插入时返回自增主键的。
但是在本地测试的时候使用上述方式确实不能返回自增id,而且还报错(不认识keyProperty中指定的Id属性),然后在网上找相关资料。终于在Stackoverflow上面找到了一些信息。
解决办法:

  1. 升级Mybatis版本到3.3.1。官方在这个版本中加入了批量新增返回主键id的功能
  2. 在Dao中不能使用@param注解。
  3. Mapper.xml中使用list变量(parameterType="java.util.List")接受Dao中的参数集合。

具体看一个例子:

<!-- 批量新增 -->
<insert id="batchInsert" parameterType="java.util.List" useGeneratedKeys="true" keyProperty="id" >
  INSERT INTO test (relation_id, summary_id, relation_type)
  VALUES
  <foreach collection="list" index="index" item="shopResource" separator=",">
    (#{shopResource.relationId}, #{shopResource.summaryId}, #{shopResource.relationType})
  </foreach>
</insert>
public List<ShopResource> batchinsertCallId(List<ShopResource> shopResourceList){
	testDao.batchInsert(shopResourceList);
	return shopResourceList;//包含了id
}

参考:https://blog.csdn.net/jiangeeq/article/details/55047116
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.使用存储过程。

 

 

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
MyBatis是一款基于Java的持久层框架,它的设计理念是将数据库操作与具体的SQL语句解耦,通过XML或注解的方式来配置SQL语句,并提供了强大的映射功能,能够将查询结果映射为Java对象。 在MyBatis中,插入数据返回主键有多种方式,其中比较常用的方式是使用数据库的自增长主键。下面是在MyBatis插入数据返回主键的源码解析: 1. 配置SQL语句:在XML文件或注解中配置插入SQL语句,并设置useGeneratedKeys属性为true,以启用主键返回功能。 2. 执行插入操作:通过MyBatis的SqlSession对象调用插入方法,传入SQL语句的参数。 3. SQL语句解析:MyBatis会根据配置的SQL语句解析生成相应的PreparedStatement对象。 4. 执行插入操作并返回主键MyBatis会通过PreparedStatement的executeUpdate方法执行插入操作,并获得影响的行数。如果配置了自动生成主键的功能,则会通过PreparedStatement的getGeneratedKeys方法获取到插入数据生成的主键。 5. 主键映射:如果返回主键是自动生成的,则MyBatis会根据配置的主键返回类型自动进行映射,将插入数据生成的主键值设置到对应的Java对象中。 6. 返回结果:最后,MyBatis会将插入操作的结果包装成对应的Java对象,并返回给调用方。 总结来说,MyBatis插入数据返回主键的过程是通过配置SQL语句和设置相关属性,然后执行插入操作并获取主键值,最后将主键值映射到Java对象中,返回给调用方。这样就可以方便地使用自动生成的主键值进行后续操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

赶路人儿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值