Mybatis新增並返回主鍵功能
本人使用的是Mybatis3.X的版本
官方文檔給出了兩種方式實現:
useGeneratedKeys
:(僅對 insert 和 update 有用)這會令 MyBatis 使用 JDBC 的 getGeneratedKeys 方法來取出由數據庫內部生成的主鍵(比如:像 MySQL 和 SQL Server 這樣的關係數據庫管理系統的自動遞增字段),默認值:false。
如果你的數據庫支持自動生成主鍵的字段(比如 MySQL 和 SQL Server),那麼你可以設置 useGeneratedKeys=”true”,然後再把 keyProperty 設置到目標屬性上就OK了。- 如果你的數據庫不支持自動生成主鍵的字段。你可以使用子標籤
<selectKey>
來實現。
示例
省略了實體類和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沒有辦法把生成的主鍵信息存回到實體類當中去。