处理 sql 大数据插入异常
handle sql exception for large data insert
我有一个 Spring 2.5 应用程序,它需要一个大 (275K) 文件并对其进行解析。然后将每条记录插入到 Postgres 数据库中。有一个唯一的列(不是 primaryKey/@Id)将踢出尝试的记录插入。这会导致 DataContraintViolationException,这看起来很自然。
我遇到的问题是这会终止进程。有没有一种好的方法可以继续处理整个文件,只记录异常并移动到下一条记录进行插入?我尝试将 respository.save(记录) 包装在 try/catch 中,但它仍然会通过事务回滚终止进程。
A ConstraintViolationException
将包装在 PersistenceException
中,Hibernate 将 generally 标记回滚事务 - even 如果异常是注册为不会在 spring 事务处理级别引起回滚,例如通过 @Transactional(noRollbackFor = PersistenceException.class)
.
所以需要一个不同的解决方案。一些想法:
- 明确查看是否已经存在相应的行(每个项目额外 select)
- 尝试在专用事务中每次插入(例如,使用
@Transactional(propagation = Propagation.REQUIRES_NEW)
注释相应的服务方法(每个项目一个附加事务)
- 处理自定义数据库语句中的约束冲突(例如
ON CONFLICT DO NOTHING
/数据库提供的其他“更新插入”/“合并”行为)
第一个和第二个选项应该提供一些并行化的潜力,因为 selects / inserts 可以彼此独立发出,不需要等待不相关的 DB 往返。
第三个选项可能是最快的,因为它不需要 selects,最少的数据库往返次数,并且可以批处理语句;但是它可能还需要最多的自定义设置:Spring JPA bulk upserts is slow (1,000 entities took 20 seconds) (Reporting back which number or even which entities were actually inserted would likely even increase the complexity: )
我有一个 Spring 2.5 应用程序,它需要一个大 (275K) 文件并对其进行解析。然后将每条记录插入到 Postgres 数据库中。有一个唯一的列(不是 primaryKey/@Id)将踢出尝试的记录插入。这会导致 DataContraintViolationException,这看起来很自然。
我遇到的问题是这会终止进程。有没有一种好的方法可以继续处理整个文件,只记录异常并移动到下一条记录进行插入?我尝试将 respository.save(记录) 包装在 try/catch 中,但它仍然会通过事务回滚终止进程。
A ConstraintViolationException
将包装在 PersistenceException
中,Hibernate 将 generally 标记回滚事务 - even 如果异常是注册为不会在 spring 事务处理级别引起回滚,例如通过 @Transactional(noRollbackFor = PersistenceException.class)
.
所以需要一个不同的解决方案。一些想法:
- 明确查看是否已经存在相应的行(每个项目额外 select)
- 尝试在专用事务中每次插入(例如,使用
@Transactional(propagation = Propagation.REQUIRES_NEW)
注释相应的服务方法(每个项目一个附加事务) - 处理自定义数据库语句中的约束冲突(例如
ON CONFLICT DO NOTHING
/数据库提供的其他“更新插入”/“合并”行为)
第一个和第二个选项应该提供一些并行化的潜力,因为 selects / inserts 可以彼此独立发出,不需要等待不相关的 DB 往返。
第三个选项可能是最快的,因为它不需要 selects,最少的数据库往返次数,并且可以批处理语句;但是它可能还需要最多的自定义设置:Spring JPA bulk upserts is slow (1,000 entities took 20 seconds) (Reporting back which number or even which entities were actually inserted would likely even increase the complexity: