1. 程式人生 > >深入淺出mybatis之返回主鍵ID

深入淺出mybatis之返回主鍵ID

目錄

新增記錄後獲取主鍵ID,這是一個很常見的需求,特別是在一次前端呼叫中需要插入多個表的場景。
除了新增單條記錄時獲取主鍵值,有時候可能需要獲取批量新增記錄時各記錄的主鍵值,MyBatis從3.3.1版本開始支援批量新增記錄並返回各記錄主鍵欄位值。

新增單一記錄時返回主鍵ID

新增一條記錄時返回主鍵值,在xml對映器和介面對映器中都可以實現。

在對映器中配置獲取記錄主鍵值

  • xml對映器

在定義xml對映器時設定屬性useGeneratedKeys值為true,並分別指定屬性keyProperty和keyColumn為對應的資料庫記錄主鍵欄位與Java物件的主鍵屬性。

<mapper namespace="org.chench.test.mybatis.mapper">
    <!-- 插入資料:返回記錄主鍵id值 -->
    <insert id="insertOneTest" parameterType="org.chench.test.mybatis.model.Test" useGeneratedKeys="true" keyProperty="id" keyColumn="id" >
        insert into test(name,descr,url,create_time,update_time) 
        values(#{name},#{descr},#{url},now(),now())
    </insert>
</mapper>
  • 介面對映器

在介面對映器中通過註解@Options分別設定引數useGeneratedKeys,keyProperty,keyColumn值

// 返回主鍵欄位id值
@Options(useGeneratedKeys = true, keyProperty = "id", keyColumn = "id")
@Insert("insert into test(name,descr,url,create_time,update_time) values(#{name},#{descr},#{url},now(),now())")
Integer insertOneTest(Test test);

獲取新新增記錄主鍵欄位值

需要注意的是,在MyBatis中新增操作返回的是記錄數並非記錄主鍵id。因此,如果需要獲取新新增記錄的主鍵值,需要在執行新增操作之後,直接讀取Java物件的主鍵屬性。

Integer rows = sqlSession.getMapper(TestMapper.class).insertOneTest(test);
System.out.println("rows = " + rows); // 新增操作返回記錄數
System.out.println("id = " + test.getId()); // 執行新增操作之後通過Java物件獲取主鍵屬性值

新增批量記錄時返回主鍵ID

如果希望執行批量新增並返回各記錄主鍵欄位值,只能在xml對映器中實現,在介面對映器中無法做到。

<!-- 批量新增資料,並返回主鍵欄位 -->
<insert id="insertBatchTest" useGeneratedKeys="true" keyProperty="id">
    INSERT INTO test(name,descr,url,create_time,update_time) VALUES
        <foreach collection="list" separator="," item="t">
        (#{t.name},#{t.descr},#{t.url},now(),now())
        </foreach>
</insert>

可以看到,執行批量新增並返回記錄主鍵值的xml對映器配置,跟新增單條記錄時是一致的。不同的地方僅僅是使用了foreach元素構建批量新增語句。

獲取主鍵ID實現原理

需要注意的是,不論在xml對映器還是在介面對映器中,新增記錄的主鍵值並非新增操作的返回值。實際上,在MyBatis中執行新增操作時只會返回當前新增的記錄數。

package org.apache.ibatis.executor.statement;
public class PreparedStatementHandler extends BaseStatementHandler {
    @Override
    public int update(Statement statement) throws SQLException {
        PreparedStatement ps = (PreparedStatement) statement;
        // 真正執行新增操作的SQL語句
        ps.execute();
        int rows = ps.getUpdateCount();
        Object parameterObject = boundSql.getParameterObject();
        KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
        // 在執行新增操作完畢之後,再處理記錄主鍵欄位值
        keyGenerator.processAfter(executor, mappedStatement, ps, parameterObject);
        // 新增記錄時返回的是記錄數,而並非記錄的主鍵欄位值
        return rows;
    }
}

順便看一下MyBatis新增操作的時序圖:

跟蹤時序圖執行步驟可以看到,MyBatis最終是通過MySQL驅動程式獲取到了新新增的記錄主鍵值。

【參考】
https://github.com/mybatis/mybatis-3/pull/350 Support insert multiple rows and write-back id.More about insert multipl...
https://www.zhihu.com/question/21153827 mybatis 批量插入如何返回每個條記錄的自生成主鍵?
https://blog.csdn.net/jiangeeq/article/details/55047116 Mybatis批量插入返回插入成功後的主鍵id
https://blog.csdn.net/top_code/article/details/52404345 MyBatis 3.3.1 批量插入多行回寫自增id