У меня проблема, когда я пытаюсь удалить данные из БД, используя несколько потоков с 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) Caused by: javax.persistence.TransactionRequiredException: Executing an update/delete query at org.hibernate.jpa.spi.AbstractQueryImpl.executeUpdate(AbstractQueryImpl.java:54)
Я продолжаю получать эту ошибку. Любая помощь приветствуется.




Это потому, что вы вызываете метод @Transactional из того же компонента.
@Transactional работает только с методами, вызываемыми на прокси, созданных Spring. Это означает, что когда вы создаете @Service или другой компонент, метод, вызываемый извне, будет транзакционным. При вызове из bean-компонента ничего не произойдет, так как он не проходит через прокси-объект.
Самым простым решением было бы перенести метод на другой компонент. Если вы действительно хотите сохранить его в одном компоненте, вам нужно вызвать его, чтобы он был обернут в прокси с помощью Spring AOP. Вы можете сделать это так:
private YourClass self;
@Autowired
private ApplicationContext applicationContext;
@PostConstruct
public void postContruct(){
self = applicationContext.getBean(YourClass.class);
}
Тогда вызов метода на self приведет к открытию транзакции.
Вы звоните
this.deleteCustomersInBatches, что аннотировано@Transactional. Эта аннотация здесь неэффективна, потому что вы вызываете нативный метод вместо прокси-метода, который будет перехвачен с использованием аннотации@Transactional.