我读了一些关于 hibernate 版本控制的文章: https://docs.jboss.org/hibernate/stable/core.old/reference/en/html/transactions-optimistic.html https://vladmihalcea.com/jpa-entity-version-property-hibernate/
并提出新的问题。
例如:
class Test {
String name;
int version;
}
对于这个测试类,关于更新操作。要检查版本,我可以遵循不同的策略:
第一个是我可以手动检查版本。
update(Test request) {
Test exist = repository.find(...);
if (exist.version != request.version) throw Exception();
...
}
第二个是我可以直接将版本发送到数据库,乐观锁会处理它。
update(Test request) {
Test exist = repository.find(...);
exist.setName(request.name);
exist.setVersion(request.version);
repository.update(exist);
}
如果版本不匹配,则会抛出
optimistic-lock-exception
。
当我认为这种情况时,第一个选项看起来很高效,因为在
db-call
之前检测到问题,但还有额外的 if-control
。当我想到一个应用程序时,如果有 1M
请求,乐观锁问题可能是 ~%1
请求,因此性能差异可能会被忽略。
你的建议是什么?您更喜欢哪一种或者您在职业生活中使用哪一种?
在这里评估了不同的解决方案。 https://gist.github.com/senolatac/89a983052368859a5447bb9dd412d4c6
让我们在示例查询中查看它。
Hibernate uses the version property in the WHERE clause of the executing UPDATE statement:
UPDATE
test
SET
name = :newName,
version = :existVersion + 1
WHERE
id = :id AND version = :existVersion
因此,如果
version = :existVersion
不匹配,则会抛出 StaleStateExcetion
,当使用 JPA 引导 Hibernate 时,它将被包装在 JPA OptimisticLockException
中。
让我们考虑一下我们有一个这样的实体:
class Test {
Long id;
String name;
int version;
}
对于这个
Test
类,关于更新操作。要检查版本,我们可以遵循不同的策略:
update(Test request) {
Test exist = repository.findById(request.id);
if (exist.version != request.version) throw Exception();
...
}
Pros
由于没有额外的数据库调用,它看起来很高性能Cons
但是额外的business-check
和额外的if-check
update(Test request) {
Test exist = repository.findById(request.id);
exist.setName(request.name);
exist.setVersion(request.version);
repository.update(exist);
}
Pros
看起来很清晰Pros
没有商业方面。一切都由 db 处理。Cons
但需要额外的数据库调用 optimitic-lock-case
Pros
但是我们可以忽略extra db-call
,因为当我们思考一个应用程序时,如果有1M
请求,乐观锁问题可能是~%1
的请求。UUID
格式的版本字段,因此在这种情况下我们无法从 hibernate @Version
中受益,因为 hibernate 仅支持 int
和 timestamp
版本字段。update(Test request) {
Test exist = repository.findById(request.id);
if (exist.version != request.version) throw Exception();
exist.setVersion(new UUID...);
repository.customUpdate(exist, request.version);
...
}
Cons
每个实体的自定义更新查询。和手动版本控制。Pros
它是安全的,但我们真的需要这种安全吗?看起来像是过度设计了。UUID
和休眠版本中有一个安全密钥字段,但请求/响应不知道版本。update(Test request) {
Test exist = repository.findById(request.id);
if (exist.secureKey != request.secureKey) throw Exception();
exist.setSecureKey(new UUID...);
repository.update(exist);
...
}
Cons
但是额外的business-check
和额外的if-check
Pros
它是安全的,但我们真的需要这种安全吗?看起来像是过度设计了。2.
一种。