乐观锁介绍:

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

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

如上图所示,如果更新操作顺序执行,则数据的版本(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 <br/>
* Function: 商品实体. <br/>
* date: 2013-5-8 上午09:16:19 <br/>
* @author chenzhou1025@126.com
*/
public class Goods implements Serializable { /**
* serialVersionUID:序列化ID.
*/
private static final long serialVersionUID = 6803791908148880587L; /**
* 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)更新商品信息. <br/>
*
* @author chenzhou1025@126.com
* @param goods 商品对象
* @return 影响的行数
*/
int updateGoodsUseCAS(Goods goods);

mapper.xml

<update id="updateGoodsUseCAS" parameterType="Goods">
<![CDATA[
update t_goods
set status=#{status},name=#{name},version=version+1
where id=#{id} and version=#{version}
]]>
</update>

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};

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

mysql乐观锁总结和实践的更多相关文章

  1. mysql乐观锁总结和实践(转)

    原文:mysql乐观锁总结和实践 上一篇文章<MySQL悲观锁总结和实践>谈到了MySQL悲观锁,但是悲观锁并不是适用于任何场景,它也有它存在的一些不足,因为悲观锁大多数情况下依靠数据库的 ...

  2. mysql乐观锁总结和实践--转

    原文地址:http://chenzhou123520.iteye.com/blog/1863407 上一篇文章<MySQL悲观锁总结和实践>谈到了MySQL悲观锁,但是悲观锁并不是适用于任 ...

  3. mysql乐观锁总结和实践(二)

    一篇文章<MySQL悲观锁总结和实践>谈到了MySQL悲观锁,但是悲观锁并不是适用于任何场景,它也有它存在的一些不足,因为悲观锁大多数情况下依靠数据库的锁机制实现,以保证操作最大程度的独占 ...

  4. 【Mysql】mysql乐观锁总结和实践

    乐观锁介绍: 乐观锁( Optimistic Locking ) 相对悲观锁而言,乐观锁假设认为数据一般情况下不会造成冲突,所以在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,如果发现冲突 ...

  5. mysql乐观锁总结和实践(转载)

    原文地址:http://chenzhou123520.iteye.com/blog/1863407 乐观锁介绍: 乐观锁( Optimistic Locking ) 相对悲观锁而言,乐观锁假设认为数据 ...

  6. mysql乐观锁总结和实践(一)

    最近学习了一下数据库的悲观锁和乐观锁,根据自己的理解和网上参考资料总结如下: 悲观锁介绍(百科): 悲观锁,正如其名,它指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持 ...

  7. 《MySQL悲观锁总结和实践》乐观锁

    mysql乐观锁总结和实践 博客分类: MyBatis 数据库 mysql数据库乐观锁悲观锁 上一篇文章<MySQL悲观锁总结和实践>谈到了MySQL悲观锁,但是悲观锁并不是适用于任何场景 ...

  8. 【转】MySQL乐观锁在分布式场景下的实践

    背景 在电商购物的场景下,当我们点击购物时,后端服务就会对相应的商品进行减库存操作.在单实例部署的情况,我们可以简单地使用JVM提供的锁机制对减库存操作进行加锁,防止多个用户同时点击购买后导致的库存不 ...

  9. MySQL乐观锁在分布式场景下的实践

    背景 在电商购物的场景下,当我们点击购物时,后端服务就会对相应的商品进行减库存操作.在单实例部署的情况,我们可以简单地使用JVM提供的锁机制对减库存操作进行加锁,防止多个用户同时点击购买后导致的库存不 ...

随机推荐

  1. 第五章 --- 关于Javascript 设计模式 之 发布-订阅模式

    先来个最简单的 发布订阅模式 document.body.addEventListener('click',function(){ alert(123); }); document.body.clic ...

  2. 关于MapReduce中自定义分区类(四)

    MapTask类 在MapTask类中找到run函数 if(useNewApi){       runNewMapper(job, splitMetaInfo, umbilical, reporter ...

  3. (转)EasyUI-datagrid-自动合并单元格

    1.目标 1.1表格初始化完成后,已经自动合并好需要合并的行: 1.2当点击字段排序后,重新进行合并: 2.实现 2.1 引入插件 /** * author ____′↘夏悸 * create dat ...

  4. 【UWP】解析GB2312、GBK编码网页乱码问题

    在WebHttpRequest请求网页后,获取到的中文是乱码,类似这样: <title>˹ŵ��Ϸ���������� - ��̳������ -  ˹ŵ��Ϸ����</title ...

  5. MySQL收藏

    MySQL手册:5.5手册 .5.6手册 cd /usr/local/mysql/bin mysql -uroot -p show processlist;   // 显示系统中正在运行的所有进程 M ...

  6. JS学习:第二周——NO.1回调函数

    [回调函数] 定义:把一个函数的定义阶段,作为参数,传给另一个函数: 回调函数调用次数,取决于条件: 回调函数可以传参: 回调函数可以给变this指向,默认是window: 回调函数没有返回值,for ...

  7. VMware ubuntu中执行python文件的操作小结

  8. CAIN怎么嗅探路由密码

    Cain & Abel 是由Oxid.it开发的一个针对Microsoft操作系统的免费口令恢复工具.号称穷人使用的L0phtcrack.它的功能十分强大,可以网络嗅探,网络欺骗,破解加密口令 ...

  9. git+github上传与管理

    1.首先下载并安装git,方便管理github上的代码 https://git-scm.com/downloads 2.然后点击安装好的git bash(注册好自己的github) git confi ...

  10. 如何将Sphinx生成的html文档集成进入Django

    参考 http://stackoverflow.com/questions/10594618/django-and-sphinx-how-to-view-the-html-sphinx-generat ...