最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

MyBatis主鍵回填的兩種實現(xiàn)方式

 更新時間:2026年04月08日 09:57:05   作者:身如柳絮隨風(fēng)揚  
這篇文章主要介紹了MyBatis中的主鍵回填機制,詳細(xì)說明了其應(yīng)用場景、兩種實現(xiàn)方式的原理、配置方法、適用場景及性能對比,并通過流程圖展示了執(zhí)行過程,針對常見問題與注意事項進行了說明,最后提供了完整示例代碼,需要的朋友可以參考下

購物下單后,訂單號是怎么自動生成的?插入數(shù)據(jù)后如何直接獲取自增主鍵?本文將帶你深入理解 MyBatis 中的主鍵回填機制,并通過流程圖和代碼示例徹底掌握它。

一、業(yè)務(wù)場景:下單后如何返回訂單編號?

想象一個典型的購物交易流程:

  1. 用戶點擊“立即購買”,填寫收貨信息,提交訂單。
  2. 后端服務(wù)將訂單數(shù)據(jù)(用戶ID、商品ID、金額、狀態(tài)等)插入到數(shù)據(jù)庫的 orders 表中。
  3. 插入成功后,系統(tǒng)需要立即返回一個訂單編號給前端,用于后續(xù)支付、查詢等操作。

這個訂單編號通常是數(shù)據(jù)庫表的主鍵,比如自增的 id 字段。但在執(zhí)行插入 SQL 時,我們并不知道這個 id 是多少 —— 它是數(shù)據(jù)庫自動生成的。

如果采用“先插入,再查詢”的方式:

-- 第一步:插入訂單(id 自動生成)
INSERT INTO orders(user_id, amount, status) VALUES(1001, 299.00, 0);
-- 第二步:根據(jù)唯一業(yè)務(wù)字段查詢剛插入的訂單
SELECT id FROM orders WHERE user_id = 1001 AND create_time = ...;

這種做法不僅繁瑣,而且在高并發(fā)下很容易出錯(多個用戶同時下單,條件可能不唯一)。于是,主鍵回填技術(shù)應(yīng)運而生。

二、什么是主鍵回填?

主鍵回填(Key Fillback / Key Return)是指在執(zhí)行數(shù)據(jù)庫插入操作后,自動將生成的主鍵值填充到傳入的 Java 對象中。這樣,你無需再次查詢,就能直接通過對象的 getId() 方法拿到主鍵。

簡單來說:插入時主鍵為 null,插入后 MyBatis 幫你把主鍵值“填回去”。

效果演示

Order order = new Order();
order.setUserId(1001);
order.setAmount(299.00);
order.setStatus(0);
// 此時 order.getId() == null
orderMapper.insertOrder(order);
// 插入后,MyBatis 自動將生成的主鍵賦值給 order 對象
System.out.println(order.getId()); // 輸出 12345

三、主鍵回填的兩種實現(xiàn)方式

MyBatis 主要提供兩種方式實現(xiàn)主鍵回填,分別適用于不同的數(shù)據(jù)庫和場景。

方式一:useGeneratedKeys+keyProperty(推薦,簡單高效)

適用數(shù)據(jù)庫:支持自動生成主鍵的數(shù)據(jù)庫,如 MySQL、SQL Server(自增列)、PostgreSQL(serial 類型)等。

原理:MyBatis 利用 JDBC 的 Statement.getGeneratedKeys() 方法獲取數(shù)據(jù)庫自動生成的主鍵。

配置示例

