mysql的乐观锁_Mysql 乐观锁

mysql的乐观锁_Mysql 乐观锁转载 http chenzhou iteye com blog 乐观锁介绍 乐观锁 OptimisticLo 相对悲观锁而言 乐观锁假设认为数据一般情况下不会造成冲突 所以在数据进行提交更新的时候 才会正式对数据的冲突与否进行检测 如果发现冲突了 则让返回用户错误的信息 让用户决定如何去做 那么我们如何实现乐观锁呢 一般来说有以下 2 种方式 1 使用数

转载:http://chenzhou.iteye.com/blog/

乐观锁介绍:

乐观锁( Optimistic Locking ) 相对悲观锁而言,乐观锁假设认为数据一般情况下不会造成冲突,所以在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,如果发现冲突了,则让返回用户错误的信息,让用户决定如何去做。那么我们如何实现乐观锁呢,一般来说有以下2种方式:

1.使用数据版本(Version)记录机制实现,这是乐观锁最常用的一种实现方式。何谓数据版本?即为数据增加一个版本标识,一般是通过为数据库表增加一个数字类型的 “version” 字段来实现。当读取数据时,将version字段的值一同读出,数据每更新一次,对此version值加一。当我们提交更新的时候,判断数据库表对应记录的当前版本信息与第一次取出来的version值进行比对,如果数据库表当前版本号与第一次取出来的version值相等,则予以更新,否则认为是过期数据。用下面的一张图来说明:

b50492e87f28692f6a1f8de6c241d376.png

如上图所示,如果更新操作顺序执行,则数据的版本(version)依次递增,不会产生冲突。但是如果发生有不同的业务操作对同一版本的数据进行修改,那么,先提交的操作(图中B)会把数据version更新为2,当A在B之后提交更新时发现数据的version已经被修改了,那么A的更新操作会失败。

2.乐观锁定的第二种实现方式和第一种差不多,同样是在需要乐观锁控制的table中增加一个字段,名称无所谓,字段类型使用时间戳(timestamp), 和上面的version类似,也是在更新提交的时候检查当前数据库中数据的时间戳和自己更新前取到的时间戳进行对比,如果一致则OK,否则就是版本冲突。

使用举例:以MySQL InnoDB为例

还是拿之前的实例来举:商品goods表中有一个字段status,status为1代表商品未被下单,status为2代表商品已经被下单,那么我们对某个商品下单时必须确保该商品status为1。假设商品的id为1。

下单操作包括3步骤:

// 1.查询出商品信息

select (status,status,version) from t_goods where id=#{id}

// 2.根据商品信息生成订单

// 3.修改商品status为2

update t_goods set status=2,version=version+1 where id=#{id} and version=#{version};

那么为了使用乐观锁,我们首先修改t_goods表,增加一个version字段,数据默认version值为1。

t_goods表初始数据如下:

mysql> select * from t_goods;

+—-+——–+——+———+

| id | status | name | version |

+—-+——–+——+———+

| 1 | 1 | 道具 | 1 |

| 2 | 2 | 装备 | 2 |

+—-+——–+——+———+

2 rows in set

mysql>

对于乐观锁的实现,我使用MyBatis来进行实践,具体如下:

Goods实体类:

/

* ClassName: Goods

* Function: 商品实体.

* date: 2013-5-8 上午09:16:19

* @author

*/

public class Goods implements Serializable {

/

* serialVersionUID:序列化ID.

*/

private static final long serialVersionUID = L;

/

* id:主键id.

*/

private int id;

/

* status:商品状态:1未下单、2已下单.

*/

private int status;

/

* name:商品名称.

*/

private String name;

/

* version:商品数据版本号.

*/

private int version;

@Override

public String toString() {

return “good id:”+id+”,goods status:”+status+”,goods name:”+name+”,goods version:”+version;

}

//setter and getter

}

GoodsDao:

/

* updateGoodsUseCAS:使用CAS(Compare and set)更新商品信息.

*

* @author

* @param goods 商品对象

* @return 影响的行数

*/

int updateGoodsUseCAS(Goods goods);

mapper.xml:

update t_goods

set status=#{status},name=#{name},version=version+1

where id=#{id} and version=#{version}

]]>

GoodsDaoTest测试类:

@Test

