当我尝试通过Hibernate使用多个线程从数据库中删除数据时遇到问题。
回购:
@Modifying
@Query("DELETE FROM Customer cus WHERE cus.customerId in :customerIds")
public void deleteByCustomerIds(@Param("customerIds") List<Long> customerIds);
服务:
public runDelete (List<Long> customerIds) {
List<List<Long>> partitions = Lists.partition(customerIds, 5000);
for(int i = 0; i < partitions.size(); i++ ) {
final int index = i;
Runnable thread = () -> deleteCustomersInBatches(partitions.get(index));
new Thread(thread).start();
}
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
private void deleteCustomerInBatches(List<Long> customerIds) {
for (List<Long> batch : Lists.partition(oldCalcIds, 1000)) {
customerRepo.deleteByCustomerIds(batch);
}
}
这是代码的样子,我在进行回购调用的服务层上有@Transactional标记。
at java.lang.Thread.run(Thread.java:748)由以下原因引起: javax.persistence.TransactionRequiredException:执行 更新/删除查询 在org.hibernate.jpa.spi.AbstractQueryImpl.executeUpdate(AbstractQueryImpl.java:54)
我一直收到此错误。任何帮助表示赞赏。
答案 0 :(得分:1)
这是因为您正在同一bean中调用@Transactional
方法。
@Transactional
仅适用于在spring创建的代理上调用的方法。这意味着,当您创建@Service
或其他bean时,从外部调用的方法将是事务性的。如果从Bean内部调用,则不会发生任何事情,因为它不会通过代理对象传递。
最简单的解决方案是将方法移至另一个bean。如果您真的想将其保留在同一组件中,则需要调用它,以便在Spring AOP中将其包装在代理中。您可以这样做:
private YourClass self;
@Autowired
private ApplicationContext applicationContext;
@PostConstruct
public void postContruct(){
self = applicationContext.getBean(YourClass.class);
}
然后在self
上调用方法将导致打开交易。