为什么我需要在Hibernate中进行只读操作?

为什么我需要在Hibernate中进行只读操作?
以下事务是否对db进行了locking?

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

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. 阅读交易可能看起来确实很奇怪,而且在这种情况下,人们通常不会标记交易的方法。 但是,无论如何,JDBC将创build事务,只是如果不明确设置不同的选项,它将在autocommit=true工作。
  2. 但是不能保证你的方法不写入数据库。 如果将方法标记为@Transactional(readonly=true) ,Spring会将JDBC事务设置为只读模式,因此您将决定是否实际上可以在此事务的作用域中写入DB。 如果你的build筑非常麻烦,而且有些团队成员可能不遵循合理的路线,那么这个标志就会指向你有问题的地方。
  3. 另外,只读事务可以通过DB进行优化,但是这当然是DB特定的。 例如,MySQL仅在5.6.4版本开始才在InnoDB中增加对此的支持。
  4. 如果您不是直接使用JDBC,而是使用ORM,那可能会有问题。 例如Hibernate社区说,在事务之外工作可能会导致不可预知的行为。 这是因为Hibernate会打开事务,但是它不会自己closures它,因此连接将被返回到连接池,事务没有被提交。 那会发生什么? JDBC保持沉默,因此这是实现特定的(MySQL回滚事务,Oracle afair提交)。 这也可以在连接池级别configuration(例如,C3P0给你这样一个选项,默认回滚)。
  5. 当涉及到Hibernate的时候,Spring将FlushMode设置为MANUAL以防止只读事务,从而导致其他优化,比如不需要脏检查。
  6. 您可能想要覆盖或显式设置事务隔离级别。 这也会影响读取事务,因为您不希望读取未提交的更改,也不会读取幻像读取等。

总而言之,你可以双向,但你需要了解后果。

事务处理实际上是对数据库进行了locking – 好的数据库引擎以合理的方式处理并发locking,并且对于只读使用来确保没有其他事务添加使视图不一致的数据。 你总是需要一个事务(虽然有时调整隔离级别是合理的,但最好不要这样做); 如果您在交易过程中不写入数据库,那么承诺和回滚事务的效果都是一样的(而且非常便宜)。

现在,如果幸运的话,对数据库的查询是ORM总是将它们映射到单个SQL查询的,那么您可以在没有显式事务的情况下依靠数据库的内置自动提交行为离开,但是ORM是相对复杂的系统所以依靠这样的行为是不安全的,除非你去检查实现实际上做了多less工作。 编写明确的事务边界要容易得多(尤其是如果你可以用AOP或类似的ORM驱动技术来做到这一点;从Java 7开始,我也可以使用试用资源)。

不pipe你只读还是不读 – 数据库必须跟踪你的结果集,因为其他的数据库客户端可能想要写的数据会改变你的结果集。

我看到有缺陷的程序去杀死巨大的数据库系统,因为他们只是读取数据,但从不提交,强制事务日志增长,因为在COMMIT或ROLLBACK之前,DB不能释放事务数据,即使客户端什么也不做用了几个小时。

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

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

将服务声明为@Transactional将为您提供整个事务持续时间的一个连接,并且所有语句都将使用该单独的隔离连接。 这比首先使用显式事务更好。

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

JPA不会强制执行读取操作的事务。 只有写入才会抛出事务所需的exception,以免忘记启动事务性上下文。 尽pipe如此,即使对于只读事务来说,声明事务边界总是更好(在Spring中,@Transactional允许你标记只读事务,这对性能有很大的好处)。

Interesting Posts