为什么只读操作需要Hibernate中的Transaction?

新手上路,请多包涵

为什么只读操作需要Hibernate中的Transaction?

以下交易是否在数据库中加锁?

从数据库中获取的示例代码:

 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() 吗?

原文由 user93796 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 803
2 个回答

阅读交易可能看起来确实很奇怪,而且在这种情况下人们通常不会标记交易方法。但是 JDBC 无论如何都会创建事务,只是它将在 autocommit=true 中工作,如果没有明确设置不同的选项。但是将事务标记为只读有实际原因:

对数据库的影响

  1. 只读标志可以让 DBMS 优化此类事务或并行运行的事务。
  2. 拥有跨越多个 SELECT 语句的事务可确保从可重复读取或快照开始的级别进行适当的隔离(例如,请参阅 PostgreSQL 的可重复读取)。否则,如果另一个事务并行提交,则 2 个 SELECT 语句可能会看到不一致的画面。这在使用 Read Committed 时不相关。

对 ORM 的影响

  1. 如果您不显式地开始/结束事务,ORM 可能会导致不可预知的结果。例如,Hibernate 将在第一个语句之前打开事务,但它不会完成它。因此连接将以未完成的事务返回到连接池。那么会发生什么? JDBC 保持沉默,因此这是特定于实现的:MySQL、PostgreSQL 驱动程序回滚此类事务,Oracle 提交它。请注意,这也可以在连接池级别进行配置,例如 C3P0 为您提供了这样的选项,默认回滚。
  2. Spring 在只读事务的情况下设置 FlushMode=MANUAL,这会导致其他优化,例如不需要脏检查。这可能会带来巨大的性能提升,具体取决于您加载的对象数量。

对架构和干净代码的影响

无法保证您的方法不会写入数据库。如果您将方法标记为 @Transactional(readonly=true) ,您将决定是否 真的 可以在此事务范围内写入 DB。如果您的体系结构很麻烦,并且某些团队成员可能会选择将修改查询放在不期望的地方,则此标志会将您指向有问题的地方。

原文由 Stanislav Bashkyrtsev 发布,翻译遵循 CC BY-SA 4.0 许可协议

所有数据库语句都在物理事务的上下文中执行,即使我们没有明确声明事务边界(例如,BEGIN、COMMIT、ROLLBACK)也是如此。

如果您没有明确声明事务边界,那么每个语句都必须在单独的事务中执行( autocommit 模式)。这甚至可能导致每个语句打开和关闭一个连接,除非您的环境可以处理每个线程的连接绑定。

将服务声明为 @Transactional 将为您在整个事务期间提供一个连接,并且所有语句都将使用该单个隔离连接。这比一开始不使用显式事务要好得多。

在大型应用程序上,您可能有很多并发请求,降低数据库连接获取请求率肯定会提高您的整体应用程序性能。

JPA 不对读取操作强制执行事务。只有写入最终会抛出 TransactionRequiredException 以防您忘记启动事务上下文。尽管如此,即使对于只读事务,声明事务边界总是更好(在 Spring @Transactional 允许您标记只读事务,这具有很大的性能优势)。

原文由 Vlad Mihalcea 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题