Spring Batch中Jackson反序列化执行上下文异常排查
Spring Batch Jackson反序列化执行上下文错误解决方案
问题根源分析
这个错误大概率是两个原因导致:一是Spring Batch元数据表中残留了旧Job执行时写入的执行上下文数据(你提到的accountIds HashMap就是旧版本Job留下的),二是默认的Jackson序列化配置不信任Object[]这类数组类型,导致反序列化失败。
具体解决步骤
清理旧执行上下文缓存
直接操作Oracle中的Spring Batch元数据表,删除对应Job的旧执行上下文记录:-- 清理Step级执行上下文 DELETE FROM BATCH_STEP_EXECUTION_CONTEXT WHERE STEP_EXECUTION_ID IN ( SELECT STEP_EXECUTION_ID FROM BATCH_STEP_EXECUTION WHERE JOB_EXECUTION_ID IN ( SELECT JOB_EXECUTION_ID FROM BATCH_JOB_EXECUTION WHERE JOB_INSTANCE_ID = ( SELECT JOB_INSTANCE_ID FROM BATCH_JOB_INSTANCE WHERE JOB_NAME = '你的Job名称' ) ) ); -- 清理Job级执行上下文 DELETE FROM BATCH_JOB_EXECUTION_CONTEXT WHERE JOB_EXECUTION_ID IN ( SELECT JOB_EXECUTION_ID FROM BATCH_JOB_EXECUTION WHERE JOB_INSTANCE_ID = ( SELECT JOB_INSTANCE_ID FROM BATCH_JOB_INSTANCE WHERE JOB_NAME = '你的Job名称' ) );如果怕误删,也可以先启动应用时加
spring.batch.job.enabled=false禁用自动执行,清理完再移除该参数。配置Jackson信任目标类型
清理缓存后仍报错的话,需要显式让Spring Batch的Jackson序列化器信任Object[]类型:- 自定义
BatchConfigurer实现:@Configuration public class CustomBatchConfigurer extends DefaultBatchConfigurer { @Override protected JobRepository createJobRepository() throws Exception { JobRepositoryFactoryBean factory = new JobRepositoryFactoryBean(); factory.setDataSource(getDataSource()); factory.setTransactionManager(getTransactionManager()); Jackson2ExecutionContextStringSerializer serializer = new Jackson2ExecutionContextStringSerializer(); serializer.getObjectMapper() .activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL); factory.setSerializer(serializer); factory.afterPropertiesSet(); return factory.getObject(); } } - 或者用Spring Boot配置简化操作(2.7+版本支持):
spring.batch.jackson.mapper.default-typing=NON_FINAL
- 自定义
校验Repository与Reader的返回类型
确保你的Repository查询方法返回的是单一主键类型的列表,而非Object[]:@Repository public interface AccountRepository extends JpaRepository<Account, Long> { @Query("SELECT a.id FROM Account a") List<Long> findAllAccountIds(); }对应的
RepositoryItemReader要匹配返回类型:@Bean public RepositoryItemReader<Long> accountIdReader(AccountRepository accountRepository) { return new RepositoryItemReaderBuilder<Long>() .repository(accountRepository) .methodName("findAllAccountIds") .pageSize(1000) .build(); }
额外提示
每次修改Job的执行上下文逻辑后,建议清理对应Job的旧执行记录,避免新旧数据冲突;生产环境可以配置Spring Batch元数据的定期清理策略,防止无效数据堆积。
内容的提问来源于stack exchange,提问作者Jérémie
相关产品推荐
相关产品推荐

