在线程中删除时的TransactionRequiredException

时间:2019-03-01 18:23:58

标签: java spring hibernate spring-boot jpa

当我尝试通过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)

我一直收到此错误。任何帮助表示赞赏。

1 个答案:

答案 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上调用方法将导致打开交易。