使用 MyBatis 和 Spring 從插入返回自動產生的 ID
1. 概述
MyBatis 是一個開源的 Java 持久性框架,可以用作 JDBC 和 Hibernate 的替代品。它幫助我們減少程式碼並簡化結果的檢索,使我們能夠專注於編寫自訂 SQL 查詢或預存程序。
在本教程中,我們將學習如何在使用 MyBatis 和 Spring Boot 插入資料時返回自動產生的 ID。
2. 依賴設定
在開始之前,讓我們在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>
3. 設定範例
讓我們先建立一個將在整篇文章中使用的簡單範例。
3.1.定義實體
首先,讓我們建立一個代表汽車的簡單實體類別:
public class Car {
private Long id;
private String model;
// getters and setters
}
其次,我們定義一條建立表格的 SQL 語句並將其放置在car-schema.sql檔案中:
CREATE TABLE IF NOT EXISTS CAR
(
ID INTEGER PRIMARY KEY AUTO_INCREMENT,
MODEL VARCHAR(100) NOT NULL
);
3.2.定義DataSource
接下來,我們指定一個資料來源。我們將使用 H2 嵌入式資料庫:
@Bean
public DataSource dataSource() {
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
return builder
.setType(EmbeddedDatabaseType.H2)
.setName("testdb")
.addScript("car-schema.sql")
.build();
}
@Bean
public SqlSessionFactory sqlSessionFactory() throws Exception {
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setDataSource(dataSource());
return factoryBean.getObject();
}
現在我們已經完成所有設置,讓我們看看如何使用基於註釋和基於 XML 的方法檢索自動生成的身份。
4. 使用註釋
我們來定義Mapper,它代表MyBatis用來將方法綁定到對應SQL語句的介面:
@Mapper
public interface CarMapper {
// ...
}
接下來,我們新增一條insert語句:
@Insert("INSERT INTO CAR(MODEL) values (#{model})")
void save(Car car);
本能地,我們可能只想返回Long並期望 MyBatis 會回傳所建立實體的 ID。然而,這並不準確。如果我們這樣做,它會回傳1 ,表示insert語句成功。
要檢索產生的 ID,我們可以使用[@Options](https://mybatis.org/mybatis-3/es/apidocs/org/apache/ibatis/annotations/Options.html)或@SelectKey註解。
4.1. @Options註解
我們擴展insert語句的一種方法是使用@Options註釋:
@Insert("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("BMW");
carMapper.saveUsingOptions(car);
assertNotNull(car.getId());
}
4.2. @SelectKey註解
另一種傳回 ID 的方法是使用@SelectKey註解。當我們想要使用序列或恆等函數來檢索標識符時,此註解會很有用。
此外,如果我們用@SelectKey註解修飾我們的方法,MyBatis 會忽略諸如@Options之類的註解。
讓我們在CarMapper中建立一個新方法來在插入後檢索識別值:
@Insert("INSERT INTO CAR(MODEL) values (#{model})")
@SelectKey(statement = "CALL IDENTITY()", before = false, keyColumn = "ID", keyProperty = "id", resultType = Long.class)
void saveUsingSelectKey(Car car);
讓我們檢查一下我們使用的屬性:
-
statement– 儲存將在insert語句之後執行的語句 -
before– 指示語句應該在插入之前還是之後執行 -
keyColumn– 儲存代表鍵的欄位的名稱 -
keyProperty– 指定將保存語句傳回值的欄位的名稱 -
resultType– 表示keyProperty的類型
此外,我們應該注意到IDENTITY()函數已從 H2 資料庫中刪除。更多詳情可在這找到 。
為了能夠在 H2 資料庫上執行CALL IDENTITY() ,我們需要將模式設定為LEGACY :
"testdb;MODE=LEGACY"
讓我們測試我們的方法以確認其正常工作:
@Test
void givenCar_whenSaveUsingSelectKey_thenReturnId() {
Car car = new Car();
car.setModel("BMW");
carMapper.saveUsingSelectKey(car);
assertNotNull(car.getId());
}
5.使用XML
讓我們看看如何實現相同的功能,但這次,我們將使用基於 XML 的方法。
首先,我們定義CarXmlMapper介面:
@Mapper
public interface CarXmlMapper {
// ...
}
與基於註解的方法不同,我們不會直接在Mapper介面中編寫SQL語句。相反,我們將定義 XML 映射器檔案並將所有查詢放入其中:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.baeldung.mybatis.generatedid.CarXmlMapper">
</mapper>
此外,在namespace屬性中,我們指定CarXml Mapper介面的完全限定名稱。
5.1. UseGeneratedKeys屬性
接下來,我們在CarXmlMapper介面中定義一個方法:
void saveUsingOptions(Car car);
此外,讓我們使用 XML 映射器來定義insert語句並將其映射到我們放置在CarXmlMapper介面中的saveUsingOptions()方法:
<insert id="saveUsingOptions" parameterType="com.baeldung.mybatis.generatedid.Car"
useGeneratedKeys="true" keyColumn="ID" keyProperty="id">
INSERT INTO CAR(MODEL)
VALUES (#{model});
</insert>
讓我們探討一下我們使用的屬性:
-
id– 將查詢綁定到CarXmlMapper類別中的特定方法 -
parameterType–saveUsingOptions()方法的參數類型 -
useGeneratedKeys– 表示我們要使用產生的 ID 功能 -
keyColumn– 指定代表鍵的列的名稱 -
keyProperty– 指定將保存金鑰的Car物件的欄位名稱
另外,讓我們測試一下我們的解決方案:
@Test
void givenCar_whenSaveUsingOptions_thenReturnId() {
Car car = new Car();
car.setModel("BMW");
carXmlMapper.saveUsingOptions(car);
assertNotNull(car.getId());
}
5.2. SelectKey元素
接下來,讓我們在CarXmlMapper介面中新增一個方法,看看如何使用selectKey元素檢索識別:
void saveUsingSelectKey(Car car);
此外,讓我們指定 XML 映射器檔案中的語句並將其綁定到方法:
<insert id="saveUsingSelectKey" parameterType="com.baeldung.mybatis.generatedid.Car">
INSERT INTO CAR(MODEL)
VALUES (#{model});
<selectKey resultType="Long" order="AFTER" keyColumn="ID" keyProperty="id">
CALL IDENTITY()
</selectKey>
</insert>
在這裡,我們使用以下屬性定義了selectKey元素:
-
resultType– 指定語句傳回的類型 -
order– 指示語句CALL IDENTITY()應該在insert語句之前還是之後調用 -
keyColumn– 儲存表示識別碼的欄位的名稱 -
keyProperty– 儲存鍵應對應的欄位的名稱
最後,讓我們建立一個測試:
@Test
void givenCar_whenSaveUsingSelectKey_thenReturnId() {
Car car = new Car();
car.setModel("BMW");
carXmlMapper.saveUsingSelectKey(car);
assertNotNull(car.getId());
}
六,結論
在本文中,我們學習如何使用 MyBatis 和 Spring 從insert語句中擷取自動產生的 ID。
總而言之,我們探索如何使用基於註釋的方法以及@Options和@SelectKey註釋來檢索ID。此外,我們也研究如何使用基於 XML 的方法傳回 ID。
像往常一樣,完整的源代碼可以在 GitHub 上找到。