乐观锁介绍:
乐观锁( 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表初始数据如下:
Sql代码
- mysql> select * from t_goods;
- +—-+——–+——+———+
- | id | status | name | version |
- +—-+——–+——+———+
- | 1 | 1 | 道具 | 1 |
- | 2 | 2 | 装备 | 2 |
- +—-+——–+——+———+
- 2 rows in set
- mysql>
于乐观锁的贯彻,我使用MyBatis来展开实践,具体如下:
Goods实体类:
Java代码
- /**
- * 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
Java代码
- /**
- * updateGoodsUseCAS:使用CAS(Compare and set)更新商品信息. <br/>
- *
- * @author chenzhou1025@126.com
- * @param goods 商品对象
- * @return 影响之行数
- */
- int updateGoodsUseCAS(Goods goods);
mapper.xml
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测试类
Java代码
- @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?”成功”:”失败”));
- }
输出结果:
Shell代码
- 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表中多少如下:
Sql代码
- 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如下:
Sql代码
- update t_goods
- set status=2,version=version+1
- where id=#{id} and version=#{version};
然我们不怕兑现了乐观锁
转自:http://chenzhou123520.iteye.com/blog/1863407