likes
comments
collection
share

告别数据冲突:Hibernate事务隔离设置,让你的并发新增更加稳健Hibernate事务隔离有问题?并发场景下的新增数

作者站长头像
站长
· 阅读数 32

哈喽,大家好,我是Xwaiy!

最近在使用Hibernate进行开发时,事务隔离方面的问题着实让我困扰了好些天。今天,就来和大家深入探讨一下这个问题。

一、并发场景下加载方法存在的问题

这个加载方法的逻辑比较简单:进入方法后,首先会查询数据,如果查询到数据存在,那就直接返回该数据;要是没有查询到数据,就执行新增数据的操作,然后返回新增后的数据。

但在并发场景下,就出现了棘手的问题,即数据会被重复新增。我尝试通过加锁来解决这个问题,可结果却不尽人意,加锁并没有起到作用。

经过仔细排查后发现,原来是事务隔离在作祟。具体的情况是这样的,当一个事务提交之后,同时创建的其他事务却不能查询到这个已经提交事务的数据,这就导致了数据新增逻辑变得混乱。

二、代码实例

public MyTask loadTask(MyTask taskInfo) throws Exception {
    String taskId = taskInfo.getTaskId();
    MyTask existingTask = getOnly(taskId);
    if (existingTask!= null) {
        return existingTask;
    }
    synchronized (taskId.intern()) {
        existingTask = getOnly(taskId);
        if (existingTask!= null) {
            return existingTask;
        }
        add(taskInfo);
        existingTask = getOnly(taskId);
    }
    return existingTask;
}

从代码能看出,虽有逻辑判断和加锁操作,但仍受事务隔离影响。

三、查询默认配置

数据库的版本不同,查询默认事务隔离配置的方式也有所差异。下面为大家介绍不同版本数据库的查询方式。

低版本数据库查询

对于低版本数据库,可使用以下SQL语句来查询默认事务隔离配置:

SHOW VARIABLES LIKE 'tx_isolation';

高版本数据库查询

而高版本数据库则需使用下面的SQL语句进行查询:

SHOW VARIABLES LIKE 'transaction_isolation';

四、Spring配置事务隔离

Spring集成Hibernate时,可在applicationContext.xml配置事务隔离。

<tx:advice id="userTxAdvice" transaction - manager="transactionManager">
    <tx:attributes>
        <tx:method name="add*" propagation="REQUIRED" read - only="false" isolation="READ_COMMITTED" rollback - for="Exception"/>
        <tx:method name="load*" propagation="REQUIRED" read - only="false" isolation="READ_COMMITTED" rollback - for="Exception"/>
        <tx:method name="get*" propagation="REQUIRED" read - only="true"/>
        <tx:method name="*" propagation="SUPPORTS" read - only="true"/>
    </tx:attributes>
</tx:advice>

isolation属性具有多种取值,各取值有着不同的特性。

默认值

DEFAULT:此为默认取值,表示遵循数据库自身默认的隔离方式。若未做特殊配置,就会采用该默认值。

最低级别

READ_UNCOMMITTED:这是事务隔离的最低级别。其并发性能高,允许多个事务同时操作数据。不过,这也带来了诸多风险,如可能出现脏读不可重复读以及幻读等问题。鉴于这些潜在隐患,在实际应用中需谨慎选用

多数默认

READ_COMMITTED:多数数据库默认采用这一事务隔离级别。它的优点在于能够防止脏读情况的发生,从而保障数据的基本准确性。然而,它也并非毫无瑕疵,不可重复读和幻读问题仍有可能出现。由于它在数据准确性与并发性能之间达到了较好的平衡,所以是较为推荐的取值。

部分问题避免

REPEATABLE_READ:该隔离级别可避免脏读和不可重复读这两种问题,这有助于提高数据的一致性。但它仍然存在一定局限性,幻读问题仍可能发生

最高级别

SERIALIZABLE:作为最高的事务隔离级别,SERIALIZABLE能够杜绝脏读、不可重复读和幻读等所有问题,有力地确保了数据的完整性。但这种高数据完整性是以牺牲并发性为代价的,在该级别下并发性极低,多个事务只能依次执行,这可能会对系统的整体效率产生影响。

五、并发测试结果

在针对并发事务并运用synchronized加锁的情形下,最后的测试结果:

REPEATABLE_READ

isolation取值为REPEATABLE_READ时,后面的事务无法查询到前面事务插入的结果。

这一结果表明,在该隔离级别下,即便使用了加锁机制,事务间的数据可见性仍然受限。这可能会对某些需要及时获取最新插入数据的业务逻辑产生影响,因为在这种情况下,后面的事务无法感知到前面事务对数据的新增操作。

READ_COMMITTED

isolation取值为READ_COMMITTED时,后面的事务能够查询到前面事务插入的结果。这意味着在此隔离级别下,事务之间的数据共享机制相对更有利于业务逻辑的正常开展。在并发环境中,不同事务能够较好地获取到及时且准确的数据,从而保障业务流程的顺利进行。

事务隔离级别在并发操作中很重要,合理设置可避免数据不一致问题。希望这篇文章能帮助大家更好理解和处理Hibernate事务隔离相关问题。如果有相关经验或问题,欢迎在评论区留言分享。

转载自:https://juejin.cn/post/7416247734552805391
评论
请登录