mysql的锁机制

137 阅读4分钟

1.为什么要加锁

当多个用户并发执行存取数据时,若对并发操作不加控制,导致数据读取和存储不正确,会破坏数据库的一致性

2.锁的分类

按粒度划分:行锁、表锁、页面锁

按使用方式划分:共享锁、排他锁

思想上划分:乐观锁、悲观锁

1)行级锁

针对当前操作的行进行加锁,能大大减少数据库操作的冲突,锁粒度最小,但加锁的开销最大,分为共享锁和排他锁,并发度最高,会出现死锁

共享锁:用法 SELECT ...LOCK IN SHARE MODE;

排他锁:用法 SELECT ...FOR UPDATE;

2)表锁

对整张表进行加锁,实现简单,myisam和innode都支持表级锁,分为共享锁和排他锁。锁粒度最大,开销小,并发度最小,不会出现死锁

3)页锁

介于行锁和表锁之间,BDB支持页级锁,并发度一般,会出现死锁

3.mysql常用存储引擎的锁机制

Myisam和momory采用表级锁

innode支持行级锁和表级锁,默认为行级锁

innode行锁是给索引上的索引项加锁来实现的

bdb采用页面锁或表级锁,默认为页面锁

4.行锁算法

5.乐观锁:

***是什么 ***假设认为数据一般情况下不会造成冲突,所以在数据进行提交更新时,才会对数据的冲突与否进行检测,如果发现冲突了,则返回用户错误信息,让用户决定如何去做

在对数据库进行处理的时候,乐观锁不会使用数据库提供的锁机制,一般的实现乐观锁的方式就是记录数据版本

数据版本,为数据增加的一个版本标识,当读取数据时,将版本标识的值一同读出,数据每更新一次,同时对版本标识进行更新。当我们提交更新的时候,判断数据库表对应记录的当前版本信息与第一次取出来的版本标识进行比对,如果数据库表当前版本号与第一次取出来的版本标识值相等,则予以更新,否则认为时过期数据

***实现 ***
***1)使用版本号实现乐观锁时,***可以在数据初始化时指定一个版本号,每次对数据的更新操作都对版本号执行+1操作。并判断当前版本号是不是该数据的最新版本号

1.查询商品信息
select (status, version) from t_goods where id=1;
2.根据商品信息生成订单
3.修改商品的status为2
update t_goods set status=2,version=version+1 where id=1 and version=1;

***2)使用条件控制实现乐观锁,***适合库存模型

***乐观锁的优缺点: ***乐观锁的更新操作,最好用主键或者唯一索引来更新,这样是行锁,否则更新时会锁表

6.悲观锁:

***是什么 ***在整个数据处理过程中,将数据处于锁定状态,悲观锁的实现往往依靠数据库提供的锁机制,

悲观锁的流程 1)在对任意记录进行修改前,先尝试为该记录加上排他锁 2)如果加锁失败,说明该该记录正在被修改,当前查询可能要等待或者抛出异常,具体由开发者决定 3)如果加锁成功,就可以对记录做修改,事务完成后就会解锁 4)期间如果由其它对该记录做修改或者加排他锁的操作,都会等待我们解锁或者直接抛出异常

mysql innode中使用悲观锁

必须关闭mysql数据库的自动提交属性,set autocommit=0;

begin;
1.查询出商品信息
select status from t_goods where id=1 for update;
2.根据商品信息生成订单
insert into t_order (id,goods_id) value (null, 1);
3.修改商品status=2
update t_goods set status=2 where goods_id=1;
commit;

select ...for update开启排他锁的方式实现了悲观锁,t_goods表中,id为1的数据被我们锁定了,其它事务必须等本次事务提交之后才能执行