This article will teach you how to get auto-incrementing IDs when using JdbcTemplate
or NamedParameterJdbcTemplate
.
Table (MYSQL)
Suppose the following data table is available.
1
2
3
4
5
6
7
8
9
10
|
CREATE TABLE `user` (
`id` int unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
`balance` decimal(10,2) DEFAULT NULL,
`create_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`enabled` tinyint unsigned NOT NULL,
`name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`update_at` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='user';
|
As you can see, the id
field is an auto-incrementing column.
JdbcTemplate
spring-jdbc
provides the GeneratedKeyHolder
object to get the auto-incremented ID value after data insertion.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
|
package io.springcloud.test;
import java.math.BigDecimal;
import java.sql.PreparedStatement;
import java.sql.Statement;
import java.time.LocalDateTime;
import javax.sql.DataSource;
import org.junit.Test;
import org.junit.runner.RunWith;
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.support.GeneratedKeyHolder;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.transaction.annotation.Transactional;
import io.springboot.demo.DemoApplication;
import lombok.extern.slf4j.Slf4j;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = DemoApplication.class, webEnvironment = WebEnvironment.RANDOM_PORT)
@Slf4j
public class DemoApplicationTest {
@Autowired
DataSource dataSource;
@Test
@Transactional
@Rollback(false)
public void test() {
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
// Create GeneratedKeyHolder object
GeneratedKeyHolder generatedKeyHolder = new GeneratedKeyHolder();
String sql = "INSERT INTO `user`(`balance`, `create_at`, `enabled`, `name`, `update_at`) VALUES(?, ?, ?, ?, ?);";
// To insert data, you need to pre-compile the SQL and set up the data yourself.
int rowsAffected = jdbcTemplate.update(conn -> {
// Pre-compiling SQL
PreparedStatement preparedStatement = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
// Set parameters
preparedStatement.setBigDecimal(1, new BigDecimal("15.88"));
preparedStatement.setObject(2, LocalDateTime.now());
preparedStatement.setBoolean(3, Boolean.TRUE);
preparedStatement.setString(4, "JdbcTemplate");
preparedStatement.setObject(5, LocalDateTime.now());
return preparedStatement;
}, generatedKeyHolder);
// Get auto-incremented ID
Integer id = generatedKeyHolder.getKey().intValue();
log.info("rowsAffected = {}, id={}", rowsAffected, id);
}
}
|
The output log is as follows, everything is OK.
1
|
2022-06-06 17:03:11.240 INFO 8964 --- [ main] io.springcloud.test.DemoApplicationTest : rowsAffected = 1, id=11
|
NamedParameterJdbcTemplate
The usage of NamedParameterJdbcTemplate
is not much different from JdbcTemplate
. But it supports using named parameters in SQL instead of ?
, by this feature we can directly use objects or Map as parameters. Very friendly. In actual development, it is more recommended to use it.
The NamedParameterJdbcTemplate
also provides more rich methods, you can refer to the documentation to learn more.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
|
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import javax.sql.DataSource;
import org.junit.Test;
import org.junit.runner.RunWith;
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.annotation.Rollback;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.transaction.annotation.Transactional;
import io.springboot.demo.DemoApplication;
import lombok.extern.slf4j.Slf4j;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = DemoApplication.class, webEnvironment = WebEnvironment.RANDOM_PORT)
@Slf4j
public class DemoApplicationTest {
@Autowired
DataSource dataSource;
@Test
@Transactional
@Rollback(false)
public void test() {
NamedParameterJdbcTemplate namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
// The GeneratedKeyHolder object is used to get the auto-incrementing ID.
GeneratedKeyHolder generatedKeyHolder = new GeneratedKeyHolder();
// SQL placeholders can use named parameters instead of "?".
String sql = "INSERT INTO `user`(`balance`, `create_at`, `enabled`, `name`, `update_at`) VALUES(:balance, :create_at, :enabled, :name, :update_at);";
// params
Map<String, Object> params = new HashMap<>();
params.put("balance", new BigDecimal("25.66"));
params.put("create_at", LocalDateTime.now());
params.put("enabled", Boolean.FALSE);
params.put("name", "NamedParameterJdbcTemplate");
params.put("update_at", LocalDateTime.now());
int rowsAffected = namedParameterJdbcTemplate.update(sql, new MapSqlParameterSource(params), generatedKeyHolder);
Integer id = generatedKeyHolder.getKey().intValue();
log.info("rowsAffected = {}, id={}", rowsAffected, id);
}
}
|
The output log is as follows, everything is OK.
1
|
2022-06-06 17:10:19.167 INFO 12408 --- [ main] io.springcloud.test.DemoApplicationTest : rowsAffected = 1, id=12
|
Summary
Get the auto-incremented ID through the GeneratedKeyHolder
object.
If you use JdbcTemplate
, then you need to pre-compile the SQL and set the parameters yourself, which is more troublesome. It is more recommended to use NamedParameterJdbcTemplate
.
GeneratedKeyHolder
has some other methods, if you want to know more, you can refer to its documentation.
Finally, take a look at the 2 data we inserted.
1
2
3
4
5
6
7
8
|
mysql> select * from `user`;
+----+---------+---------------------+---------+----------------------------+---------------------+
| id | balance | create_at | enabled | name | update_at |
+----+---------+---------------------+---------+----------------------------+---------------------+
| 11 | 15.88 | 2022-06-06 17:03:11 | 1 | JdbcTemplate | 2022-06-06 17:03:11 |
| 12 | 25.66 | 2022-06-06 17:10:19 | 0 | NamedParameterJdbcTemplate | 2022-06-06 17:10:19 |
+----+---------+---------------------+---------+----------------------------+---------------------+
2 rows in set (0.00 sec)
|