JdbcTemplate 获取自增ID
JdbcTemplate
是由 spring-jdbc
提供的一个 JDBC 工具类模块,可以快速地对数据库进行 CURD 操作。
本文将会教你如何在使用 JdbcTemplate
执行 INSERT
操作时获取到自增ID。
项目设置
创建任意 spring boot 项目。添加 mysql-connector-j
以及 spring-boot-starter-jdbc
依赖。
你可以通过 start.springboot.io 快速创建此示例项目。
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
配置数据源
在 application.yaml
中配置基础的数据源信息。
spring:
datasource:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&allowMultiQueries=true
username: root
password: root
配置 JdbcTemplate
通过配置类,注册 JdbcTemplate
Bean。
import javax.sql.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
@Configuration
public class JdbcTemplateConfiguration {
@Bean
public JdbcTemplate jdbcTemplate (DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
}
创建示例表
CREATE TABLE `users` (
`id` int unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
`account` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '账户',
`create_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '用户名称',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='系统用户';
其中 id
字段是自增的。
GeneratedKeyHolder
spring-jdbc
提供了一个 GeneratedKeyHolder
类,通过它可以获取到自增列的值。
public class GeneratedKeyHolder implements KeyHolder {
// 返回唯一自增 key 的值
public Number getKey();
// 返回唯一自增 key 的值,指定其返回类型
public <T> T getKeyAs(Class<T> keyType);
// 返回多个自增 key 及其值
public Map<String, Object> getKeys();
public List<Map<String, Object>> getKeyList();
}
JdbcTeplate 获取自增 ID
在 src/test/main
包下创建测试类:
import java.sql.Types;
import java.time.LocalDateTime;
import java.util.Arrays;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.PreparedStatementCreator;
import org.springframework.jdbc.core.PreparedStatementCreatorFactory;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.test.context.junit4.SpringRunner;
import cn.springdoc.demo.DemoApplication;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = DemoApplication.class, webEnvironment = WebEnvironment.RANDOM_PORT)
public class DemoApplicationTest {
static final Logger logger = LoggerFactory.getLogger(DemoApplicationTest.class);
@Autowired
private JdbcTemplate jdbcTemplate;
@Test
public void test() {
// 创建 GeneratedKeyHolder 对象
GeneratedKeyHolder keyHolder = new GeneratedKeyHolder();
// Insert SQL
String sql = "INSERT INTO `users`(`id`, `account`, `create_at`, `name`) VALUES(?, ?, ?, ?);";
// 初始化 CreatorFactory,指定要执行的 SQL,以及参数的 Jdbc 类型
PreparedStatementCreatorFactory factory = new PreparedStatementCreatorFactory(sql,
Types.BIGINT, Types.VARCHAR, Types.TIMESTAMP, Types.VARCHAR);
// 需要返回自增记录值
factory.setReturnGeneratedKeys(true);
// 设置占位符参数,返回 creator
PreparedStatementCreator creator = factory
.newPreparedStatementCreator(Arrays.asList(null, "springdoc.cn", LocalDateTime.now(), "Spring 中文网"));
// 执行更新,返回受影响行数
int retVal = this.jdbcTemplate.update(creator, keyHolder);
// 通过 keyHolder 获取到自增值
Long id = keyHolder.getKey().longValue();
logger.info("受影响行数 = {}, 自增ID = {}", retVal, id);
}
}
执行测试,输出日志如下:
INFO 5372 --- [ main] cn.springdoc.test.DemoApplicationTest : 受影响行数 = 1, 自增ID = 101
NamedParameterJdbcTemplate 获取自增 ID
NamedParameterJdbcTemplate
封装了 JdbcTeplate
,提供了 “命名参数” 的支持。
同样,需要先在配置类中注册 Bean。
@Bean
public NamedParameterJdbcTemplate namedParameterJdbcTemplate (DataSource dataSource) {
return new NamedParameterJdbcTemplate(dataSource);
}
创建测试:
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.test.context.junit4.SpringRunner;
import cn.springdoc.demo.DemoApplication;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = DemoApplication.class, webEnvironment = WebEnvironment.RANDOM_PORT)
public class DemoApplicationTest {
static final Logger logger = LoggerFactory.getLogger(DemoApplicationTest.class);
@Autowired
private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
@Test
public void test() {
// 创建 GeneratedKeyHolder 对象
GeneratedKeyHolder keyHolder = new GeneratedKeyHolder();
// Insert SQL
String sql = "INSERT INTO `users`(`id`, `account`, `create_at`, `name`) VALUES(:id, :account, :create_at, :name);";
// 使用 Map 封装参数,key 就是 SQL 中对应的参数名称
Map<String, Object> params = new HashMap<>();
params.put("id", null);
params.put("account", "springdoc.cn");
params.put("create_at", LocalDateTime.now());
params.put("name", "Spring 中文网");
// 执行更新,返回受影响行数
int retVal = this.namedParameterJdbcTemplate.update(sql, new MapSqlParameterSource(params), keyHolder);
// 通过 keyHolder 获取到自增值
Long id = keyHolder.getKey().longValue();
logger.info("受影响行数 = {}, 自增ID = {}", retVal, id);
}
}
注意,这里的 insert
SQL 语句中,我们使用了 “命名参数” 占位符,而不是问号。
执行测试,输出日志如下:
INFO 13016 --- [ main] cn.springdoc.test.DemoApplicationTest : 受影响行数 = 1, 自增ID = 102