Hibernate Isolation 对插入起作用吗?
Do Hibernate Isolation work on insertion?
我有一个问题可能可以通过多种方式解决,包括 re-challenging 数据库设计,但我的经理对 Hibernate 注释有偏见,现在我们到了。
我们想在 table 中插入家庭成员。部分列如下:
- id(auto-increment,唯一,每个成员一个)
- client_id(独一无二,每个家庭一个)
- member_type(可以是我、伙伴或CHILD)
- 等等
(我提到这个是因为会有一个且只有一个家庭成员具有 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 隔离级别会消耗大量数据库性能,但我的经理不在乎,因为我们不需要经常这样做。然而,这个隔离级别应该保证所有事务都按顺序执行,但我对此不太满意table,因为我无法弄清楚框架将做什么才能使其工作。
我认为我们希望它仅适用于此方法并像我们已经实现的那样工作 synchronized
,但是同步会同时应用于所有实例 运行 我们的应用程序.然而,我无法想象如果没有 Hibernate 对数据库中的整个 table 应用锁并阻止对此 table 的所有其他请求,那将如何工作。我什至怀疑 Hibernate 是否真的这样做了。
我考虑过使用锁等替代方法,但我认为检查 "non existence" 是棘手的部分,我想知道 Hibernate 将如何继续比较请求中的两个连续读取。
有人可以帮我弄清楚如何建立该业务以及它是否有机会按预期运作?
(顺便说一句,我犹豫要不要问我关于代码审查的问题,但这更多的是关于 Hibernate 的内部结构,而不是我感到困扰的代码片段)
这与 Hibernate 无关。数据库事务具有隔离级别,该注释仅请求数据库事务具有 SERIALIZABLE
.
的隔离级别
您最好不要尝试 "imagine" 这将如何工作,因为您肯定会错的。特别是如果你认为是 Hibernate 在做某事,当 Hibernate 正常工作时,它是数据库根据不同的隔离级别(假设通用默认值 READ COMMITTED
)表现不同。
您也不能指望具有 SERIALIZABLE
隔离级别的单个事务是正确的,因为其他事务将具有默认隔离级别 READ COMMITTED
。只有当 所有 事务具有 SERIALIZABLE
隔离级别时,它们才会得到保证,但即便如此,它们实际上并不是 运行 一个接一个地 糟糕 的性能。参见关于 Postgres 实现的例子 this discussion。
进行该交易 SERIALIZABLE
可能 解决您的问题,但在不了解全局的情况下无法保证,它可能是偶然的而不是设计的。如果您对数据库不是很有经验,我建议您寻求外部专业 DBA 的帮助。或者至少在 DBA 上闲逛,直到您意识到问题的复杂性。
我有一个问题可能可以通过多种方式解决,包括 re-challenging 数据库设计,但我的经理对 Hibernate 注释有偏见,现在我们到了。
我们想在 table 中插入家庭成员。部分列如下:
- id(auto-increment,唯一,每个成员一个)
- client_id(独一无二,每个家庭一个)
- member_type(可以是我、伙伴或CHILD)
- 等等
(我提到这个是因为会有一个且只有一个家庭成员具有 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 隔离级别会消耗大量数据库性能,但我的经理不在乎,因为我们不需要经常这样做。然而,这个隔离级别应该保证所有事务都按顺序执行,但我对此不太满意table,因为我无法弄清楚框架将做什么才能使其工作。
我认为我们希望它仅适用于此方法并像我们已经实现的那样工作 synchronized
,但是同步会同时应用于所有实例 运行 我们的应用程序.然而,我无法想象如果没有 Hibernate 对数据库中的整个 table 应用锁并阻止对此 table 的所有其他请求,那将如何工作。我什至怀疑 Hibernate 是否真的这样做了。
我考虑过使用锁等替代方法,但我认为检查 "non existence" 是棘手的部分,我想知道 Hibernate 将如何继续比较请求中的两个连续读取。
有人可以帮我弄清楚如何建立该业务以及它是否有机会按预期运作?
(顺便说一句,我犹豫要不要问我关于代码审查的问题,但这更多的是关于 Hibernate 的内部结构,而不是我感到困扰的代码片段)
这与 Hibernate 无关。数据库事务具有隔离级别,该注释仅请求数据库事务具有 SERIALIZABLE
.
您最好不要尝试 "imagine" 这将如何工作,因为您肯定会错的。特别是如果你认为是 Hibernate 在做某事,当 Hibernate 正常工作时,它是数据库根据不同的隔离级别(假设通用默认值 READ COMMITTED
)表现不同。
您也不能指望具有 SERIALIZABLE
隔离级别的单个事务是正确的,因为其他事务将具有默认隔离级别 READ COMMITTED
。只有当 所有 事务具有 SERIALIZABLE
隔离级别时,它们才会得到保证,但即便如此,它们实际上并不是 运行 一个接一个地 糟糕 的性能。参见关于 Postgres 实现的例子 this discussion。
进行该交易 SERIALIZABLE
可能 解决您的问题,但在不了解全局的情况下无法保证,它可能是偶然的而不是设计的。如果您对数据库不是很有经验,我建议您寻求外部专业 DBA 的帮助。或者至少在 DBA 上闲逛,直到您意识到问题的复杂性。