Spring 数据数据安全 from/to 第 3 方查询吗?

Is Spring Data data-safe from/to 3rd party queries?

我对 Spring Data/Hibernate 我读到的与黑盒持久性相关的内容感到困惑 - 主要是查询缓存和刷新。

据我了解:

缓存查询:
Spring 数据不会 运行 直接在数据库上查询事务,而是将它们缓存在内存中,直到某个(可能的最新)时刻——即数据库中的事务提交。这是因为性能 - 因此代码不必在每次 repository 调用时都到达数据库。

法拉盛:
当需要与数据库交互时——例如接收生成的(数字 id)或 default 值 - 代码可以 flush 一个 repository 到 运行 直接在数据库上查询(仍在单个事务中) .这使得可以做例如通过外键等进行数据绑定...

我需要了解以下内容:

在回答你的问题之前,让我先澄清一下。

Spring Data 是一个广泛的保护伞,可以涵盖许多数据存储。例如,有Spring数据JDBC直接与JDBC驱动通信;有 Spring Data Redis 用于提供对 Redis 服务器的存储库访问;并且,与您的问题最相关的是 Spring Data JPA,它使用 JPA 实现(默认情况下为 Hibernate)通过 JPA 与您的数据库进行交互。

您所指的缓存是 Hibernate 的 first-level 缓存 the Persistence Context。它实际上是 JPA 实体的缓存。在刷新时,Hibernate 将采用“已保存”实体(merged/persisted,通过调用 Spring 数据存储库上的 #save 方法触发)并生成适当的 INSERT/UPDATE/DELETE查询更新数据库中的数据。


Is Spring Data completely data-safe to 3rd party data manipulation (e.g. other applications, db console,..)? I mean - is it possible that there can be an inconsistency in transactivity/flushing with other clients?

听起来你在问 Isolation,答案将取决于你认为隔离级别中的“data-safe”。大多数数据库默认为“READ COMMITTED”,其中committed并发事务的数据可以在当前事务中读取,就好像uncommitted改变从未发生过。我假设这是您将坚持使用的隔离级别。更严格的隔离级别需要更仔细的考虑以避免过度锁定。

在 READ COMMITTED 隔离级别下,Hibernate 执行的缓存(就读取现象而言)与通过 non-JPA application/database console/etc.那是因为事务只读取已提交的数据——所以推迟 INSERTs/UPDATEs 并不重要,因为它们的新状态只有在 COMMIT 之后才可见,而不管 INSERT/UPDATE 本身由数据库执行。

实体的缓存是使用持久性上下文完成的。 Persistence Context 绑定到 Hibernate Session。 Hibernate Session 在 Spring 事务开始时打开,并在事务结束时关闭。因此,修改实体的缓存不会比数据库事务更有效。请注意, 有几个例外,但在会话结束时,对实体的 修改 仍然会 flushed/committed 到数据库。


If not, what are the settings to achieve this?

同样,“data-safe”-ness 取决于数据库的默认隔离级别。如果您认为您需要与默认隔离级别不同的隔离级别,您可以通过以下几种方式更改它:

  1. 如果允许,更改整个数据库的隔离级别。这将取决于您使用的是哪种 DBMS,因此您需要查找相应 DBMS 的文档。
  2. 更改 Hibernate 的已配置事务隔离级别,我将参考 this other SO answer,其中还包括对隔离级别的描述
  3. 使用 Spring 的 @Transactional 注释设置隔离级别。例如,可以通过使用 @Transactional(isolation = Isolation.SERIALIZABLE) 注释您的事务方法来设置 SERIALIZABLE 隔离级别。有关其他选项和说明,请参阅 Javadoc

Does Micronaut data work the same way?

我没有使用过 Micronaut 数据,但据我所知,这个问题的答案也将取决于你如何使用 Micronaut 数据。 Micronaut Data JDBC(和 Spring Data JDBC,就此而言)没有实体缓存。据我了解,Micronaut Data JPA 仍然只是委托给 Hibernate,在这种情况下,是的,Hibernate 仍将使用 Persistence Context 执行实体缓存。

就是说,正如我之前提到的,由于 READ COMMITTED 隔离级别的行为,通常不会涉及该隔离级别。

is it possible that there can be an inconsistency in transactivity/flushing with other clients?

是的。 Spring 数据不可能做到这一点。

If not, what are the settings to achieve this?

这取决于问题中未包含的因素,解决方案不一定受设置控制。架构是相关的。

Does Micronaut data work the same way?

关于上述各项,是的。

为了澄清问题,我将添加一个pseudo-code来形象化问题。
考虑在数据库上设置 READ_COMMITED 级别,并且每个方法开头的 number=5

@Transactional
fun read() {
    val number1 = myRepository.findById(1).number
    //now another client commits number = 10
    val number2 = myRepository.findById(1).number
}

@Transactional
fun write() {
    val number1 = myRepository.updateNumberById(id=1, number=10).number
    //now another client commits number = 7
    val number2 = myRepository.findById(1).number
}

每个方法中number1和number2的取值是多少,Hibernate和DB之间的流程是怎样的?