mybatis提供了两种方式获取数据库自增主键:
1、通过useGeneratedKeys、keyProperty、keyColumn
2、通过 标签。
在获取数据库自增主键时,我们一般会把数据库主键设置为自动增长的,如有一张数据库表user定义如下:
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT, #自增
`name` varchar(255) NOT NULL,
`age` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
对应的User类:
public class User {
private Integer id;
private String name;
private Integer age;
//...setters and getters
//...to string...
}
useGeneratedKeys
、keyProperty
、keyColumn
属性,仅能在
或者
元素中使用。作用分别如下所示:
useGeneratedKeys :
这会令 MyBatis 使用 JDBC 的ResultSet.getGeneratedKeys 方法来取出由数据库内部生成的主键(比如:像 MySQL 和 SQL Server 这样的关系数据库管理系统的自动递增字段),默认值:false。
keyProperty:
唯一标记一个属性,MyBatis 会通过 ResultSet.getGeneratedKeys 的返回值,默认:unset。如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表。
keyColumn :
通过生成的键值设置表中的列名,这个设置仅在某些数据库(像 PostgreSQL)是必须的,当主键列不是表中的第一列的时候需要设置。如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表。
如果你的数据库支持自动生成主键的字段(比如 MySQL 和 SQL Server),那么你可以设置 useGeneratedKeys=”true”,然后再把 keyProperty 设置到目标属性上就OK了。如果你的数据库还支持多行插入, 你也可以传入一个数组或集合,并返回自动生成的主键。下面分别进行演示:
获取插入的单条记录的自增id:
<insert id="insert" parameterType="User" useGeneratedKeys="true" keyProperty="id">
INSERT INTO user (name, age) VALUES (#{name}, #{age})
insert>
测试代码如下:
@Test
public void testInsert() {
User user = new User();
user.setName("tianshouzhi");
user.setAge(27);
System.out.println("插入前 id:" + user.getId());
sqlSession.insert("com.tianshouzhi.mybatis.batch.mappers.UserMapper.insert", user);
System.out.println("插入后:" + user.getId());
}
运行程序后控制台输出:
插入前:User{id=null, name='tianshouzhi', age=27}
23:16:10.935 [main] DEBUG com.tianshouzhi.mybatis.batch.mappers.UserMapper.insert - ==> Preparing: INSERT INTO user ( name, age) VALUES ( ?, ?)
23:16:10.998 [main] DEBUG com.tianshouzhi.mybatis.batch.mappers.UserMapper.insert - ==> Parameters: tianshouzhi(String), 27(Integer)
23:16:11.107 [main] DEBUG com.tianshouzhi.mybatis.batch.mappers.UserMapper.insert - <== Updates: 1
插入后:User{id=1, name='tianshouzhi', age=27}
获取批量插入的记录自增id
需要注意的是:获取批量插入的数据自增id之前存在bug,直接mybatis3.4.0之后才修复,读者需要保证mybatis版本>=3.4.0
<insert id="batchInsert" parameterType="java.util.List" useGeneratedKeys="true" keyProperty="id">
INSERT INTO user (id, name, age) VALUES
<foreach collection="list" item="user" index="index" separator="," >
(#{user.id}, #{user.name}, #{user.age})
foreach>
insert>
测试代码如下:
@Test
public void testBatchInsert() {
User user1 = new User();
user1.setName("tianshouzhi");
user1.setAge(27);
User user2 = new User();
user2.setName("wangxiaoxiao");
user2.setAge(26);
List<User> userList = new ArrayList<User>();
userList.add(user1);
userList.add(user2);
System.out.println("插入前:" + userList);
sqlSession.insert("com.tianshouzhi.mybatis.batch.mappers.UserMapper.batchInsert", userList);
System.out.println("插入后:" + userList);
}
运行程序后输出:
插入前:[User{id=null, name='tianshouzhi', age=27}, User{id=null, name='wangxiaoxiao', age=26}]
23:16:42.894 [main] DEBUG com.tianshouzhi.mybatis.batch.mappers.UserMapper.batchInsert - ==> Preparing: INSERT INTO user (id, name, age) VALUES (?, ?, ?) , (?, ?, ?)
23:16:42.956 [main] DEBUG com.tianshouzhi.mybatis.batch.mappers.UserMapper.batchInsert - ==> Parameters: null, tianshouzhi(String), 27(Integer), null, wangxiaoxiao(String), 26(Integer)
23:16:43.112 [main] DEBUG com.tianshouzhi.mybatis.batch.mappers.UserMapper.batchInsert - <== Updates: 2
插入后:[User{id=2, name='tianshouzhi', age=27}, User{id=3, name='wangxiaoxiao', age=26}]
对于不支持自动生成类型的数据库或可能不支持自动生成主键 JDBC 驱动来说,MyBatis 有另外一种方法来生成主键。通过
。如下:
<insert id="insertSelectKey" parameterType="User">
<selectKey keyProperty="id" resultType="int" order="AFTER">
SELECT last_insert_id();
selectKey>
INSERT INTO user ( name, age) VALUES ( #{name}, #{age})
insert>
这里的的作用,在INSERT语句执行完成之后(order=“AFTER”),执行sql: SELECT last_insert_id();语句,获得自增id。这是mysql提供的获取上一次插入记录的自增id的语法,其他数据库中可能不同。
测试代码如下:
@Test
public void insertSelectKey() {
User user = new User();
user.setName("tianshouzhi");
user.setAge(27);
System.out.println("插入前:" + user);
sqlSession.insert("com.tianshouzhi.mybatis.batch.mappers.UserMapper.insertSelectKey", user);
System.out.println("插入后:" + user);
}
运行程序后,控制台输出:
插入前:User{id=null, name='tianshouzhi', age=27}
23:30:14.961 [main] DEBUG com.tianshouzhi.mybatis.batch.mappers.UserMapper.insertSelectKey - ==> Preparing: INSERT INTO user ( name, age) VALUES ( ?, ?)
23:30:15.008 [main] DEBUG com.tianshouzhi.mybatis.batch.mappers.UserMapper.insertSelectKey - ==> Parameters: tianshouzhi(String), 27(Integer)
23:30:15.102 [main] DEBUG com.tianshouzhi.mybatis.batch.mappers.UserMapper.insertSelectKey - <== Updates: 1
23:30:15.102 [main] DEBUG com.tianshouzhi.mybatis.batch.mappers.UserMapper.insertSelectKey!selectKey - ==> Preparing: SELECT last_insert_id();
23:30:15.102 [main] DEBUG com.tianshouzhi.mybatis.batch.mappers.UserMapper.insertSelectKey!selectKey - ==> Parameters:
23:30:15.102 [main] DEBUG com.tianshouzhi.mybatis.batch.mappers.UserMapper.insertSelectKey!selectKey - <== Total: 1
插入后:User{id=4, name='tianshouzhi', age=27}
可以看到这里同样获取到了数据库自增id。
因此,笔者建议在绝大部分情况下,都应该使用useGeneratedKeys、keyProperty的方式来获取自增id。只有在数据库不支持自增id的情况下 ,你才应该使用,并将order属性值设置为BEFORE,也就是在INSERT语句执行生成之前,生成这条记录的唯一id。例如使用oracle时,你可以在中先使用序列生成一个唯一id。
selectKey 元素描述如下:
<selectKey keyProperty="id" resultType="int" order="BEFORE" statementType="PREPARED">
属性描述
keyProperty
selectKey 语句结果应该被设置的目标属性。如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表。
keyColumn
匹配属性的返回结果集中的列名称。如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表。
resultType
结果的类型。MyBatis 通常可以推算出来,但是为了更加确定写上也不会有什么问题。MyBatis 允许任何简单类型用作主键的类型,包括字符串。如果希望作用于多个生成的列,则可以使用一个包含期望属性的 Object 或一个 Map。
order
这可以被设置为 BEFORE
或 AFTER
。如果设置为 BEFORE,那么它会首先选择主键,设置 keyProperty 然后执行插入语句。如果设置为 AFTER,那么先执行插入语句,然后是 selectKey 元素 - 这和像 Oracle 的数据库相似,在插入语句内部可能有嵌入索引调用。
statementType
与前面相同,MyBatis 支持 STATEMENT,PREPARED 和 CALLABLE 语句的映射类型,分别代表 PreparedStatement 和 CallableStatement 类型。