首页 > 解决方案 > Hibernate Isolation 对插入有效吗?

问题描述

我有一个问题可能可以通过各种方式解决,包括重新挑战数据库设计,但我的经理对 Hibernate 注释有偏见,我们就在这里。

我们想在表中插入家庭成员。一些列如下:

(我之所以提到这一点,是因为只有一个家庭成员的类型为 ME 和给定的 client_id,但不确定这对我有什么帮助,但是因为可能有几个 CHILD,因此我无法在两列)

假设用户可能是新用户,刚刚连接了我们的应用程序并从合作伙伴服务中导入了家庭数据。如果它不存在,我们希望将其持久化到我们的数据库中。而且我们还想防止来自另一个线程或实例的并行插入。这是我想出的。

@Transactional(isolation = Isolation.SERIALIZABLE)
public void firstCreateFamily(List<FamilyMember> members, long clientId) {
    if(!this.familyMemberRepository.existByClientId(clientId)) {
        this.familyMemberRepository.save(members);
    }
}

根据文档,使用 SERIALIZABLE 隔离级别会消耗大量数据库性能,但我的经理并不关心,因为我们不需要经常这样做。尽管如此,这种隔离级别应该保证所有事务都将按顺序执行,但我对此不太满意,因为我无法弄清楚框架将如何使其工作。

我认为我们希望它仅适用于这种方法并且工作起来有点像我们已经做到了synchronized,但是同步同时应用于运行我们应用程序的所有实例。然而,我无法想象如果没有 Hibernate 将锁应用到数据库中的整个表并阻止对该表的所有其他请求,这将如何工作。我什至对 Hibernate 是否真的这样做有一些怀疑。

我考虑过使用锁等替代方案,但我认为检查“不存在”是棘手的部分,我想知道 Hibernate 将如何继续比较请求上的两次连续读取。

有人可以帮我弄清楚如何建立该业务以及它是否有机会按预期工作?

(顺便说一句,我犹豫是否要问我关于代码审查的问题,但这更多是关于 Hibernate 内部,而不是关于我困扰的片段)

标签: javaspringhibernatetransaction-isolation

解决方案


这与休眠无关。数据库事务具有隔离级别,该注释仅要求数据库事务具有隔离级别SERIALIZABLE

最好不要试图“想象”它会如何工作,因为你肯定会错。尤其是当您认为是 Hibernate 正在做某事时,当 Hibernate 正常工作并且数据库根据不同的隔离级别(假设为 common default READ COMMITTED)表现不同时。

您也不能期望具有SERIALIZABLE隔离级别的单个事务是正确的,因为其他事务将具有默认隔离级别READ COMMITTED. 只有当所有事务都具有SERIALIZABLE隔离级别时,它们才会得到保证,但即便如此,它们实际上也不会一个接一个地运行,因为这对性能来说是很糟糕的。例如,参见这个关于 Postgres 实现的讨论。

进行该交易SERIALIZABLE 可能会解决您的问题,但如果不了解大局,则无法保证,它可能会偶然而不是设计。如果您对数据库不是很有经验,我建议您寻求外部专业 DBA 的帮助。或者至少在DBA上四处逛逛,直到您意识到问题有多复杂。


推荐阅读