Mybatis回写主键的值

前言

每种数据库都有自己的主键生成方式,比如MySQL支持自增的主键, 在插入数据后自动生成主键, 比如Oracle通过序列的方式, 在插入数据之前生成主键, 再写去表中。

环境准备

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public interface UserMapper {
int insert(User User);
}
public class User {
Long id;
String name;
// 省略构造函数和getter setter方法
}
public class MyTest {
@Test
public void testInsert() throws IOException {
// 1. 初始化 SqlSession
Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader);
try(SqlSession sqlSession = factory.openSession()){
// 2. 获取Mapper
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
User user = new User();
user.setName("测试用户");
System.out.println(user);
int result = userMapper.insert(user);
Assert.assertEquals(1, result);
// 3. 判断主键回写成功
Assert.assertNotNull(user.getId());
System.out.println(user);
}
}
}

使用JDBC的useGeneratedKeys获取主键值

只支持插入数据后生成主键的数据库。如MySQLSQLServer
底层是使用了JDBCstatement.getGeneratedKeys()

1
2
3
4
5
6
7
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.ahao.demo.mapper.UserMapper">
<insert id="insert" useGeneratedKeys="true" keyProperty="id">
insert sys_user(id, name) values (#{id}, #{name})
</insert>
</mapper>

使用selectKey获取主键值

useGeneratedKeys局限于主键自增的数据库, 不支持Oracle这种先生成主键, 再把主键插入数据库中的形式。
selectKey两者都支持, 缺点就是比较笨重, 需要写多一点xml代码。

1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.ahao.demo.mapper.UserMapper">
<insert id="insert">
<selectKey keyProperty="id" keyColumn="id" resultType="Long" order="AFTER">
select LAST_INSERT_ID()
</selectKey>
insert sys_user(id, name) values (#{id}, #{name})
</insert>
</mapper>

keyProperty指的是实体的field名称, keyColumn指的是数据表的column名称, resultType指定返回的Java类型。
order分为AFTERBEFORE, 因为MySQL中, 主键是在插入数据之后生成的, 所以选择AFTEROracle则要选Before
需要注意的是, selectKey的位置不会影响结果, 最好是根据实际情况来选择放置位置, 比如MySQL就放在SQL之前, 表示先生成主键后插入数据。

各数据库回写主键的SQL

  • MySQLSELECT LAST_INSERT_ID()
  • Sql ServerSELECT SCOPE_IDENTITY()
  • OracleSELECT SEQ_ID.nextval from dual
  • Db2VALUES IDENTITY_VAL_LOCAL()
  • HSQLDBCALL IDENTITY()

不使用实体类获取主键