乐观锁
假设: 认为数据一般情况下不会造成冲突
在数据进行提交更新的时候才会正式对数据的冲突与否进行检测,如果发现冲突了,则让返回用户错误的信息,让用户决定如何去做
实现方法
使用数据版本(Version)记录机制实现
这是乐观锁最常用的一种实现方式。为数据增加一个版本标识,一般是通过为数据库表增加一个数字类型的 “version” 字段来实现。
当读取数据时,将version字段的值一同读出,数据每更新一次,对此version值加1。当我们提交更新的时候,判断数据库表对应记录的当前版本信息与第一次取出来的version值进行比对,如果数据库表当前版本号与第一次取出来的version值相等,则予以更新,否则认为是过期数据。使用时间戳(timestamp)
和上面的version类似,也是在更新提交的时候检查当前数据库中数据的时间戳和自己更新前取到的时间戳进行对比,如果一致则OK,否则就是版本冲突。
实现举例
表结构
+----+--------+------+---------+
| id | status | name | version |
+----+--------+------+---------+
| 1 | 1 | 道具 | 1 |
| 2 | 2 | 装备 | 2 |
+----+--------+------+---------+
下单操作包括3步骤:
- 查询出商品信息
select (status,status,version) from t_goods where id=#{id}
- 根据商品信息生成订单
- 修改商品status为2
update t_goods
set status=2,version=version+1
where id=#{id} and version=#{version};
悲观锁
锁住读取的记录,防止其它事务读取和更新这些记录。其它事务会一直阻塞,直到这个事务结束。
要使用悲观锁,我们必须关闭mysql数据库的自动提交属性,我们可以使用命令设置MySQL为非autocommit模式:
set autocommit=0;
设置完autocommit后,我们就可以执行我们的正常业务了。具体如下:
//0.开始事务
begin;/begin work;/start transaction; (三者选一就可以)
//1.查询出商品信息
select status from t_goods where id=1 for update;
//2.根据商品信息生成订单
insert into t_orders (id,goods_id) values (null,1);
//3.修改商品status为2
update t_goods set status=2;
//4.提交事务
commit;/commit work;