本人使用的是Mybatis3.X的版本
官方文档给出了两种方式实现:
useGeneratedKeys
:(仅对 insert 和 update 有用)这会令 MyBatis 使用 JDBC 的 getGeneratedKeys 方法来取出由数据库内部生成的主键(比如:像 MySQL 和 SQL Server 这样的关系数据库管理系统的自动递增字段),默认值:false。
如果你的数据库支持自动生成主键的字段(比如 MySQL 和 SQL Server),那么你可以设置 useGeneratedKeys=”true”,然后再把 keyProperty 设置到目标属性上就OK了。- 如果你的数据库不支持自动生成主键的字段。你可以使用子标签
来实现。
省略了实体类和mapper接口层的代码,只给出xml文件的代码作为示例
<mapper namespace="com.mirt.mybatis_demo.mapper.AutoIncrementMapper">
<resultMap id="BaseResult" type="com.mirt.mybatis_demo.entity.AutoIncrementEntity">
<result column="id" property="id"/>
<result column="comment" property="comment"/>
<result column="create_time" property="createTime"/>
resultMap>
<insert id="saveOneByUseGeneratedKeys" useGeneratedKeys="true" keyProperty="id">
insert into auto_increment_table (comment, create_time) values (#{comment},now());
insert>
<insert id="saveOneBySelectKey" parameterType="com.mirt.mybatis_demo.entity.AutoIncrementEntity">
<selectKey resultType="int" order="AFTER" keyProperty="id">
SELECT LAST_INSERT_ID();
selectKey>
insert into auto_increment_table (comment, create_time) values (#{comment},now());
insert>
mapper>
此处定义了两种方法 saveOneByUseGeneratedKeys
,saveOneBySelectKey
用于演示官方给出的两种方法是否可行。
给出测试类下的方法以及结果
@Test
public void saveOneByUseGeneratedKeys() {
AutoIncrementEntity aie = new AutoIncrementEntity();
aie.setComment("useGeneratedKeys");
boolean res = autoIncrementMapper.saveOneByUseGeneratedKeys(aie) > 0;
if (res) {
System.out.println(aie);
}else {
System.out.println("insert fail");
}
}
@Test
public void saveOneBySelectKey() {
AutoIncrementEntity aie = new AutoIncrementEntity();
aie.setComment("selectKey");
boolean res = autoIncrementMapper.saveOneByUseGeneratedKeys(aie) > 0;
if (res) {
System.out.println(aie);
}else {
System.out.println("insert fail");
}
}
返回结果为
{id:1}
{id:2}
可以看出来确实返回了自增的主键。
package org.apache.ibatis.executor.keygen;
import java.sql.Statement;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
public interface KeyGenerator {
void processBefore(Executor var1, MappedStatement var2, Statement var3, Object var4);
void processAfter(Executor var1, MappedStatement var2, Statement var3, Object var4);
}
mybatis的KeyGenerator接口提供了两个方法,一个是执行前一个是执行后,在上面的示例中由于主键是在插入后才获得的,所以使用的都是processAfter
这个方法。
该接口有三个实现类,默认使用的是Jdbc3KeyGenerator
这个实现类。
public void processAfter(Executor executor, MappedStatement ms, Statement stmt, Object parameter) {
this.processBatch(ms, stmt, this.getParameters(parameter));
}
public void processBatch(MappedStatement ms, Statement stmt, Collection<Object> parameters) {
ResultSet rs = null;
try {
rs = stmt.getGeneratedKeys();
Configuration configuration = ms.getConfiguration();
TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();
String[] keyProperties = ms.getKeyProperties(); // 可以配置多个keyproperties
ResultSetMetaData rsmd = rs.getMetaData();
TypeHandler<?>[] typeHandlers = null;
MetaObject metaParam;
if (keyProperties != null && rsmd.getColumnCount() >= keyProperties.length) {
for(Iterator var10 = parameters.iterator(); var10.hasNext(); this.populateKeys(rs, metaParam, keyProperties, typeHandlers)) {
Object parameter = var10.next();
if (!rs.next()) {
break;
}
metaParam = configuration.newMetaObject(parameter);
if (typeHandlers == null) {
typeHandlers = this.getTypeHandlers(typeHandlerRegistry, metaParam, keyProperties, rsmd);
}
}
}
} catch (Exception var20) {
throw new ExecutorException("Error getting generated key or setting result to parameter object. Cause: " + var20, var20);
} finally {
if (rs != null) {
try {
rs.close();
} catch (Exception var19) {
;
}
}
}
}
// 将获得的值存入到实体类指定的字段
private void populateKeys(ResultSet rs, MetaObject metaParam, String[] keyProperties, TypeHandler<?>[] typeHandlers) throws SQLException {
for(int i = 0; i < keyProperties.length; ++i) {
String property = keyProperties[i];
TypeHandler<?> th = typeHandlers[i];
if (th != null) {
Object value = th.getResult(rs, i + 1);
metaParam.setValue(property, value);
}
}
}
mybatis的官方文档中对于keyPropwety
有如下描述
(仅对 insert 和 update 有用)唯一标记一个属性,MyBatis 会通过 getGeneratedKeys 的返回值或者通过 insert 语句的 selectKey 子元素设置它的键值,默认:unset。如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表。
从源码中了解到keyProperty也确实可以支持设置多个,统一在插入操作前后统一存入。
有一点需要注意就是如果你的主键没有setter方法的话,这里是会报错的。mybatis没有办法把生成的主键信息存回到实体类当中去。