1. 概述
MyBatis 是一個開源的 Java 持久性框架,可作為 JDBC 和 Hibernate 的替代方案使用。它幫助我們減少代碼,簡化結果檢索,使我們能夠專注於編寫自定義 SQL 查詢或存儲過程。
在本教程中,我們將學習如何插入數據時返回自動生成的 ID,同時結合 MyBatis 和 Spring Boot。
2. 依賴配置
在開始之前,讓我們在 <em/>pom.xml</em/> 中添加mybatis-spring-boot-starter</em/>` 依賴:
<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
}第二,我們定義一個創建表並將其放在 car-schema.sql 文件的 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 註解或 @SelectKey 註解。
4.1. @Options 註解
通過使用 @Options 註解,我們可以擴展我們的語句。
@Insert("INSERT INTO CAR(MODEL) values (#{model})")
@Options(useGeneratedKeys = true, keyColumn = "ID", keyProperty = "id")
void saveUsingOptions(Car car);在這裏,我們設置了三個屬性:
- useGeneratedKeys – 指示是否使用自動生成鍵功能
- keyColumn – 設置鍵值存儲在的列名
- keyProperty – 表示鍵值將存儲在的字段名
此外,我們可以通過用逗號分隔來指定多個鍵屬性。
在後台,MyBatis 使用反射將 ID 列的值映射到 id 字段中 Car 對象的 id 字段。
接下來,讓我們創建一個測試以確認一切都按預期工作:
@Test
void givenCar_whenSaveUsingOptions_thenReturnId() {
Car car = new Car();
car.setModel("BMW");
carMapper.saveUsingOptions(car);
assertNotNull(car.getId());
}4.2. @SelectKey 註解
使用 @SelectKey 註解返回 ID 還有另一種方式。<strong>此註解在我們需要使用序列或身份函數來檢索標識符時非常有用。</strong>
此外,如果我們在方法上裝飾了 @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 – 指示語句應在 insert 語句之前執行還是之後執行
- 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 mapper 文件並將所有查詢都放在其中:
<?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 屬性中,我們指定了 CarXmlMapper 接口的完全限定名稱。
5.1. UseGeneratedKeys 屬性
接下來,我們將在 CarXmlMapper 接口中定義一個方法:
void saveUsingOptions(Car car);此外,讓我們使用 XML mapper 定義 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. <em>SelectKey</em> 元素
接下來,讓我們在 <em>CarXmlMapper</em> 接口中添加一個新方法,以查看如何使用 <em>SelectKey</em> 元素檢索身份:
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());
}6. 結論
在本文中,我們學習瞭如何使用 MyBatis 和 Spring 從 <em >insert</em> 語句中檢索自動生成的 ID。
總結一下,我們探討了如何使用基於註解的方法以及 <em >@Options</em> 和 <em >@SelectKey</em> 註解來檢索 ID。此外,我們還研究瞭如何使用基於 XML 的方法返回 ID。