mysql怎么保证隔离性 mysql56默认隔离级别( 三 )


使用select…for update会把数据给锁住,不过我们需要注意一些锁的级别 , MySQL InnoDB默认Row-Level Lock,所以只有「明确」地指定主键或者索引,MySQL 才会执行Row lock (只锁住被选取的数据) ,否则MySQL 将会执行Table Lock (将整个数据表单给锁住) 。举例如下:
1、select * from t_items where id=1 for update;
这条语句明确指定主键(id=1),并且有此数据(id=1的数据存在),则采用row lock 。只锁定当前这条数据 。
2、select * from t_items where id=3 for update;
这条语句明确指定主键,但是却查无此数据,此时不会产生lock(没有元数据,又去lock谁呢?) 。
3、select * from t_items where name='手机' for update;
这条语句没有指定数据的主键,那么此时产生table lock , 即在当前事务提交前整张数据表的所有字段将无法被查询 。
4、select * from t_items where id0 for update;或者select * from t_items where id1 for update;(注:在SQL中表示不等于)
上述两条语句的主键都不明确,也会产生table lock 。
5、select * from t_items where status=1 for update;(假设为status字段添加了索引)
这条语句明确指定了索引,并且有此数据,则产生row lock 。
6、select * from t_items where status=3 for update;(假设为status字段添加了索引)
这条语句明确指定索引,但是根据索引查无此数据,也就不会产生lock 。
乐观锁( Optimistic Locking ) 相对悲观锁而言,乐观锁假设认为数据一般情况下不会造成冲突,所以只会在数据进行提交更新的时候 , 才会正式对数据的冲突与否进行检测,如果发现冲突了,则返回用户错误的信息,让用户决定如何去做 。实现乐观锁一般来说有以下2种方式:
Mysql隔离级别之MVCC的ReadView的理解 比较常用的两种分别是读已提交、可重复读,那么Mysql是如何保证多个事务读取一条数据的隔离性的?
当我们读取一条被其他事务变更的数据时,会在undo Log中产生一条变更前的日志.这个日志可以专门用于回滚 。
我们大概来看一下这个日志的大概结构:
前面三个字段属于变更前的,另外:
trx_id: 代表是哪个事务编号修改的 。
roll_pointer: 相当于一个链表 , 往下查找就是上一次更改前的 。当一条数据被更改了多次之后,由该字段构建成一个链表俗称 版本链。
有了undo Log的话可以很快追溯到更改之前的数据,有了这个之后,假设多个事务都在读同一条记录,并且还发生了修改 , 这个时候
多版本并发控制,指的就是在使用读提交和可重复读隔离级别的事务,在执行普通select操作时 , 访问记录版本链的过程;使不同事务的读写、写读操作并发执行,提高系统性能;
基于当前活跃事务列表构成的ReadView , 当某个事务创建ReadView时,会将当前活跃的事务也加入其中 。
我们来看一下大概结构:
readview 中四个比较重要的概念:
m_ids :表示在生成readview时,当前系统中 活跃的读写事务id列表 ;
min_trx_id :表示在生成readview时 , 当前系统中活跃的读写事务中最小的事务id , 也就是m_ids中最小的值;
max_trx_id :表示生成readview时,系统中应该分配给下一个事务的id值;
creator_trx_id :表示生成该readview的事务的事务id;
有了readview,在访问某条记录时,按照以下步骤判断记录的某个版本是否可见:
下面是对于同一条数据的多个事务读取流程:
ReadView( 简称RV )一旦创建是不可变的,即便其中某个线程事务提交了,也不会影响当前线程创建的ReadView,你可以理解为一个副本快照 。

推荐阅读