Spring Batch使用HibernateItemWriter连Azure SQL报错,如何实现重试逻辑?
问题解决方案
结论
你遇到的是Azure SQL的瞬态网络故障,完全可以通过重试逻辑解决。
现有代码问题修正
你当前的实现有两处明显错误:
- HibernateItemWriter 不应该在每次
write()方法执行时重复实例化,该类是线程安全的,应该在Bean初始化阶段完成实例化和属性设置 afterPropertiesSet()是初始化校验方法,需要在write()调用前执行,你当前放在写完数据后调用完全不符合规范
修正后的Writer示例代码:
public class StoreWriter implements ItemWriter<Store> { private static final Logger logger = Logger.getLogger(StoreWriter.class); private HibernateItemWriter<Store> hibernateItemWriter; @Autowired private SessionFactory sessionFactory; // 初始化阶段完成HibernateItemWriter配置 @PostConstruct public void init() { hibernateItemWriter = new HibernateItemWriter<>(); hibernateItemWriter.setSessionFactory(sessionFactory); hibernateItemWriter.afterPropertiesSet(); } @Override public void write(List<? extends Store> items) throws Exception { hibernateItemWriter.write(items); logger.info(String.format("Store Processing Completed %s", LocalDateTime.now())); } }
重试逻辑实现方案
推荐直接使用Spring Batch原生的重试配置,不需要额外硬编码重试逻辑,在Step定义时配置即可:
@Bean public Step storeProcessStep(JobRepository jobRepository, PlatformTransactionManager transactionManager, StoreReader reader, StoreProcessor processor, StoreWriter writer) { return new StepBuilder("storeProcessStep", jobRepository) .<Store, Store>chunk(100, transactionManager) .reader(reader) .processor(processor) .writer(writer) // 容错重试配置 .faultTolerant() // 仅对瞬态连接异常重试,不要全局重试所有异常 .retry(org.hibernate.exception.JDBCConnectionException.class) .retry(com.microsoft.sqlserver.jdbc.SQLServerException.class) // 最大重试次数,可根据实际场景调整 .retryLimit(3) // 指数退避策略:首次重试间隔1秒,后续间隔翻倍,最大间隔10秒,避免瞬时高并发请求打垮数据库 .backOffPolicy(backOffPolicy()) .build(); } private BackOffPolicy backOffPolicy() { ExponentialBackOffPolicy backOffPolicy = new ExponentialBackOffPolicy(); backOffPolicy.setInitialInterval(1000); backOffPolicy.setMultiplier(2); backOffPolicy.setMaxInterval(10000); return backOffPolicy; }
如果你不想修改现有Writer结构,也可以使用Spring Retry注解实现:
- 在配置类上添加
@EnableRetry注解开启重试功能 - 在write方法上添加重试注解:
@Retryable(retryFor = {JDBCConnectionException.class, SQLServerException.class}, maxAttempts = 3, backoff = @Backoff(delay = 1000, multiplier = 2, maxDelay = 10000)) @Override public void write(List<? extends List<Store>> items) throws Exception { // 你的原有业务逻辑 }
额外优化建议
- 驱动层面配置重试:在Azure SQL的JDBC连接URL中添加参数
connectRetryCount=3;connectRetryInterval=10,让JDBC驱动层面先做一层连接重试 - 连接池配置优化:给数据源配置连接有效性校验,比如添加
testOnBorrow=true;validationQuery=SELECT 1,避免拿到失效的连接 - 幂等性保证:写入数据的表需要配置唯一主键约束,避免重试时出现重复插入的脏数据
内容的提问来源于stack exchange,提问作者One Developer
相关产品推荐
相关产品推荐

