You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 22:16:14