public void goodsDaoTest(){

int goodsId = 1;

// 根据相同的id查询出商品信息,赋给2个对象

Goods goods1 = this.goodsDao.getGoodsById(goodsId);

Goods goods2 = this.goodsDao.getGoodsById(goodsId);

// 打印当前商品信息

System.out.println(goods1);

System.out.println(goods2);

// 更新商品信息1

goods1.setStatus(2);//修改status为2

int updateResult1 = this.goodsDao.updateGoodsUseCAS(goods1);

System.out.println(“修改商品信息1″+(updateResult1==1?”成功”:”失败”));

// 更新商品信息2

goods1.setStatus(2);//修改status为2

int updateResult2 = this.goodsDao.updateGoodsUseCAS(goods1);

System.out.println(“修改商品信息2″+(updateResult2==1?”成功”:”失败”));

}

输出结果:

good id:1,goods status:1,goods name:道具,goods version:1

good id:1,goods status:1,goods name:道具,goods version:1

修改商品信息1成功

修改商品信息2失败

说明:

在GoodsDaoTest测试方法中,我们同时查出同一个版本的数据,赋给不同的goods对象,然后先修改good1对象然后执行更新操作,执行成功。然后我们修改goods2,执行更新操作时提示操作失败。此时t_goods表中数据如下:

mysql> select * from t_goods;

+—-+——–+——+———+

| id | status | name | version |

+—-+——–+——+———+

| 1 | 2 | 道具 | 2 |

| 2 | 2 | 装备 | 2 |

+—-+——–+——+———+

2 rows in set

mysql>

我们可以看到 id为1的数据version已经在第一次更新时修改为2了。所以我们更新good2时update where条件已经不匹配了,所以更新不会成功,具体sql如下:

update t_goods set status=2,version=version+1 where id=#{id} and version=#{version};

这样我们就实现了乐观锁。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/176878.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月26日 下午8:49
下一篇 2026年3月26日 下午8:49


相关推荐

  • 大话设计模式(五)观察者模式

    大话设计模式(五)观察者模式大话设计模式 五 观察者模式概念在阎宏博士的 JAVA 与模式 一书中开头是这样描述观察者 Observer 模式的 观察者模式是对象的行为模式 又叫发布 订阅 Publish Subscribe 模式 模型 视图 Model View 模式 源 监听器 Source Listener 模式或从属者 Dependents 模式 观察者模式定义了一种一对多的依赖关系 让多个观察者对象

    2026年3月19日
    2
  • java小型图书馆管理系统

    java小型图书馆管理系统根据需求,建立了一个BookMgr类,该类为实现小型图书馆的各个需求。为了和用户有一个良好的交互,根据需求且满足要求中的隐藏条件,先命名了交互的菜单函数printMenu1(),代码如下:publicvoidprintMenu1(){          System.out.println(“欢迎使用图书馆管理系统”);          Syst

    2022年7月8日
    24
  • 推理努力程度(Effort Level)​

    推理努力程度(Effort Level)​

    2026年3月18日
    2
  • 详解Vue slot插槽

    详解Vue slot插槽这篇文章主要为大家介绍了 Vue 的 slot 插槽 具有一定的参考价值 感兴趣的小伙伴们可以参考一下 希望能够给你带来帮助 1 作用 让父组件可以向子组件指定位置插入 html 结构 也是一种组件间通信的方式 适用于父组件 gt 子组件 传的是 HTML 格式 父组件 App 子组件 Category 在父组件或者子组件里都可以给插槽中的内容设置样式 效果一样作用域插槽 1 理解 数据在组件的自身 Category 但根据数据生成的结构需要组件的使用者 APP 来决定 games

    2026年2月22日
    1
  • SpringBoot整合TKmybatis

    SpringBoot整合TKmybatisSpringBoot 整合 TKmybatis 前言 最近公司在用 tkmybatis 于是乎去看了一下 挺好用的 所以在这里记录一下其用法 一什么是 TKmybatis 就我个人的理解而言 tkmybatis 就是一个框架或者说工具 其在 mybatis 的基础上进行了再次封装 使得我们可以不用写简单而重复的 CRUD 代码 又一次解放了生产力 如果涉及到多表查询 需要自己写 sql 哦 因为 tkmybat

    2026年3月16日
    2
  • Java单例模式实现方式

    Java单例模式实现方式懒汉式-非线程安全publicclassLazyNoSafe{privatestaticLazyNoSafeinstance;publicstaticLazyNoSafegetInstance(){if(instance==null){instance=newLazyNoSafe();…

    2022年7月25日
    8

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号