更新操作时的 Hibernate 版本检查

问题描述 投票:0回答:1

我读了一些关于 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
请求,因此性能差异可能会被忽略。

你的建议是什么?您更喜欢哪一种或者您在职业生活中使用哪一种?

hibernate
1个回答
0
投票

在这里评估了不同的解决方案。 https://gist.github.com/senolatac/89a983052368859a5447bb9dd412d4c6

Hibernate 如何处理乐观锁?

让我们在示例查询中查看它。

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
类,关于更新操作。要检查版本,我们可以遵循不同的策略:

  1. 我们可以手动检查版本:
update(Test request) {
   Test exist = repository.findById(request.id);
   if (exist.version != request.version) throw Exception();
   ...
}
  • Pros
    由于没有额外的数据库调用,它看起来很高性能
  • Cons
    但是额外的
    business-check
    和额外的
    if-check
  1. 我们可以直接将版本发送到数据库,乐观锁会处理它。
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
    的请求。
  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
    它是安全的,但我们真的需要这种安全吗?看起来像是过度设计了。
  1. 安全密钥和版本 假设,我们在
    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.
    一种。

参考文献

© www.soinside.com 2019 - 2024. All rights reserved.