1. Overview
1.概述
In this tutorial, we’re going to examine the cause of the TransactionRequiredException error and how to solve it.
在本教程中,我们将研究TransactionRequiredException错误的原因以及如何解决它。
2. TransactionRequiredException
2.TransactionRequiredException
This error typically occurs when we’re trying to perform a database operation that modifies the database without a transaction.
这个错误通常发生在我们试图在没有事务的情况下执行一个修改数据库的操作时。
For example, attempting to update a record without a transaction:
例如,试图在没有交易的情况下更新一条记录。
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();
Will raise an exception with a message along the following lines:
将引发一个异常,其信息大致如下。
...
javax.persistence.TransactionRequiredException: Executing an update/delete query
at org.hibernate.query.internal.AbstractProducedQuery.executeUpdate(AbstractProducedQuery.java:1586)
...
3. Providing a Transaction
3.提供事务
The obvious solution is to wrap any database-modifying operation in a transaction:
明显的解决方案是将任何修改数据库的操作包在一个事务中:。
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();
In the code snippet above, we manually initiate and commit the transaction. Although in a Spring Boot environment, we can achieve this by using the @Transactional annotation.
在上面的代码片段中,我们手动启动并提交事务。虽然在Spring Boot环境中,我们可以通过使用@Transactional annotation来实现。
4. Transaction Support in Spring
4.Spring中的事务支持
If we want more fine-grained control, we can use Spring’s TransactionTemplate. Because this allows the programmer to trigger the persistence of an object immediately before proceeding with the code execution of a method.
如果我们想要更细粒度的控制,我们可以使用Spring的TransactionTemplate。因为这允许程序员在进行方法的代码执行之前立即触发对象的持久化。
For example, let’s say we want to update the post before sending an email notification:
例如,假设我们想在发送电子邮件通知之前更新帖子。
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. This is because the transaction will only be committed when the method exits and is about to return to the caller.
将@Transactional应用于上述方法可能会导致电子邮件被发送,尽管在更新过程中出现了异常。这是因为只有当方法退出并即将返回给调用者时,事务才会被提交。
Therefore, updating the post within a TransactionTemplate will prevent this scenario as it’ll commit the operation immediately:
因此,在TransactionTemplate中更新帖子将防止这种情况,因为它将立即提交操作。
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. Conclusion
5.结论
In conclusion, it’s generally a good practice to wrap database operations in a transaction. It helps in preventing data corruption. The complete source code is available over on Github.
总之,一般来说,将数据库操作包裹在一个事务中是一个好的做法。它有助于防止数据损坏。完整的源代码可在Github上找到。