MyBatis從插入語句中檢索自動生成的ID

banq發表於2024-06-02

MyBatis是一個開源 Java 持久層框架,可以作為JDBC和Hibernate的替代品。它可以幫助我們減少程式碼並簡化結果的檢索,讓我們專注於編寫自定義 SQL 查詢或儲存過程。

在本教程中,我們將學習如何使用 MyBatis 和 Spring Boot 插入資料時返回自動生成的 ID。

依賴設定
在開始之前,讓我們在pom.xml中新增mybatis-spring-boot-starter依賴項:

<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>3.0.3</version>
</dependency>

讓我們首先建立一個將在整篇文章中使用的簡單示例。

1. 定義實體
首先,讓我們建立一個代表汽車的簡單實體類:

public class Car {
    private Long id;
    private String model;
    <font>// getters and setters<i>
}

其次,我們定義一個建立表的SQL語句,並將其放在car-schema.sql檔案中:

CREATE TABLE IF NOT EXISTS CAR
(
    ID    INTEGER PRIMARY KEY AUTO_INCREMENT,
    MODEL VARCHAR(100) NOT NULL
);

2. 定義資料來源
接下來,讓我們指定資料來源。我們將使用 H2 嵌入式資料庫:

@Bean
public DataSource dataSource() {
    EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
    return builder
      .setType(EmbeddedDatabaseType.H2)
      .setName(<font>"testdb")
      .addScript(
"car-schema.sql")
      .build();
}
@Bean
public SqlSessionFactory sqlSessionFactory() throws Exception {
    SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
    factoryBean.setDataSource(dataSource());
    return factoryBean.getObject();
}

現在我們已經完成所有設定,讓我們看看如何使用基於註釋和基於 XML 的方法來檢索自動生成的身份。

使用註釋
讓我們定義Mapper,它代表 MyBatis 用於將方法繫結到相應 SQL 語句的介面:

@Mapper
public interface CarMapper {
    <font>// ...<i>
}

接下來我們新增一個插入語句:

@Insert(<font>"INSERT INTO CAR(MODEL) values (#{model})")
void save(Car car);

直覺地,我們可能傾向於返回Long並期望 MyBatis 返回所建立實體的 ID。然而,這並不準確。如果我們這樣做,它會返回1,表示插入語句成功。

要檢索生成的 ID,我們可以使用@Options或@SelectKey註釋。

1. @Options註釋
我們可以擴充套件插入語句的一種方法是使用@Options註釋:

@Insert(<font>"INSERT INTO CAR(MODEL) values (#{model})")
@Options(useGeneratedKeys = true, keyColumn =
"ID", keyProperty = "id")
void saveUsingOptions(Car car);

這裡我們設定了三個屬性:
  • useGeneratedKeys – 表示我們是否要使用生成的金鑰功能
  • keyColumn – 設定包含鍵的列的名稱
  • keyProperty – 表示儲存鍵值的欄位名稱

此外,我們可以用逗號分隔來指定多個關鍵屬性。

在後臺,MyBatis 使用反射將 ID 列的值對映到Car物件的id欄位中。

接下來,讓我們建立一個測試來確認一切是否按預期進行:

@Test
void givenCar_whenSaveUsingOptions_thenReturnId() {
    Car car = new Car();
    car.setModel(<font>"BMW");
    carMapper.saveUsingOptions(car);
    assertNotNull(car.getId());
}

2. @SelectKey註釋
返回 ID 的另一種方法是使用@SelectKey註釋。當我們想要使用序列或身份函式來檢索識別符號時,此註釋非常有用。

此外,如果我們使用@SelectKey註釋修飾我們的方法,MyBatis 會忽略諸如@Options之類的註釋。

讓我們在CarMapper內部建立一個新方法來檢索插入後的標識值:

@Insert(<font>"INSERT INTO CAR(MODEL) values (#{model})")
@SelectKey(statement =
"CALL IDENTITY()", before = false, keyColumn = "ID", keyProperty = "id", resultType = Long.class)
void saveUsingSelectKey(Car car);

讓我們檢查一下我們使用的屬性:
  • statement – 儲存將在插入語句之後執行的語句
  • before – 表示語句應該在插入之前還是之後執行
  • keyColumn – 儲存代表鍵的列的名稱
  • keyProperty – 指定將儲存語句返回的值的欄位的名稱
  • resultType – 表示keyProperty的型別

此外,我們應該注意到IDENTITY()函式已從 H2 資料庫中刪除。更多詳細資訊請參見此處。

為了能夠在 H2 資料庫上執行CALL IDENTITY(),我們需要將模式設定為LEGACY:

<font>"testdb;MODE=LEGACY"

讓我們測試一下我們的方法來確認它能正常工作:

@Test
void givenCar_whenSaveUsingSelectKey_thenReturnId() {
    Car car = new Car();
    car.setModel(<font>"BMW");
    carMapper.saveUsingSelectKey(car);
    assertNotNull(car.getId());
}

相關文章