【问题标题】:Hibernate optimistic locking different behavior between Postgres and MariaDb休眠乐观锁定 Postgres 和 MariaDb 之间的不同行为
【发布时间】:2018-10-19 12:03:06
【问题描述】:

我刚刚发现,当我对 Postgresql 或 MariaDB 数据库使用乐观锁定时,我的应用程序的行为会有所不同,我想知道是否有人可以解释会发生什么以及如何使应用程序以与 MariaDB 相同的方式工作?我使用带有 InnoDB 引擎和默认设置的 Postgresl 10.5 和 MariaDB 10.3.10。我使用 Spring 框架版本 5.1.0 和 Hibernate 5.3.6。

所以我的代码如下所示:

@Entity
@Getter
@Setter
@NoArgsConstructor
public class Bla {

    @Id
    @GeneratedValue
    private long id;

    @Version
    private long version;

    private int counter;
}

我也有这个实体的存储库和以下服务方法:

@Transactional
public int increment(long id) {
    Bla bla = blaRepo.getOne(id);
    bla.setCounter(bla.getCounter() + 1);
    return bla.getCounter();
}

如果我在多个线程上调用此方法,我希望如果它们触及具有相同版本的实体,更新只会对其中一个成功。例如:如果我在一次运行中使用 Postgres db 启动 50 个线程,我会得到 3 个成功的调用并返回值 1、2、3,而其他 47 个调用失败并出现 ObjectOptimisticLockingFailureException,这是预期的行为 - 这就是我想要的要表现的应用程序。

但是,如果我切换到 MariaDB,则不会发生这种情况。所有 50 个线程都成功完成,并且我在多个线程中得到相同的响应值,就好像没有乐观锁一样。例如现在前 5 个线程返回 1,然后其中 20 个返回 2,其余 3 或 4 个。

为什么会这样?这没有任何意义 - 对于两个数据库,生成的查询都是

update bla set counter=?, version=? where id=? and version=?

但在 Postgresql 中会正确失败,而在 MariaDB 中会意外成功。

【问题讨论】:

  • 你在使用 MyISAM 吗?
  • @LaurenzAlbe 不,我使用 InnoDb 作为 MariaDB 的引擎。

标签: postgresql hibernate jpa mariadb optimistic-locking


【解决方案1】:

可能发生的唯一方法是 MariaDB 有一个错误,因为一旦 Tx 修改了一条记录,它就会锁定它,直到它提交或回滚。其他 Tx 会因锁而阻塞 UPDATE,但必须在锁释放后重新评估条件。

尝试切换到 READ_COMMITTED,看看它是否能解决问题。这可能是 REPEATABLE_READ 异常。

【讨论】:

  • 感谢您的评论弗拉德。我发现了问题 - 我想我会把它作为问题的答案发布,这样我就可以提供更多细节。这似乎确实是某个地方的错误,但我不知道是在 Hibernate 中还是在 MariaDB jdbc 连接器中。
  • 如果它是 Hibernate 中的一个错误,你会为 PostgreSQL 复制它。很可能与 MariaDB 相关。确保驱动程序与服务器版本兼容。
  • 是的,我认为你是对的。我刚刚添加了我的答案 - 它是关于 batch_size 的。非常感谢您的暗示。
【解决方案2】:

我找到了解决这个问题的方法。

看来我在 application.properties 中设置了这个属性:

spring.jpa.properties.hibernate.jdbc.batch_size = 50

当我使用 Postgresql 时,我得到以下带有两个线程的调试跟踪:

13223 [pool-2-thread-2] DEBUG org.hibernate.SQL - update bla set counter=?, version=? where id=? and version=?
13223 [pool-2-thread-1] DEBUG org.hibernate.SQL - update bla set counter=?, version=? where id=? and version=? 
13226 [pool-1-thread-1] DEBUG org.hibernate.engine.jdbc.batch.internal.BatchingBatch - Executing batch size: 1
13226 [pool-1-thread-2] DEBUG org.hibernate.engine.jdbc.batch.internal.BatchingBatch - Executing batch size: 1
13230 [pool-1-thread-1] ERROR org.hibernate.engine.jdbc.batch.internal.BatchingBatch - HHH000315: Exception executing batch [org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1], SQL: update bla set counter=?, version=? where id=? and version=?

然后使用相同批量大小为 50 的 MariaDB:

21978 [pool-2-thread-2] DEBUG org.hibernate.SQL - update bla set counter=?, version=? where id=? and version=?
21978 [pool-2-thread-1] DEBUG org.hibernate.SQL - update bla set counter=?, version=? where id=? and version=? 
21979 [pool-2-thread-2] DEBUG org.hibernate.engine.jdbc.batch.internal.BatchingBatch - Executing batch size: 1
21979 [pool-2-thread-1] DEBUG org.hibernate.engine.jdbc.batch.internal.BatchingBatch - Executing batch size: 1
21980 [pool-2-thread-2] DEBUG org.hibernate.jdbc.Expectations - Success of batch update unknown: 0
21980 [pool-2-thread-1] DEBUG org.hibernate.jdbc.Expectations - Success of batch update unknown: 0

然后使用批量大小为 1 的 MariaDB:

12994 [pool-2-thread-2] DEBUG org.hibernate.SQL - update bla set counter=?, version=? where id=? and version=?
12994 [pool-2-thread-1] DEBUG org.hibernate.SQL - update bla set counter=?, version=? where id=? and version=?
12997 [pool-2-thread-1] DEBUG org.hibernate.cache.internal.TimestampsCacheEnabledImpl - Invalidating space [bla], timestamp: 6307671153053696
12998 [pool-2-thread-2] DEBUG org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl - JDBC transaction marked for rollback-only (exception provided for stack trace)

现在确实应用程序抛出了预期的 ObjectOptimisticLockingFailureException

但不幸的是,这意味着使用 MariaDb 对实体进行乐观锁定以及任何大于 1 的批量大小都是不兼容的。

【讨论】:

  • 这听起来像是 MariaDB 驱动程序中的错误。您应该为此打开错误报告。
  • 这个问题似乎在最新版本(2.3.0)中得到了修复! jira.mariadb.org/browse/CONJ-642
猜你喜欢
  • 2021-09-27
  • 2017-02-06
  • 2011-10-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-14
  • 2011-03-21
  • 1970-01-01
相关资源
最近更新 更多