1、为什么需要锁
到淘宝上买一件商品,商品只有一件库存,这个时候如果还有另一个人买,那么如何解决是你买到还是另一个人买到的问题?
2、锁的概念
1、锁是计算机协调多个进程或线程并发访问某一资源的机制。
2、在数据库中,数据也是一种供许多用户共享的资源。如何保证数据并发访问的一致性、有效性是所有数据库必须解决的一个问题,锁冲突也是影响数据库并发访问性能的一个重要因素。
3、 锁对数据库而言显得尤其重要,也更加复杂。
3、MySQL中的锁
- 按操作划分:DML锁,DDL锁
- 按锁的粒度划分:表级锁、行级锁、页级锁
- 按锁级别划分:共享锁、排他锁
- 按加锁方式划分:自动锁、显示锁
- 按使用方式划分:乐观锁、悲观锁
3.1、表级锁
特点:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。
使用场景:表级锁更适合于以查询为主,只有少量按索引条件更新数据的应用
3.2、行级锁
特点:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。
使用场景:行级锁则更适合于有大量按索引条件并发更新少量不同数据,同时又有并发查询的应用
3.3、页级锁(间隙锁)
特点:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般。
3.4、排它锁
- 排它锁又叫写锁,如果事务T对A加上排它锁,则其它事务都不能对A加任何类型的锁。获准排它锁的事务既能读数据,又能写数据。
- 用法 : SELECT … FOR UPDATE
3.5、悲观锁
悲观锁(Pessimistic Locking),悲观锁是指在数据处理过程,使数据处于锁定状态,一般使用数据库的锁机制实现。
例:
- 每次获取商品时,不对该商品加锁。
- 在更新数据的时候需要比较程序中的库存量与数据库中的库存量是否相等,如果相等则进行更新
- 反之程序重新获取库存量,再次进行比较,直到两个库存量的数值相等才进行数据更新。
# 乐观锁实现加一操作代码
# 我们可以看到,只有当对数量-1操作时才会加锁,只有当程序中值和数据库中的值相等时才正真执行。
# 不加锁
select id,name,stock where id=1;
# 业务处理
begin;
update shop set stock=stock-1 where id=1 and stock=stock;
commit;
3.6、乐观锁
乐观锁相对悲观锁而言,它认为数据一般情况下不会造成冲突,所以在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,如果发现冲突了,则让返回错误信息,让用户决定如何去做
例:
- 每次获取商品时,对该商品加排他锁。
- 也就是在用户A获取获取 id=1 的商品信息时对该行记录加锁,期间其他用户阻塞等待访问该记录
# 悲观锁实现加一操作代码
# 我们可以看到,首先通过begin开启一个事物,在获得shop信息和修改数据的整个过程中都对数据加锁,保证了数据的一致性。
'''
begin;
select id,name,stock as old_stock from shop where id=1 for update;
update shop set stock=stock-1 where id=1 and stock=old_stock;
commit
'''