TransactionRequiredException при удалении в потоках - PullRequest
0 голосов
/ 01 марта 2019

У меня проблема при попытке удалить данные из БД с использованием нескольких потоков в 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 голосов
/ 02 марта 2019

Это потому, что вы вызываете метод @Transactional из одного и того же компонента.

@Transactional работает только с методами, вызванными для прокси, созданных Spring.Это означает, что когда вы создаете @Service или другой компонент, метод, вызываемый извне, будет транзакционным.Если он вызывается из bean-компонента, ничего не произойдет, поскольку он не проходит через прокси-объект.

Самое простое решение - переместить метод в другой bean-компонент.Если вы действительно хотите сохранить его в том же компоненте, то вам нужно вызвать его, чтобы он был обернут в прокси с помощью Spring AOP.Вы можете сделать это следующим образом:

private YourClass self;

@Autowired
private ApplicationContext applicationContext;

@PostConstruct
public void postContruct(){
    self = applicationContext.getBean(YourClass.class);
}

Тогда вызов метода self приведет к открытию транзакции.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...