如何使用 Spring 的 JdbcTemplate 运行多个查询/更新调用作为同一事务的一部分

问题描述 投票:0回答:1

我正在用 Spring JDBC 编写自己的

DAO
层。 我有一个名为
T insert(T entity);
的方法,它插入一个实体并将更新后的版本返回给用户。在我的代码中,逻辑由两部分组成,调用
NamedParameterJdbcTemplate.update
保存实体,然后调用
NamedParameterJdbcTemplate.queryForObject
从数据库中检索更新的实体。

第一部分执行类似这样的查询:

INSERT INTO client (email_address, company_name)
VALUES ('[email protected]', 'some company name');

第二部分执行类似这样的:

SELECT * FROM client t
WHERE t.id = currval('client_id_seq');

我正在使用 Postgres,其中

client
实际上是一个可更新的视图,而不是一个表,而
client_id_seq
是一个手动定义的序列,使
client
表现得像一个表。

它工作正常,除了这两个语句不是事务性的。理论上,在执行第一条语句和第二条语句之间,可以执行另一个并行语句,这会改变

currval('client_id_seq')
,使我的方法第二部分的结果出错。

有没有办法用Spring Jdbc同时执行和获取数据?我试过多语句查询,司机抱怨有多个

ResultSet
,我也试过这样写事务查询:

BEGIN;

INSERT INTO client (email_address, company_name)
VALUES ('[email protected]', 'some company name');

SELECT * FROM client t
WHERE t.id = currval('client_id_seq');

COMMIT;

司机抱怨说

ResultSet
是空的。

如何确保这两次获取之间的一致性?

编辑:

如果我理解@Mar-Z的答案是正确的,如果

client_id_seq
的值为0,SESSION 1调用
nextval('client_id_seq')
,然后SESSION 2调用
nextval('client_id_seq')
client_id_seq
的ACTUAL值为现在 2。但是,如果我在 SESSION 1 中调用
currval('client_id_seq')
,我会得到 1,如果我在 SESSION 2 中调用
currval('client_id_seq')
,我会得到 2。这看起来很有希望。

我可能唯一担心的另一件事是,我知道 Spring Boot 使用连接池(我认为默认情况下是 HikariCP),以及 1 个经过身份验证的连接 = 1 个 postgres 会话。有没有可能,假设我们在连接池中有一些连接

SESS_1
。插入
update
的第一个
client
调用通过
SESS_1
提交给数据库。在我的
insert()
方法的第一次和第二次调用之间,另一个进程也通过
SESS_1
向数据库提交一些查询,因此将
currval('client_id_seq')
更改为
SESS_1
,然后我的方法的第二部分运行
SELECT 
再次查询
SESS_1
,所以最后,我得到了错误的数据。或者更糟糕的是,如果连接池决定关闭
SESS_1
并为我的
SESS_2
方法的第二部分提供一个不同的连接,比如说
insert()
怎么办?

Spring JDBC 是否有一些东西可以确保不会发生这种情况?我需要配置什么吗?

java spring spring-boot jdbc spring-jdbc
1个回答
0
投票

您无需担心事务和并行更改序列。通过调用 currval('client_id_seq'),您将获得仅在 YOUR 当前会话中使用 nextval('client_id_seq') 获得的序列值。其他会话将使用不同的值。这是由数据库保证的。

更多细节在这里:https://www.postgresql.org/docs/current/functions-sequence.html

© www.soinside.com 2019 - 2024. All rights reserved.