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
}
然后在 car-schema.sql
文件中定义建表语句:
CREATE TABLE IF NOT EXISTS CAR
(
ID INTEGER PRIMARY KEY AUTO_INCREMENT,
MODEL VARCHAR(100) NOT NULL
);
3.2. 配置数据源
使用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两种方式实现自增ID的获取。
4. 使用注解方式
定义Mapper接口,MyBatis通过它绑定方法和SQL语句:
@Mapper
public interface CarMapper {
// ...
}
添加基础插入方法:
@Insert("INSERT INTO CAR(MODEL) values (#{model})")
void save(Car car);
⚠️ 常见误区:直接返回 Long
类型并不能获取自增ID,实际返回的是影响行数(成功插入返回1)。
要获取自增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
:实体类中接收ID的字段名
✅ 底层原理: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 注解方案
使用 @SelectKey
获取自增ID,特别适合使用序列或特殊函数生成ID的场景。
⚠️ 注意:当同时存在 @SelectKey
和 @Options
时,前者优先级更高。
实现方法:
@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
:获取ID的SQL语句before
:是否在插入前执行(false表示插入后执行)keyColumn
:主键列名keyProperty
:实体类接收字段resultType
:返回值类型
⚠️ H2数据库兼容性:需设置数据库模式为 LEGACY
才能使用 CALL IDENTITY()
:
"testdb;MODE=LEGACY"
测试验证:
@Test
void givenCar_whenSaveUsingSelectKey_thenReturnId() {
Car car = new Car();
car.setModel("BMW");
carMapper.saveUsingSelectKey(car);
assertNotNull(car.getId());
}
5. 使用XML方式
5.1. 定义XML Mapper
创建 CarXmlMapper
接口:
@Mapper
public interface CarXmlMapper {
// ...
}
在XML文件中定义SQL映射(namespace
需指定接口全路径):
<?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>
5.2. useGeneratedKeys 属性方案
在接口中添加方法:
void saveUsingOptions(Car car);
XML中定义插入语句:
<insert id="saveUsingOptions" parameterType="com.baeldung.mybatis.generatedid.Car"
useGeneratedKeys="true" keyColumn="ID" keyProperty="id">
INSERT INTO CAR(MODEL)
VALUES (#{model});
</insert>
属性说明:
id
:绑定接口方法名parameterType
:参数类型useGeneratedKeys
:启用自增键keyColumn
:主键列名keyProperty
:实体类接收字段
测试验证:
@Test
void givenCar_whenSaveUsingOptions_thenReturnId() {
Car car = new Car();
car.setModel("BMW");
carXmlMapper.saveUsingOptions(car);
assertNotNull(car.getId());
}
5.3. selectKey 元素方案
接口添加方法:
void saveUsingSelectKey(Car car);
XML中使用 selectKey
元素:
<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>
元素属性:
resultType
:返回值类型order
:执行时机(AFTER表示插入后执行)keyColumn
:主键列名keyProperty
:实体类接收字段
测试验证:
@Test
void givenCar_whenSaveUsingSelectKey_thenReturnId() {
Car car = new Car();
car.setModel("BMW");
carXmlMapper.saveUsingSelectKey(car);
assertNotNull(car.getId());
}
6. 总结
本文介绍了在MyBatis和Spring中获取插入数据自增ID的两种实现方式:
✅ 注解方案:
@Options
:简单直接,适合标准自增列@SelectKey
:灵活强大,支持复杂ID生成策略
✅ XML方案:
useGeneratedKeys
:与注解版功能一致selectKey
:提供更细粒度的控制
完整代码示例可在 GitHub仓库 获取。