前言
介绍mysql 锁的机制。
正文
锁类型
读锁,是一种共享锁,s锁,允许一个事务是读取一行,阻止其他事务获取相同的数据集的排他锁。
注:排它锁的意思就是说只能加相同的锁,不能加不同的锁,比如都加共享锁,也就是说大家可以都读取。
假如事务A对数据项Z进行s锁,那么事务B只能添加s锁,而不能添加互斥锁,也就是X锁。这保证了,其他事务可以读取Z,
但是在A的S锁释放之前,是不能进行任何修改的。
写锁,是互斥锁的一种,x锁。允许获取排它锁的事务更新数据,阻止其他事务取得相同的数据及共享读锁和排它写锁。
也就是说,加入事务A对数据项Z加了写锁,那么会产生一个效果,那就是其他事务就不能对该数据加任何锁了,这个时候
A可以对数据项Z进行读取和修改。
锁对象
这里介绍锁对象。
表锁:一次性对一张表整体加锁,是mysql中最大颗粒度的锁定机制。
MylSAM 存储引擎就是使用表锁,开销小、实现逻辑非常简单,带来的系统负面影响小,加锁和释放锁快,无死锁,但是锁范围大,容易发生锁冲突,并发最低。
行锁:一次性对一条数据加锁,锁定对象的颗粒度小。也就是我们常用的innodb可以用到行锁,开销大,加锁慢,容易出现死锁;锁的范围较小,不易发生锁冲突,并发高。
页面锁:锁定颗粒介于表锁和行锁之间;开销和加锁时间介于表锁和行锁之间。会出现死锁;并发度一般。
具体使用哪种引擎,哪种级别的锁,还是要看业务的,一般来说需要高并发的一般都是用innodb。
innodb
事务
为什么提及到这个innodb东西呢?是因为,俺只用到这东西,其他只是在理解层面上。
innodb 在锁的概念上两个特征,一个是支持事务,第二个就是行锁。
为什么说出这两个特征,前面提及过一个问题,就是说行锁有几个问题,开销发,加锁慢,容易出现死锁。
这里再次介绍事务的ACID。
原子性(actomicity),事务是一个操作单元对数据修改要不全部执行,要不就是全不执行。
一致性(Consistent),在事务开始和完成的时候,数据必须保持一致状态。
隔离性(lsolation),数据库系统提供一定的隔离机制,保证事务在不受外部并发影响的独立环境执行。
持久性(durable),事务完成之后,他对于数据的修改是永久性的,即使出现系统故障也能够保持。
同样的,因为事务需要保持着这几种特性,才能说是一个合格的事务。
因为事务的并发,然后又是行锁,那么就会产生一系列并发问题。
假设在不采用锁措施的情况下:
1.脏读:一个事务正在对一条数据做修改,在这个事务提交前。这时候另外一个事务也用来读取该条数据,这个时候就是读取了未提交的数据了。
2.不可重复读:一个事务在读取某些数据已经发生了改变,或某些记录已经被删除了。其实就是两次读取不一致。
是这样的,事务可以看成一系列事件的执行,比如说事件A进行读取数据Z,然后其他事务对数据Z进行写操作,那么A后面一个事件B也是读取操作,这个时候B读取到的数据和A读取到的数据不一致。
所以这个就叫做不可重复读,其实就是事务的隔离性被破坏。
幻读:一个事务两次的查询条件重新读取以前的数据已经发生数量的改变。比如说同一个事务T, A事件 读取到的数据是10条,然后事务B进行了增加一条,那么问题来了,事务B执行相同条件的查询的时候就出现了问题。
更新丢失:这个很好理解了,如果理解了脏读的话,这个就更好理解了,是这样子的,如果两个事务,同时对一条数据进行修改,然后分不同时候提交,那么肯定有一个是没有保存。
事务隔离
通过事务的隔离,来解决一些问题,但是呢,也要权衡利弊,为啥这么说呢?加锁肯定降低性能的。
1.读未提交:
就是不加锁,上面的问题就是因为不加锁导致的,所以说,you know。
2.读已提交
就是说事务只能读取到其他事务提交后的东西,写锁。
这个东西可以解决脏读,为什么这么说呢?因为脏读不就是读取没有提交的数据。
但是不可重复读还是会发生,是这样的,不可重复读是因为一个事务的事件中间穿插了其他事务的写事件。
3.可重复读
事务不会读到其他事务对已有数据的修改,及时其他事务已提交,也就是说,事务开始时读到的已有数据是什么,在事务提交前的任意时刻,这些数据的值都是一样的。
幻读问题依然存在。
4.串行化
这个不并发自然不产生问题。
结
该节为简单介绍,后续为悲观和乐观锁。