JdbcClient操作PostgreSQL时,如何在查询间强制提交以更新CURRENT_TIMESTAMP?
解决JdbcClient同事务中CURRENT_TIMESTAMP值相同的问题
问题原因
PostgreSQL的CURRENT_TIMESTAMP返回的是当前事务启动时的时间戳,同一个事务内多次调用该函数会返回完全相同的值,这是数据库的设计特性,并非JdbcClient的问题。你的测试方法默认处于Spring的事务管理下,两次查询共用同一个事务,因此time1和time2值相等。
解决方案:在查询间强制提交事务
方法1:使用REQUIRES_NEW事务传播级别
通过将每个查询逻辑放到标记为@Transactional(propagation = Propagation.REQUIRES_NEW)的方法中,让每次查询都运行在独立事务里,执行完毕后自动提交:
@Autowired private JdbcClient jdbcClient; @Test void test() { var time1 = getCurrentTimestamp(); System.out.println(time1); var time2 = getCurrentTimestamp(); System.out.println(time2); assertThat(time2).isAfter(time1); } @Transactional(propagation = Propagation.REQUIRES_NEW) private Timestamp getCurrentTimestamp() { return (Timestamp) jdbcClient.sql("SELECT CURRENT_TIMESTAMP").query().singleValue(); }
该传播级别会暂停当前正在执行的事务(如果存在),新建一个独立事务执行目标方法,执行完成后提交新事务,再恢复原事务。
方法2:手动管理事务(用PlatformTransactionTemplate)
借助Spring的PlatformTransactionTemplate手动控制事务的创建和提交,确保每次查询都在独立事务中执行:
@Autowired private JdbcClient jdbcClient; @Autowired private PlatformTransactionTemplate transactionTemplate; @Test void test() { var time1 = transactionTemplate.execute(status -> (Timestamp) jdbcClient.sql("SELECT CURRENT_TIMESTAMP").query().singleValue() ); System.out.println(time1); var time2 = transactionTemplate.execute(status -> (Timestamp) jdbcClient.sql("SELECT CURRENT_TIMESTAMP").query().singleValue() ); System.out.println(time2); assertThat(time2).isAfter(time1); }
transactionTemplate.execute()方法会自动完成事务的开启、提交(无异常时)操作,每次调用对应一个独立事务。
注意事项
- 强制拆分事务会增加数据库事务的开销,仅建议在测试场景或确有必要的业务逻辑中使用。
- Spring Boot的测试方法默认被
@Transactional注解包裹,这也是测试中两次查询共享事务的原因。
内容的提问来源于stack exchange,提问作者Denis
相关产品推荐
相关产品推荐