<insert id="insertOrder" useGeneratedKeys="true" keyProperty="id">
    INSERT INTO orders(user_id, amount, status)
    VALUES (#{userId}, #{amount}, #{status})
</insert>
  • useGeneratedKeys="true":開啟主鍵回填功能。
  • keyProperty="id":指定將生成的主鍵值賦給 Java 對象的哪個屬性(對應(yīng) Order 類中的 id 字段)。

Java 接口方法

public interface OrderMapper {
    int insertOrder(Order order);
}

使用注意

  • 只能用于單條插入(批量插入時需特殊處理,不同數(shù)據(jù)庫支持情況不一)。
  • 數(shù)據(jù)庫表必須定義自增列或類似機制。

方式二:<selectKey>標(biāo)簽(靈活,支持多種數(shù)據(jù)庫)

適用場景

  • 數(shù)據(jù)庫沒有自增列(如 Oracle 使用序列)。
  • 需要在插入前生成主鍵(比如使用 UUID)。
  • 需要執(zhí)行自定義查詢來獲取主鍵值(如 MySQL 的 LAST_INSERT_ID())。

原理:通過子查詢執(zhí)行一個 SQL 語句來獲取主鍵,可以指定在插入語句之前(order="BEFORE")或之后(order="AFTER")執(zhí)行。

示例 1:MySQL 插入后獲取自增 ID

<insert id="insertOrder">
    <!-- 插入后執(zhí)行,獲取最后插入的 ID -->
    <selectKey keyProperty="id" resultType="int" order="AFTER">
        SELECT LAST_INSERT_ID()
    </selectKey>
    INSERT INTO orders(user_id, amount, status)
    VALUES (#{userId}, #{amount}, #{status})
</insert>

示例 2:Oracle 插入前從序列獲取 ID

<insert id="insertOrder">
    <selectKey keyProperty="id" resultType="long" order="BEFORE">
        SELECT ORDERS_SEQ.NEXTVAL FROM DUAL
    </selectKey>
    INSERT INTO orders(id, user_id, amount, status)
    VALUES (#{id}, #{userId}, #{amount}, #{status})
</insert>

示例 3:使用 UUID 作為主鍵(插入前生成)

<insert id="insertUser">
    <selectKey keyProperty="id" resultType="String" order="BEFORE">
        SELECT REPLACE(UUID(), '-', '')
    </selectKey>
    INSERT INTO users(id, name) VALUES (#{id}, #{name})
</insert>

屬性說明

  • keyProperty:目標(biāo)對象的屬性名。
  • resultType:主鍵的 Java 類型。
  • orderBEFORE(在插入前執(zhí)行)或 AFTER(在插入后執(zhí)行)。

四、流程圖:主鍵回填的執(zhí)行過程

為了更直觀地理解兩種方式的執(zhí)行流程,下面用流程圖表示。

1.useGeneratedKeys方式流程

1.useGeneratedKeys方式流程

2.<selectKey order="AFTER">方式流程(以 MySQL 為例)

2.<selectKey order="AFTER">方式流程(以 MySQL 為例)

3.<selectKey order="BEFORE">方式流程(以 Oracle 為例)

3.<selectKey order="BEFORE">方式流程(以 Oracle 為例)

五、兩種方式的對比與選擇

對比項useGeneratedKeys<selectKey>
配置復(fù)雜度極低,兩個屬性即可稍高,需要寫子查詢
適用數(shù)據(jù)庫支持自增列的數(shù)據(jù)庫(MySQL 等)所有數(shù)據(jù)庫(Oracle、SQL Server 等)
性能高,一次網(wǎng)絡(luò)交互可能兩次交互(AFTER 時)
批量插入支持有限制(需看驅(qū)動)一般不用于批量
主鍵生成時機插入后可自由控制(BEFORE / AFTER
非數(shù)值主鍵(UUID)不支持支持

選擇建議

  • MySQL + 自增主鍵 → 優(yōu)先使用 useGeneratedKeys。
  • Oracle 序列 / UUID / 復(fù)合主鍵 → 使用 <selectKey>。
  • 需要插入前生成主鍵(如分布式 ID) → 使用 <selectKey order="BEFORE">

六、常見問題與注意事項

1. 為什么插入后對象的 id 還是 null?

  • 檢查 useGeneratedKeys="true"keyProperty 是否正確配置。
  • 檢查 keyProperty 對應(yīng)的屬性在 Java 對象中是否有 setter 方法(MyBatis 通過反射賦值)。
  • 確認(rèn)數(shù)據(jù)庫表確實支持自增列(MySQL 需 AUTO_INCREMENT)。

2. 批量插入時能否使用主鍵回填?

  • MySQL 驅(qū)動支持批量插入時返回生成的主鍵,但 MyBatis 的 useGeneratedKeys 對批量支持不統(tǒng)一。建議使用循環(huán)單條插入,或者使用 <foreach> 配合特殊寫法(需要數(shù)據(jù)庫驅(qū)動支持)。
  • 簡單場景下,可以放棄批量回填,插入后單獨查詢。

3.LAST_INSERT_ID()與并發(fā)

MySQL 的 LAST_INSERT_ID()連接級別的,每個客戶端連接返回自己最后插入的 ID,不會受其他并發(fā)連接影響,因此是安全的。

4. 主鍵回填后,對象會被修改嗎?

會!MyBatis 會直接修改傳入的 Java 對象的屬性值。因此你無需重新接收返回值,直接使用原對象即可。

七、完整示例代碼

數(shù)據(jù)庫表(MySQL)

CREATE TABLE `orders` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) NOT NULL,
  `amount` decimal(10,2) NOT NULL,
  `status` tinyint(4) DEFAULT '0',
  PRIMARY KEY (`id`)
);

Java 實體類

public class Order {
    private Integer id;
    private Integer userId;
    private BigDecimal amount;
    private Integer status;
    // 省略 getter / setter / toString
}

Mapper 接口

@Mapper
public interface OrderMapper {
    // 方式一:useGeneratedKeys
    int insertOrder(Order order);
    // 方式二:selectKey (MySQL AFTER)
    int insertOrderWithSelectKey(Order order);
}

XML 映射文件

<!-- 方式一 -->
<insert id="insertOrder" useGeneratedKeys="true" keyProperty="id">
    INSERT INTO orders(user_id, amount, status)
    VALUES (#{userId}, #{amount}, #{status})
</insert>
<!-- 方式二 -->
<insert id="insertOrderWithSelectKey">
    <selectKey keyProperty="id" resultType="int" order="AFTER">
        SELECT LAST_INSERT_ID()
    </selectKey>
    INSERT INTO orders(user_id, amount, status)
    VALUES (#{userId}, #{amount}, #{status})
</insert>

測試代碼

@SpringBootTest
class OrderMapperTest {
    @Autowired
    private OrderMapper orderMapper;
    @Test
    void testInsert() {
        Order order = new Order();
        order.setUserId(1001);
        order.setAmount(new BigDecimal("199.00"));
        order.setStatus(0);
        int rows = orderMapper.insertOrder(order);
        System.out.println("影響行數(shù):" + rows);
        System.out.println("回填后的主鍵:" + order.getId()); // 輸出自增 ID
    }
}

八、總結(jié)

主鍵回填是 MyBatis 中非常實用且高頻使用的特性,它解決了插入數(shù)據(jù)后立即獲取主鍵的痛點。掌握兩種實現(xiàn)方式:

  • useGeneratedKeys:簡潔高效,MySQL 首選。
  • <selectKey>:靈活強大,適配各種數(shù)據(jù)庫及非自增主鍵場景。

在實際開發(fā)中,根據(jù)數(shù)據(jù)庫類型和業(yè)務(wù)需求選擇合適的方式,可以大大簡化代碼邏輯,提升開發(fā)效率。

以上就是MyBatis主鍵回填的兩種實現(xiàn)方式的詳細(xì)內(nèi)容,更多關(guān)于MyBatis實現(xiàn)主鍵回填的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 設(shè)計模式之模版方法模式_動力節(jié)點Java學(xué)院整理

    設(shè)計模式之模版方法模式_動力節(jié)點Java學(xué)院整理

    這篇文章主要介紹了設(shè)計模式之模版方法模式,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-08-08
  • Java開發(fā)實現(xiàn)人機猜拳游戲

    Java開發(fā)實現(xiàn)人機猜拳游戲

    這篇文章主要為大家詳細(xì)介紹了Java開發(fā)實現(xiàn)人機猜拳游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-08-08
  • Java之ThreadPoolExecutor類詳解

    Java之ThreadPoolExecutor類詳解

    這篇文章主要介紹了Java之ThreadPoolExecutor類詳解,本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-08-08
  • MyBatis通用Mapper和PageHelper的過程詳解

    MyBatis通用Mapper和PageHelper的過程詳解

    這篇文章主要介紹了MyBatis通用Mapper和PageHelper的相關(guān)知識,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-11-11
  • Java重點之基于比較的七大排序

    Java重點之基于比較的七大排序

    最近幾天在研究排序算法,看了很多博客,發(fā)現(xiàn)網(wǎng)上有的文章中對排序算法解釋的并不是很透徹,而且有很多代碼都是錯誤的,所以我根據(jù)這幾天看的文章,整理了一個較為完整的排序算法總結(jié),本文中的所有算法均有JAVA實現(xiàn),經(jīng)本人調(diào)試無誤后才發(fā)出,如有錯誤,請各位前輩指出
    2021-10-10
  • java利用反射實現(xiàn)動態(tài)代理示例

    java利用反射實現(xiàn)動態(tài)代理示例

    這篇文章主要介紹了java利用反射實現(xiàn)動態(tài)代理示例,需要的朋友可以參考下
    2014-04-04
  • 使用spring mail發(fā)送html郵件的示例代碼

    使用spring mail發(fā)送html郵件的示例代碼

    本篇文章主要介紹了使用spring mail發(fā)送html郵件的示例代碼,這里整理了詳細(xì)的示例代碼,具有一定的參考價值,有興趣的可以了解一下
    2017-09-09
  • Java線程池的應(yīng)用實例分析

    Java線程池的應(yīng)用實例分析

    這篇文章主要介紹了Java線程池的應(yīng)用,結(jié)合具體實例形式分析了java線程池的斐波那契數(shù)列計算與模擬工人做工等應(yīng)用的操作技巧,需要的朋友可以參考下
    2019-10-10
  • java編譯命令基礎(chǔ)知識點

    java編譯命令基礎(chǔ)知識點

    在本篇文章里小編給大家整理的是一篇關(guān)于java編譯命令基礎(chǔ)知識點內(nèi)容,有興趣的朋友們可以學(xué)習(xí)下。
    2021-01-01
  • 迪米特法則_動力節(jié)點Java學(xué)院整理

    迪米特法則_動力節(jié)點Java學(xué)院整理

    這篇文章主要介紹了迪米特法則,迪米特法則就是一個在類創(chuàng)建方法和屬性時需要遵守的法則,有興趣的可以了解一下
    2017-08-08

最新評論

祁连县| 阳泉市| 句容市| 基隆市| 南投市| 龙口市| 江川县| 绥阳县| 中阳县| 冕宁县| 安宁市| 桦甸市| 精河县| 汤阴县| 剑河县| 阜宁县| 衡东县| 白银市| 黄石市| 本溪市| 闸北区| 长顺县| 英山县| 汉川市| 博罗县| 石嘴山市| 顺昌县| 资阳市| 三亚市| 毕节市| 景洪市| 晋州市| 读书| 马关县| 陆川县| 遵化市| 桑植县| 东台市| 女性| 祥云县| 仪陇县|