Erro TransactionRequiredException
1. Visão geral
Neste tutorial, vamos examinar a causa do erroTransactionRequiredException e como resolvê-lo.
2. TransactionRequiredException
This error typically occurs when we’re trying to perform a database operation that modifies the database without a transaction.
Por exemplo, tentando atualizar um registro sem uma transação:
Query updateQuery
= session.createQuery("UPDATE Post p SET p.title = ?1, p.body = ?2 WHERE p.id = ?3");
updateQuery.setParameter(1, title);
updateQuery.setParameter(2, body);
updateQuery.setParameter(3, id);
updateQuery.executeUpdate();
Irá gerar uma exceção com uma mensagem nas seguintes linhas:
...
javax.persistence.TransactionRequiredException: Executing an update/delete query
at org.hibernate.query.internal.AbstractProducedQuery.executeUpdate(AbstractProducedQuery.java:1586)
...
3. Fornecimento de uma transação
A solução óbvia é envolver qualquer operação de modificação de banco de dados em uma transação:
Transaction txn = session.beginTransaction();
Query updateQuery
= session.createQuery("UPDATE Post p SET p.title = ?1, p.body = ?2 WHERE p.id = ?3");
updateQuery.setParameter(1, title);
updateQuery.setParameter(2, body);
updateQuery.setParameter(3, id);
updateQuery.executeUpdate();
txn.commit();
No snippet de código acima, iniciamos e confirmamos manualmente a transação. Emborain a Spring Boot environment, we can achieve this by using the @Transactional annotation.
4. Suporte para transações na primavera
If we want more fine-grained control, we can use Spring’s TransactionTemplate. Porque isso permite ao programador disparar a persistência de um objeto imediatamente antes de prosseguir com a execução do código de um método.
Por exemplo, digamos que queremos atualizar a postagem antes de enviar uma notificação por e-mail:
public void update() {
entityManager.createQuery("UPDATE Post p SET p.title = ?2, p.body = ?3 WHERE p.id = ?1")
// parameters
.executeUpdate();
sendEmail();
}
Applying the @Transactional to the method above may cause the email to be sent in spite of an exception in the update process. Isso ocorre porque a transação só será confirmada quando o método for encerrado e estiver prestes a retornar ao chamador.
Portanto, atualizar a postagem dentro deTransactionTemplate evitará este cenário, pois comprometerá a operação imediatamente:
public void update() {
transactionTemplate.execute(transactionStatus -> {
entityManager.createQuery("UPDATE Post p SET p.title = ?2, p.body = ?3 WHERE p.id = ?1")
// parameters
.executeUpdate();
transactionStatus.flush();
return null;
});
sendEmail();
}
5. Conclusão
Em conclusão, geralmente é uma boa prática envolver as operações do banco de dados em uma transação. Ajuda na prevenção de corrupção de dados. O código-fonte completo está disponívelover on Github.