本篇介绍一下Mybatis中selectKey的使用。

在开发过程中,CRUD是免不了的,在插入数据时,通常我们只需要返回受影响行数即可,但也有些场景需要返回插入数据后的主键ID,在Mybatis中只需要使用selectKey即可实现。

自增主键使用示例

通常我们会将SQL写在MyBatis的*Mapper.xml文件中,本次示例也是如此

创建表

1
2
3
4
5
6
7
CREATE TABLE `t_user` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT 'UserId',
`username` varchar(80) NOT NULL COMMENT 'username',
`password` varchar(80) NOT NULL COMMENT 'password',
`create_time` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT 'create_time',
PRIMARY KEY (`id`)
) ENGINE=InnoDB

插入数据并返回自增主键

1
2
3
4
5
6
7
8
9
10
11
12
<?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="xyz.cco.sm.mapper.UserMapper">
<insert id="saveUser" parameterType="xyz.cco.sm.mapper.entity.UserEntity">
insert into t_user (username,password) values (#{username},#{password})
<selectKey keyProperty="id" order="AFTER" resultType="Long">
SELECT LAST_INSERT_ID()
</selectKey>
</insert>
</mapper>
  • selectKey会将SELECT LAST_INSERT_ID()的结果存放在传入的UserEntity中的id属性中。
  • keyProperty的值是UserEntity中主键的属性名,本次的值是id
  • order,它的值有两种,AFTERBEFORE:
    • AFTER表示SELECT LAST_INSERT_ID()insert语句执行之后执行,多用与自增主键(例如MySQL)
    • BEFORE表示SELECT LAST_INSERT_ID()insert语句执行之前执行,多用于主键不自增(例如Oracle的sequence)
  • resultType主键的类型。

非自增主键使用示例

这里主要指Oracle,Oracle没有MySQL那种自增主键,通常都是使用sequence来实现的自增。

创建表

1
2
3
4
create table t_grade(
gid number(6) primary key, --主键
gradeName varchar2(20) not null -- 年级名称
);

创建sequence

1
2
3
4
5
6
CREATE SEQUENCE g_seq
INCREMENT BY 1 -- 每次加几个
START WITH 1 -- 从1开始计数
NOMAXvalue -- 不设置最大值
NOCYCLE -- 一直累加,不循环
CACHE 10;

插入数据并返回自增序列

1
2
3
4
5
6
7
8
9
10
11
12
<?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="xyz.cco.sm.mapper.GradeMapper">
<insert id="saveUser" parameterType="xyz.cco.sm.mapper.entity.GradeEntity">
<selectKey keyProperty="gid" order="BEFORE" resultType="Long">
SELECT G_SEQ.NEXTVAL FROM dual
</selectKey>
insert into t_grade (gid,gradeName) values (#{gid},#{gradeName})
</insert>
</mapper>
  • orader的值一定是BEFORE
  • insert语句必须要将主键ID加上去

业务层逻辑

上面两个分部介绍了MySQL自增ID的用法,以及Oracle的序列用法,刚开始我以为返回值就是插入数据的主键ID,结果测试发现每次都是1,没仔细阅读文档,实际上它是将主键ID设置在了传入的Entity类里面了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class UserServiceImpl implements UserService {

private final UserMapper userMapper;

public UserServiceImpl(UserMapper userMapper) {
this.userMapper = userMapper;
}

@Override
public Long insertUserAndGetPrimaryKey(UserBo userBo) {
UserEntity entity = new UserEntity();
BeanUtils.copyProperties(userBo, entity);
userMapper.saveUser(entity);
return entity.getId();
}
}

注意return的是entity.getId(),而不是userMapper.saveUser(entity)的返回值。