告别数据冲突:Hibernate事务隔离设置,让你的并发新增更加稳健Hibernate事务隔离有问题?并发场景下的新增数
哈喽,大家好,我是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