使用 REPEATABLE READ 保证特定值的唯一性
Guarantee uniqueness of speciifc values using REPEATABLE READ
我们有一个简单的 table:
Human:
+------+
|Height|
+------+
| |
+------+
我有一个方法可以添加一个人:
@AutoWired
HumanRepository humanRepo; // JpaRepository
@Transactional(isolationLevel = REPEATABLE_READ)
void addHuman(int height){
if(humanRepo.existsByHeight(height){
throw new HumanWithSuchHeightExists();
}
humanRepo.save(Human.builder().height(height).build())
}
而且我想保证确实存在一个特定身高的男人。
REPEATABLE_READ
可以保证吗?
- 我的代码(伪代码)是否满足该条件?
理论上说,唯一能够绝对保证 re 的隔离级别。数据完整性(wrt 声明的规则)是可序列化的。
使用 REPEATABLE READ,从理论上讲,您仍然面临着两个事务试图插入同一行以及以下事件序列让其通过的风险:
T1 检查行是否存在,行不存在
T2 检查行是否存在,行不存在
T1 插入,可能重复行的存在检查(仍然不存在)
T2 插入,可能会重复该行的存在性检查(仍然 "not exist" 因为 T1 尚未提交,因此其新插入的数据对 T2 不可见)。
T1 提交
T2 提交
REPEATABLE READ,顾名思义,只提供关于 现有行 的保证(即 if 找到一行存在,它不会被其他事务更改,然后读取变为 "repeatable")。
是的,PostgreSQL SERIALIZABLE 应该防止创建多个具有相同高度的记录。它将中止 T1 或 T2。
我认为该异常正式称为反依赖循环 (G2)。这是一个good reference that includes major databases
此外,为什么不使用 unique constraint 呢?
我们有一个简单的 table:
Human:
+------+
|Height|
+------+
| |
+------+
我有一个方法可以添加一个人:
@AutoWired
HumanRepository humanRepo; // JpaRepository
@Transactional(isolationLevel = REPEATABLE_READ)
void addHuman(int height){
if(humanRepo.existsByHeight(height){
throw new HumanWithSuchHeightExists();
}
humanRepo.save(Human.builder().height(height).build())
}
而且我想保证确实存在一个特定身高的男人。
REPEATABLE_READ
可以保证吗?- 我的代码(伪代码)是否满足该条件?
理论上说,唯一能够绝对保证 re 的隔离级别。数据完整性(wrt 声明的规则)是可序列化的。
使用 REPEATABLE READ,从理论上讲,您仍然面临着两个事务试图插入同一行以及以下事件序列让其通过的风险:
T1 检查行是否存在,行不存在
T2 检查行是否存在,行不存在
T1 插入,可能重复行的存在检查(仍然不存在)
T2 插入,可能会重复该行的存在性检查(仍然 "not exist" 因为 T1 尚未提交,因此其新插入的数据对 T2 不可见)。
T1 提交
T2 提交
REPEATABLE READ,顾名思义,只提供关于 现有行 的保证(即 if 找到一行存在,它不会被其他事务更改,然后读取变为 "repeatable")。
是的,PostgreSQL SERIALIZABLE 应该防止创建多个具有相同高度的记录。它将中止 T1 或 T2。
我认为该异常正式称为反依赖循环 (G2)。这是一个good reference that includes major databases
此外,为什么不使用 unique constraint 呢?