Mybatis 深入浅出之useGeneratedKeys

Mybatis 深入浅出之useGeneratedKeys

针对单条数据insert(或update)时useGeneratedKeys
批量操作使用ON DUPLICATE KEY,这里不做说明



一、关于useGeneratedKeys疑惑点

写这个记录主要是在复习Mybatis时,写了一段CRUD时,对自己的写的业务所呈现的结果感到很诧异,跟自己记忆中的不大一样,所以写了这篇文章做记录,问题如下:
Order.java

public class Order {
	private Long id;
	private String serial;
}

orderMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org/DTD Mapper 3.0" 
	"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.vic.mybatis.dao.OrderDao">
	<insert id="createOrder" useGeneratedKeys="true" keyProperty="id">
		insert into t_order(serial) values (#{serial})
	</insert>
</mapper>

OrderDao.java

@Mapper
public interface OrderDao {
    public int createOrder(Order order);
}

OrderServiceImpl.java

@Service
@Slf4j
public class OrderServiceImpl implements OrderService {

    @Resource
    private OrderDao orderDao;

    @Override
    public int createOrder(Order order) {
    	// 这个result是否就是插入数据成功后返回的主键ID?
    	int id = orderDao.createOrder(order);
    	log.info(" *****插入数据后返回的id: " + id + " *****");
    	log.info(" *****插入数据后返回的id: " + order.getId() + " *****");
        return result;
    }
}

针对上面我写的业务,在OrderServiceImpl.java中输出的两行信息里,第一行永远是 1(因为我插入后数据库插入了一条数据,这里认为它插入数据成功,因为它还有不成功情况,这里先不讲)
但是当我插入到第5条数据后返回1时,发现我又菜了一点,因为我疑惑了,这个createOrder 方法返回的到底是执行sql的状态呢,还是说应该返回的是这个数据的主键ID?因为我设置了 useGeneratedKeys="true", 它的定义不就是约定产生主键并返回吗?
带着我的疑惑,鄙人开始了一番骚操作,查文档,看源码,就像看看useGeneratedKeys这个参数是个什么鬼。
如下,啰嗦务怪,技术不够,废话来凑,争取下次我一看这篇文章就懂:


二、useGeneratedKeys 官方定义?

  1. 首先我们看下mybatis对于mapper中useGeneratedKey的描述官网描述

(insert and update only) This tells MyBatis to use the JDBC getGeneratedKeys method to retrieve keys generated internally by the database (e.g. auto increment fields in RDBMS like MySQL or SQL Server). Default: false.

就是使用JDBC的getGeneratedKeys的方法来获取的,而且只有insertupdate 生效。但是注意, 我上面小标题中写的是mapper中的, 为什么呢, 因为Configuration和Mapper接口映射注解中也有

  1. 我们看下mybatis对于Configuration中useGeneratedKey的描述官网描述

Allows JDBC support for generated keys. A compatible driver is required. This setting forces generated keys to be used if set to true, as some drivers deny compatibility but still work (e.g. Derby). Default: false.

允许JDBC支持自动生成主键。需要兼容的驱动程序。如果设置为true,此设置将强制使用生成主键,因为某些驱动程序拒绝兼容性,但仍然有效(例如Derby),而且出现在setting中时,它将全局生效。

  1. 我们看下mybatis对于注解映射中useGeneratedKey的描述官网描述

@Options This annotation provides access to the wide range of switches and configuration options that are normally present on the mapped statement as attributes

@Options注解提供了对广泛开关和配置选项的访问,这些开关和配置选项通常作为属性出现在映射语句中,就是也就是说这个配置了后,它会直接作为属性出现在映射语句中,会覆盖上面Configuration(setting)中的配置

三、Mybatis中的useGeneratedKeys?

这里不深究useGeneratedKeys它的工作过程或者原理。


3.1、对于Configuration(setting)中useGeneratedKey

<settings>
	<setting name="useGeneratedKeys" value="true" />
</settings>

在执行insert成功之后可以获取到数据库自动生成的主键ID,因为在settings元素中设置useGeneratedKeys是全局生效的,但实际是只会对接口映射器(没有同时配置@Options注解情况下)产生影响,对xml映射器不起效。

3.2、对于mapper中useGeneratedKey

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org/DTD Mapper 3.0" 
	"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.vic.mybatis.dao.OrderDao">
	<insert id="createOrder" useGeneratedKeys="true" keyProperty="id">
		insert into t_order(serial) values (#{serial})
	</insert>
</mapper>

在mapper(xml)中配置的useGeneratedKeys属性只会对当前mapper(xml映射器)产生影响,且在settings元素中设置的全局useGeneratedKeys参数值对于mapper(xml映射器)不产生任何作用。

3.3、对于注解映射中useGeneratedKey

@Options(useGeneratedKeys = true, keyProperty = "id", keyColumn = "id")
@Insert("insert into t_order(serial) values(#{serial})")
Integer createOrder(Order order);

在同时在Configuration(setting) 和 接口映射器中都添加了useGeneratedKeys属性, 无论属性值是否相同, 接口映射器的优先级会高于Configuration(setting) 的优先级;
也就说,不管你在Configuration(setting) 中设置useGeneratedKeys 为 true 或者 false,只要你在接口映射器中设置了@Options(useGeneratedKeys = true), 那么就会返回主键ID,如果@Options(useGeneratedKeys = false),那么就不会返回主键ID

四、基于前面的问题?

设置了useGeneratedKeys = true的情况下,执行insert(或者update)后,会返回主键ID,那么我在问题中上面OrderServiceImpl.java中输出两个信息里面, 第一个输出是执行状态,第二是主键ID。
那么在执行完createOrder方法后返回的到底是什么?
Bug执行insert操作最终走向
如上图,我们执行insert操作后,最终都走向了这里,你没看错,就是update方法,它返回了ps.getUpdateCount()的结果, 这个方法很熟悉吧,单纯使用JDBC操作数据那会儿,还有映象吗?我还是贴一张图吧
结果集

Retrieves the current result as an update count;

还有-1情况,说人话就是,受影响行数。


好了,就介绍到这里吧,加油~骚年,拼命吧大叔。

下一篇看看insert 过程以及主键产生过程

如果写错或者不妥善地方, 欢迎大佬留言指正,不喜勿碰,感谢各位大佬

如果有来生,我要做一棵树,站成永恒,没有悲欢的姿势,一半在尘土里安详,一半在风里飞扬;一半洒落荫凉,一半沐浴阳光,非常沉默、非常骄傲。从不依靠、从不寻找。
如果有来生,我要化成一阵风,一瞬间也能成为永恒。没有善感的情怀,没有多情的眼睛。一半在雨里洒脱,一半在春光里旅行;寂寞了,孤自去远行,把淡淡的思念统带走,从不思念、从不爱恋。 ------三毛

猜你喜欢

转载自blog.csdn.net/H1101370034/article/details/121231207