Spring事务性只读和隔离级别

Posted

技术标签:

【中文标题】Spring事务性只读和隔离级别【英文标题】:Spring transactional readOnly and isolation levels 【发布时间】:2018-08-02 07:01:21 【问题描述】:

我读到了 spring/hibernate 中的传播和隔离。 我有一种特定的方法,我们有

0. @Transactional (the default spring annotation)
1. read several rows
2. some business logic
3. read (from other table using some data from the first read)

这对我来说有点不安全。如果其他人在步骤 2 中删除了一行怎么办。 我认为我应该将方法注释更改为

@Transactional(readOnly = true, isolation = Isolation.SERIALIZABLE)

这对我的具体情况有效吗? (任务是修复导致系统出现一些问题的事务注释并尽可能少地更改其他代码行) 提前致谢。

【问题讨论】:

【参考方案1】:

如果我理解你的情况,你有一些方法,可以从数据库中读取几次。

所以,如果你的方法只是从数据库中读取,那么你只需要像这样的注释:@Transactional(readOnly = true, isolation = Isolation.SERIALIZABLE)

因为实际上你只是从数据库中读取数据。

但是,如果您的方法同时提供对数据库读取和写入的访问权限 - 最好的方法是将其分成两种方法,其中一种是只读的。

【讨论】:

是的,但它不是“公正的”,因为 SERIALIZABLE 是最重的隔离。我们真的需要它吗?也许是的 - 99% 肯定。 @saferJo 对不起,我更正了我的答案并删除了 SERIALIZABLE,它只是拼写错误 如果在业务逻辑期间有人从第一个表中删除了某些内容并提交了怎么办。 @saferJo 所以,这取决于项目... Read Uncommitted: 允许脏读 Read Committed: 不允许脏读 Repeatable Read: 如果一行在同一个事务中被读取两次,结果总是相同 可序列化:按顺序执行所有事务这里是隔离列表 所以在我的情况下应该是可序列化的,因为第二次读取将依赖于表中的某些内容不会同时被删除......【参考方案2】:

这取决于您所说的不安全是什么意思,您编写的业务逻辑是什么,在您的示例中,您只执行读取操作,而在快速读/写操作中建议使用可序列化,如果在第一个表中更新某些内容,也适用于您的情况一个可序列化的事务将像一个冻结的环境一样运行,没有任何东西被执行, 只要其他交易插入数据,它对您来说就是不可见的,因此最终您第二次读取的结果可能是错误的

正如他们在 oracle 上提到的例子:

除非在编写此类应用程序级一致性检查时考虑到这一点,否则可能会导致数据库不一致,即使在使用可序列化事务时也是如此。

此外,当您在此处使用可序列化时,您必须注意 无法序列化访问,当您尝试更新同一个表时,可能会在您的代码(其他类)中发生异常,这可能会很棘手

解决这个问题的另一种方法是使用读取提交隔离,当您重新实现第二次读取时,请记住代表数据库的真实状态,我的意思是如果其他行接收更新并且 commit 他们必须考虑使用第一次阅读中使用的数据,如果没有您的方法的真实示例,我无法为您提供完整的工作示例。

【讨论】:

以上是关于Spring事务性只读和隔离级别的主要内容,如果未能解决你的问题,请参考以下文章

spring事务 只读此文

spring事务

spring tx——TransactionManger

Spring事务

Spring 事务类型与隔离级别

Spring事务隔离级别:REQUIRES_NEW使用细节