Spring Batch中HQL查询如何获取正确的UTC时间
解决方法
方案1:使用StepScope传入动态UTC时间参数(最稳妥,无数据库依赖)
默认@Bean是单例模式,只会在应用启动时初始化一次,这是你无法每次任务运行传入最新时间的核心原因。给Reader添加@StepScope注解即可让其在每次步骤运行时重新实例化,拿到任务运行时的当前UTC时间:
@Bean @StepScope fun postgresPostReader(): ItemReader<Post> { // 每次步骤运行时生成当前UTC时间 val currentUtcTime = Instant.now() return JpaPagingItemReaderBuilder<Post>() .name("postgresPostReader") .entityManagerFactory(entityManagerFactory) .queryString("SELECT p FROM Post p WHERE p.expireAt <= :currentUtcTime") // 传入动态参数 .parameterValues(mapOf("currentUtcTime" to currentUtcTime)) .pageSize(1000) .build() }
注意:Spring Boot项目默认已开启StepScope支持,无需额外配置。
方案2:直接在JPQL中调用数据库UTC时间函数(无需修改Bean作用域)
如果你不想调整Bean的作用域,可以直接调用Postgres原生的时区转换函数获取UTC时间,避免时区偏差:
@Bean fun postgresPostReader(): ItemReader<Post> { return JpaPagingItemReaderBuilder<Post>() .name("postgresPostReader") .entityManagerFactory(entityManagerFactory) // 调用Postgres的timezone函数将当前时间转为UTC .queryString("SELECT p FROM Post p WHERE p.expireAt <= FUNCTION('timezone', 'UTC', CURRENT_TIMESTAMP)") .pageSize(1000) .build() }
原方案失效原因
CURRENT_TIMESTAMP配合hibernate.jdbc.time_zone=UTC不生效:部分Hibernate版本中,CURRENT_TIMESTAMP返回的时间不会遵循该时区配置,仍使用JVM默认时区,和Instant类型的UTC时间对比会出现偏差。now()不符合要求:Postgres的now()返回的是数据库服务器所在时区的时间,不是标准UTC时间。- 直接传入
Instant.now()失效:默认单例Bean仅在应用启动时初始化一次,时间不会随任务运行更新。
内容的提问来源于stack exchange,提问作者Annon
相关产品推荐
相关产品推荐

