Spring Batch按日期排序时oracle.sql.TIMESTAMP序列化报错如何解决?
问题根因
- 你自定义的全局ObjectMapper不生效是因为Spring Batch内部处理执行上下文序列化的
Jackson2ExecutionContextStringSerializer是单独初始化的,默认不会复用Spring容器里的@PrimaryObjectMapper,所以你加的Oracle TIMESTAMP序列化规则根本没被Batch用到。 - 报错的本质是
JdbcPagingItemReader做分页时,会把每页最后一条的排序键值(也就是你这里的MY_DT字段值)作为分页偏移量存到执行上下文里,而Oracle JDBC驱动默认返回的日期类型是oracle.sql.TIMESTAMP原生类型,Jackson没有内置的序列化支持,就会触发你看到的序列化失败错误。
解决方案推荐
方案1:修改JDBC连接参数(最省力)
直接在你的Oracle数据库连接URL或者连接属性里添加参数oracle.jdbc.J2EE13Compliant=true,这个参数会让Oracle驱动把原生的oracle.sql.TIMESTAMP自动转换成标准的java.sql.Timestamp返回,Jackson本身支持对标准JDK日期类型的序列化,不需要额外改代码。
示例连接配置:
spring.datasource.url=jdbc:oracle:thin:@//host:port/service?oracle.jdbc.J2EE13Compliant=true
方案2:显式配置Spring Batch的执行上下文序列化器(适合需要保留序列化自定义规则的场景)
你需要把自定义的序列化规则注册到Spring Batch专用的序列化器里,而不是只定义全局ObjectMapper:
@Configuration @EnableBatchProcessing public class BatchConfig extends DefaultBatchConfigurer { @Override protected ExecutionContextSerializer createExecutionContextSerializer() { ObjectMapper objectMapper = new ObjectMapper(); // 注册你自己写的OracleTimestampSerializer SimpleModule simpleModule = new SimpleModule(); simpleModule.addSerializer(oracle.sql.TIMESTAMP.class, new OracleTimestampSerializer()); objectMapper.registerModule(simpleModule); // 其他你需要的ObjectMapper配置 return new Jackson2ExecutionContextStringSerializer(objectMapper); } }
注意:你之前写的序列化器里加的RuntimeException测试用的代码要记得删掉,否则会主动抛异常。另外建议你把序列化逻辑改成将oracle.sql.TIMESTAMP转成标准LocalDateTime后序列化,比写二进制兼容性更好,反序列化也更方便
方案3:关闭Reader的状态保存(适合不需要断点重启的一次性作业)
如果你的作业不需要支持失败后从断点重启,可以直接给JdbcPagingItemReader设置saveState=false,这样Reader就不会把分页偏移量存到执行上下文里,也就不会触发序列化流程,自然不会报错:
JdbcPagingItemReader<YourEntity> reader = new JdbcPagingItemReader<>(); reader.setSaveState(false); // 其他reader配置
内容的提问来源于stack exchange,提问作者kamaci
相关产品推荐
相关产品推荐

