无论何时,只要有多个查询需要在同一时刻修改数据,都会产生并发控制的问题,并发控制是一个复杂而庞大的过程。上网搜多了就会经常看到乐观锁,悲观锁,读锁,写锁,表锁,行锁,手动加锁,自动加锁,事务等另人眼花缭乱,今天特地来总结下
我们先来了解下几个概念
1.乐观锁:顾名思义就是很乐观,在每次数据修改之前认为不会有并发问题,而是是数据修改的时候再去检查数据一致性问题,由此可见乐观锁是一种描述加锁时机的锁,这种锁本质上不是数据库的锁概念,而是我们定义出来的。
2.悲观锁:悲观锁是相对乐观锁来的,也就是在每次数据修改之前悲观的认为一定会发生并发问题,故在操作之前就给相应的数据行或者表加上锁,操作完后释放锁,这种锁本质上也不是数据库的锁概念,而是我们定义出来的。
3.读写锁:读锁也叫共享锁,或者说相互之间不堵塞的,多个客户在同一时刻可以同时读取同一个资源,而互不干扰,不过加了共享锁就不能再加写锁了;写锁是排他的,也就是说一个写锁会阻塞其他的写锁和读锁。
4.锁粒度:表锁和行级锁,表锁是MySQL中最基本的锁策略,并且是开销最小的策略,它会锁定整张表。一个用户对表进行写操作(插入,删除,更新等)前,需要先获得写锁,这会阻塞其他用户对表的读写操作。只有没有写锁时,其他读取的用户才能获得读锁,读锁之间是不相互阻塞的。由此可见表锁不太适合大量写操作的业务,如果存在大量的写操作就会造成严重的阻塞。行级锁顾名思义锁定部分的数据行,行级锁只在存储引擎层实现。
5.手动加锁:包括乐观锁和悲观锁,乐观锁一般是通过在表里面加个版本号或者时间戳来实现,版本号或者时间搓大于当前值的时候才能进行数据的修改,悲观锁我们常见的就是事务,select ... for update 给行加上锁(在一个事务中或者关闭自动提交功能后才有用),提交(commit )后其他事务中才可以对改数据进行修改。
- 自动加锁:一般是MySQL在Create,alter,insert,update 等命令时会自动加上。
7.事务:(可以顺便了解下事务日志)事务有四种隔离级别,对应不同的锁机制,
隔离级别:Read Uncommitted(读取未提交内容),Read Committed(读取提交内容),Repeatable Read(可重复读) MySQL 默认的事务隔离级别,Serializable(可串行化)
接下来我们再来简单了解下事务4种隔离级别的定义:
- Read Uncommitted (未提交读):事务中的修改,即使没有提交,对其他事务也是可见的,会导致脏读,这种隔离级别在实际应用中很少使用,可能需要手动加锁才能保证不会脏读。
2.Read Committed (提交读):大多数数据库系统的默认隔离级别都是提交读,一个事务在开始时只能“看见”已经提交的事务所做的修改,换句话说,一个事务在开始直到提交之前,所做的任何修改对其他事务是不可见的,这个级别有时候也可以叫做不可重复读,因为两次执行同样的查询可能得到不同的结果。
3.Repeatable Read(可重复读) :改级别保证了在同一个事务中多次读取同样数据的结果是一样的。但是在理论上,可重复读隔离级别还是无法解决另外一个幻读的问题,所谓幻读,指的是当某个事务在读取某个范围内的数据时,另外一个事务又插入了新的记录,当之前的的事务再次读取范围记录时就会产生幻行,Innodb存储引擎通过多版本并发控制解决了幻行的问题。
4.Serializable(可串行化):是最高的隔离级别。它通过强制事务串行执行,避免了幻读的问题,该隔离级别是会在读取的每一行数据上加上锁,所以会导致大量的超时和锁争议的问题。实际应用中也很少使用。
了解了这么多大家是不是相对之前对各种锁清晰了许多呢?
MySQL 数据库锁实现是庞大而复杂的,如果想进一步了解的朋友可以关注后续文章,我将会对每种锁的实现进行展示。
思考:
1.各种锁是怎么实现的以及应用场景?
2.并发事务可能带来哪些问题?
网友评论