Hibernate乐观锁引发的StaleObjectStateException分析

本文通过一个实例分析了在使用Hibernate乐观锁时遇到的StaleObjectStateException问题,解释了该异常产生的原因并提出了解决方案。文章详细探讨了乐观锁的工作原理,事务传播行为如何影响乐观锁的执行,并给出了代码示例及配置调整建议。
摘要由CSDN通过智能技术生成

前言
最近一个项目中使用了Hibernate的乐观锁,不巧的是出现了乐观锁最容易报的错:org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction
下面将通过一个模拟的实例重现问题,并做相应的分析。

乐观锁的作用
乐观锁的主要作用是为了解决事务并发带来的问题,相对于悲观锁而言,乐观锁机制采取了更加宽松的加锁机制;
悲观锁大多数情况下依靠数据库的锁机制实现,以保证操作最大程度的独占性,但随之而来的就是数据库性能的大量开销,特别是对长事务而言;
乐观锁机制在一定程度上解决了这个问题;乐观锁,大多是基于数据版本(Version)记录机制实现;

乐观锁原理:读取出数据时,将此版本号一同读出,之后更新时,对此版本号加一;
此时,将提交数据的版本数据与数据库表对应记录的当前版本信息进行比对,如果提交的数据版本号大于数据库表当前版本号,则予以更新,否则认为是过期数据;
当出现version过期时,会抛出如下错误:

public StaleObjectStateException(String persistentClass, Serializable identifier) {
    super("Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect)");
    this.entityName = persistentClass;
    this.identifier = identifier;
}

本地重现
1.MYSQL建表SQL如下

CREATE TABLE `test_bean` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `version` int(11) NOT NULL,
  `status` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
 
INSERT INTO `test_bean` VALUES ('1', '1', '1');

其中的version字段,就是用来做乐观锁处理的

2.实体TestBean以及TestBean.hbm.xml

public class TestBean {
 
    private long id;
    private int version;
    private int status;
}

TestBean.hbm.xml如下:

<hibernate-mapping package="zh.maven.hibernate_version">
    <class name="TestBean" table="test_bean" optimistic-lock="version">
        <id name="id" column="id">
            <generator class="native" />
        </id>
        <version name="version" column="version" type="integer"></version>
        <property name="status" />
    </class>
</hibernate-mapping>

3.主要代码
其中包括FirstService调用SecondService实现查询和更新,SecondService调用SecondDao实现查询和更新,代码如下:

public class FirstService {
 
    private SecondService secondService;
 
    public void modifyProcess() {
        TestBean testBean = secondService.get(1L);
        printLog(testBean);
        testBean.setStatus(4);
        secondService.update(testBean);
        printLog(testBean);
        sendNotify(testBean);
    }
 
    private void sendNotify(TestBean testBean) {
        testBean.setStatus(20);
        secondService.update(testBean);
        printLog(testBean);
    }
    ......
}
public class SecondService {
 
    private SecondDao secondDao;
 
    public TestBean get(long id) {
        return s
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值