1、乐观锁与悲观锁
1.1 乐观锁
乐观锁指:在当前线程/操作数据的过程中,其它线程/操作不会修改数据,不会引起数据冲突、仅在数据提交的时候对数据进行检测
适用场景:适合读取大于写入
实现方式:
- 1、使用
version
方式 - 2、使用
timestamp (时间戳 )
方式
- 1、使用
实现方式:
- 查询数据的时候,将
version/timestamp
查询出来, - 修改数据的时候,将
version/timestamp
的值作为更新条件,并且增加version
或 更新timestamp
- 如果操作成功,则表明数据在此次操作中,没发生冲突
- 如果操作失败,则表示数据在此次操作中,发生冲突
- 查询数据的时候,将
例如:
begin; select * from goods where id=1; //根据库存,创建订单 insert into orders (good_id,num) values (xx,1); //更新产品存库 update goods set stock=stock-1,version=version+1 where id=1 and version=`old_version_value` commit/rollback;
1.2 悲观锁
- 悲观锁指:在当前线程/操作处理数据的过程中,其它线程/操作会修改数据,引起数据冲突、所以需要对数据进行锁定,防止其它操作修改数据
- mysql 自己已实现悲观锁
- 使用之前请使用
set autocommit=0
关闭自动提交,并在transaction(事务)
中使用 - 分为
共享/读锁
、排他/写锁
- 默认的
DDL(insert/update/delete)
会使用排他/写锁
- 适用场景:适合写入大于读取
1.2.1 共享/读锁
多个线程可同时对数据加上
共享/读锁
使用
select .... lock in share mode
进行锁定锁定成功之后,其它线程/操作能同时对数据进行
共享/读锁
锁定,但不能进行排他/写锁
例如:
set autocommit=0; begin; select * from goods where id=1 lock in share mode; commit/rollback;
1.2.2 排他/写锁
同一时刻仅一个线程/操作能对数据加上
排他/写锁
使用
select .... for update
进行锁定锁定成功之后,其它线程/操作对数据进行
共享/读锁
、排他/写锁
时将阻塞获取之后,可以对数据进行写入/修改
例如:用户下单,修正库存
begin; select * from goods where id=xx for update; //根据库存,创建订单 insert into orders (good_id,num) values (xx,1); //更新产品存库 update goods set stock=stock-1 where id=1; commit/rollback;
1.3 总结
insert/update/delete
将对数据进行排他/写锁
select
语句默认不会对数据进行锁定- 要记住锁机制一定要在事务中才能生效,事务也就要基于MySQL InnoDB 引擎。
- 访问量不大,不会造成压力时使用悲观锁,面对高并发的情况下,我们应该使用乐观锁。
- 读取频繁时使用乐观锁,写入频繁时则使用悲观锁。
- 乐观锁不能解决脏读的问题。
2、行锁与表锁
2.1 行锁
- 仅
innodb
支持行锁,myisam
不支持行锁 - 行锁基于
索引
,如果 SQL 锁定语句应用不到索引,不会使用行锁,将使用表锁
2.2 表锁
innodb/myisam
都支持表锁- 在
innodb
中,如果 SQL 锁定语句应用到索引,使用行锁
,否则使用表锁
myisam
中使用 sql 锁定语句对数据进行锁定时,全部使用表锁