【问题标题】:hibernate get data after flush before commit提交前刷新后休眠获取数据
【发布时间】:2017-03-28 15:29:28
【问题描述】:

在我的服务类(注解为 Transactional)中,我更新对象并将其另存为:

myObj.save(flush:true)   //(Thread A, updates the value, Step A)

在此之后,会进行需要很长时间的数据处理。在此处理期间,在域类中进行了很多更改,但这些更改与此处无关。由于所有这些处理都发生在同一个服务类中,因此它是单个事务的一部分。

现在,与此同时,当所有这些处理正在进行时,另一个线程,它是不同休眠会话的一部分,访问

MyObj.findAll() //Thread B 在结果集中我看到了更新的值。 Step A 中更新的值 但是,线程 A 尚未完成,因此尚未将更改提交到数据库。我可以确认这一点,因为同时如果我直接在 mysql 工作台中运行查询,那么我看不到更改。仅当通过休眠访问对象时更改可见。

我的印象是,如果由于刷新而进行了更改,那么这些更改在同一个事务中可见,而在其他事务中不可见。有人可以澄清一下吗?

【问题讨论】:

    标签: mysql hibernate grails grails-orm


    【解决方案1】:

    答案是这取决于 mysql 服务器中使用的隔离级别。正如innodb transaction isolation levels 上的 mysql 文档所说:

    隔离级别是微调之间平衡的设置 性能和可靠性、一致性和再现性 多个事务进行更改并执行时的结果 同时查询。

    InnoDB 提供了由 SQL:1992 标准:未提交读、已提交读、可重复读、 和可序列化的。 InnoDB 的默认隔离级别是 REPEATABLE 阅读。

    文档非常详细地描述了各个级别之间的差异。我想特别提请您注意未提交的阅读级别:

    SELECT 语句以非锁定方式执行,但是 可能会使用行的早期版本。因此,使用这个 隔离级别,这样的读取是不一致的。这也称为 脏读。否则,此隔离级别的工作方式类似于 READ COMMITTED。

    此隔离级别使查询能够读取由尚未提交的其他事务更新的数据。但是,在您的代码中使用此隔离级别之前,请确保您了解此隔离级别的所有含义。您无法挑选要查看哪些交易的未提交数据。因此,您可以选择稍等片刻来获取提交的数据。

    【讨论】:

    • 感谢您的解释,它真的很有帮助。但是,当我使用查询“select @@GLOBAL.tx_isolation, @@tx_isolation;”检查 MySQL 中的隔离级别时它显示“可重复阅读”。我会调查 hibernate 是否设置了一些隔离级别,虽然不应该是这样,但我仍然会尝试找出答案。任何其他想法/解释为什么它可能会发生,因为隔离级别是可重复读取的。
    • 从答案的第一个引号中可以看出,"The default isolation level for InnoDB is REPEATABLE READ." 根据我的经验,ORM 很少设置隔离级别,它们只使用设置的任何内容。
    • 是的,这也是我的假设。 Hibernate 肯定没有设置隔离级别。这就是为什么最初的根本原因仍然未知的原因。感谢您抽出宝贵时间,让我知道是否还有其他需要调查的内容,以找出为什么线程 B 在线程 A 尚未完成时读取更新。
    猜你喜欢
    • 2011-07-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-25
    相关资源
    最近更新 更多