为什么我在Hibernate中需要Transaction才能进行只读操作?
以下事务是否锁定了数据库?
从DB获取的示例代码:
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()
吗?
答案 0 :(得分:115)
您实际上可能有理由将交易标记为只读。
autocommit=true
中工作。@Transactional(readonly=true)
,Spring会将JDBC事务设置为只读模式,因此您将指示在此事务范围内是否可以实际写入DB。如果您的架构很麻烦,并且某些团队成员可能会选择将修改查询放在不合预期的地方,那么这个标志会指向您有问题的地方。总结一下 - 你可以双向进行,但你需要了解后果。
答案 1 :(得分:32)
所有数据库语句都在物理事务的上下文中执行even when we don’t explicitly declare transaction boundaries(BEGIN / COMMIT / ROLLBACK)。
如果您没有明确声明事务边界,那么每个语句都必须在单独的事务中执行(autocommit
模式)。除非您的环境可以处理每线程连接绑定,否则这甚至可能导致每个语句打开和关闭一个连接。
将服务声明为@Transactional
将为您提供整个事务持续时间的一个连接,并且所有语句都将使用该单个隔离连接。这比首先不使用显式事务更好。
在大型应用程序上,您可能会有许多并发请求,而reducing database connection acquisition request rate肯定会提高您的整体应用程序性能。
JPA不会对读取操作强制执行事务。只有在忘记启动事务上下文时,才会写入最终抛出事务所需的异常。然而,即使对于只读事务,声明事务边界总是更好(在Spring @Transactional
中允许您标记只读事务,这具有很大的性能优势)。
答案 2 :(得分:16)
事务确实将锁定放在数据库上 - 良好的数据库引擎以合理的方式处理并发锁定 - 并且对于只读用途非常有用,以确保没有其他事务添加使您的视图不一致的数据。你总是想要一个交易(虽然有时调整隔离级别是合理的,但最好不要这样做);如果您在交易期间从未写过数据库,那么提交和回滚交易的工作都是相同的(并且非常便宜)。
现在,如果你很幸运,并且你对数据库的查询是这样的,ORM总是将它们映射到单个SQL查询,你可以在没有显式事务的情况下离开,依赖于数据库的内置 - 在自动提交行为中,但是ORM是相对复杂的系统,因此依赖这种行为完全不安全,除非你去做更多的工作来检查实现实际上做了什么。编写显式事务边界更容易正确(特别是如果你可以使用AOP或类似的ORM驱动技术;从Java 7开始,我认为也可以使用try-with-resources)。
答案 3 :(得分:12)
无论您是否只阅读 - 数据库必须仍然跟踪您的结果集,因为其他数据库客户端可能希望编写会更改结果集的数据。
我已经看到了错误的程序来杀死庞大的数据库系统,因为它们只是读取数据,但从不提交,迫使事务日志增长,因为DB无法在COMMIT或ROLLBACK之前释放事务数据,即使客户几个小时都没有做任何事。