java为什么我需要Hibernate中的事务来执行只读操作?
为什么我需要Hibernate中的事务来执行只读操作
以下事务是否在数据库中设置了锁
从数据库获取的示例代码:
Transaction tx = HibernateUtil.getCurrentSession().beginTransaction(); // why begin transaction?
//readonly operation here
tx.commit() // why tx.commit? I don't want to write anything
我可以用session.close()
代替tx.commit()
吗
# 1 楼答案
事务确实会在数据库上设置锁—好的数据库引擎会以合理的方式处理并发锁—并且对于只读使用非常有用,可以确保没有任何其他事务会添加使视图不一致的数据。您总是想要一个事务(尽管有时调整隔离级别是合理的,但最好不要这样做);如果您在事务期间从未向数据库写入数据,那么提交和回滚事务都是一样的(而且非常便宜)
现在,如果幸运的话,您对DB的查询是这样的,ORM总是将它们映射到单个SQL查询,那么您可以不用显式的事务,依靠DB的内置自动提交行为,但是ORMs是相对复杂的系统,因此依赖这种行为是不安全的,除非你做更多的工作来检查实现的实际功能。在中编写显式事务边界要容易得多(特别是如果可以使用AOP或类似的ORM驱动技术;从Java7开始,我想也可以使用try with resources)
# 2 楼答案
不管您是否只读取,数据库仍然必须跟踪您的结果集,因为其他数据库客户端可能希望写入会更改您的结果集的数据
我见过错误的程序杀死大型数据库系统,因为它们只读取数据,但从不提交,迫使事务日志增长,因为DB无法在提交或回滚之前释放事务数据,即使客户端数小时不做任何事情
# 3 楼答案
实际上,您可能有理由将事务标记为只读
autocommit=true
中工作李>@Transactional(readonly=true)
,Spring将把JDBC事务设置为只读模式,因此您将指定是否可以在该事务的范围内写入DB。如果您的体系结构很麻烦,并且一些团队成员可能会选择将修改查询放在不期望的地方,那么这个标志会将您指向有问题的地方李>总而言之,你可以走两条路,但你需要了解后果
# 4 楼答案
所有数据库语句都在物理事务的上下文中执行,即使我们没有显式声明事务边界(例如,BEGIN、COMMIT、ROLLBACK)
如果不显式声明事务边界,则每个语句都必须在单独的事务(
autocommit
模式)中执行。这甚至可能导致每个语句打开和关闭一个连接,除非您的环境可以处理每个线程的连接绑定将服务声明为
@Transactional
将在整个事务期间为您提供一个连接,并且所有语句都将使用该单个隔离连接。这比一开始不使用显式事务要好得多在大型应用程序上,您可能会有许多并发请求,降低数据库连接获取请求率肯定会提高应用程序的整体性能
JPA不会对读取操作强制执行事务。只有当您忘记启动事务上下文时,写入操作才会抛出
TransactionRequiredException
。然而,即使对于只读事务,声明事务边界也总是更好的(在Spring中@Transactional
允许您标记只读事务,这对性能有很大好处)