MYISAN与InnoDB关于锁方面的区别是什么?
- MYISAN默认用的是表级锁,不支持行级锁
- InnoDB默认用的是行级锁,也支持表级锁
MYISAM适合的场景
- 频繁执行全表count语句
- 对数据进行增删改的频率不高,查询非常频繁
- 没有事务
InnoDB适合的场景
- 数据增删改查都相当频繁
- 可靠性要求比较高,要求支持事务
数据库锁的分类
- 按锁的粒度划分,可分为表级锁、行级锁、页级锁
- 按锁级别划分,可分为共享锁、排它锁
- 按加锁方式划分,可分为自动锁和显示锁
- 按操作划分,可分为DML锁、DDL锁
- 按使用方式划分,可分为乐观锁和悲观锁
事务并发访问引起的问题以及如何避免
- 更新丢失----------mysql所有的事务隔离级别在数据库层面均可避免
- 脏读-------------READ-COMMITTED事务隔离级别以上可以避免
- 不可重复读----REPEATABLE-READ事务隔离级别以上可避免
- 幻读--------------SERIALIZABLE事务隔离级别可避免
共享锁和排他锁的区别:
- 共享锁(s):又称读锁。允许一个事务去读一行,阻止其他事务获得相同数据集的排他锁。若事务T对数据对象A加上S锁,则事务T可以读A但不能修改A,其他事务只能再对A加S锁,而不能加X锁,直到T释放A上的S锁。这保证了其他事务可以读A,但在T释放A上的S锁之前不能对A做任何修改。
- 排他锁(X):又称写锁。允许获取排他锁的事务更新数据,阻止其他事务取得相同的数据集共享读锁和排他写锁。若事务T对数据对象A加上X锁,事务T可以读A也可以修改A,其他事务不能再对A加任何锁,直到T释放A上的锁。
InnoDB可重复读隔离级别下如何避免幻读
- 表象:基于伪MVCC实现的快照读也就是(非阻塞读)
- 内在:next-key锁(行锁+GAP锁也就是间隙锁)
当前读就是加锁了再进行操作(加了锁的增删改查语句)
快照读,读到的可能不是数据的最新版本,而是历史版本
不管上的是X锁(排他锁)还是S锁(共享锁)都为当前读。当前读是啥意思呢?意思是当前操作的是最新记录,其他的并发事务不能修改当前记录,对当前记录加锁。其中,select…lock in share mode是使用的S锁,select…for update、update、insert、delete都是使用的X锁。
==而快照读是什么呢?==快照读就是不加锁的非阻塞读,也就是select操作。不过这里的快照读是基于非Serializable事务隔离界别下的,因为在Serializable隔离级别下,快照度会退化为当前读。这里的快照读就是MVCC的实现机制
做简单总结:
- 在RC隔离界别下,当前读和快照读读取的都是同一版本。
- 在RR隔离界别下,当前读读到的是最新版本数据,而快照度可能读取到的是历史版本数据。
==那么在RR隔离级别下,什么时候可以读到最新版本数据呢?==如果在进行增、删、改完成之后,再去查询快照读,则此时读取到的是最新版本的数据。如果是在增、删、改之前进行了快照读,在增、删、改之后继续快照读,则读到的就是旧版本数据。
RR级别下的InnoDB的(快照读)非阻塞读是如何实现的?
底层实现离不开数据行里的DB_TRX_ID、DB_ROLL_PTR、DB_ROW_ID字段,除此之外还需要undo日志,以及read view。
原理实现就是下列几个关键内容:
- 数据行里的DB_TRX_ID、DB_ROLL_PTR、DB_ROW_ID
- undo日志
- read view机制
说起DB_TRX_ID、DB_ROLL_PTR、DB_ROW_ID,那就要先知道MySQL一条记录是由记录的额外信息部分和记录的真实数据两部分组成。记录的额外记录部分存有变长字段长度列表、NULL值列表等,而记录的真实数据部分又由真实数据以及DB_TRX_ID、DB_ROLL_PTR、DB_ROW_ID这三个隐藏列组成。
比如现在有一个记录Field1、Field2、Field3数据分别为11、12、13,现在事务要修改该记录,将Field2修改为32。则这条记录首先会加载X锁,首先undo log中会拷贝一条修改前的记录,并赋值DB_ROW_ID。此时被X锁锁住的记录的DB_TRX_ID、DB_ROLL_PTR、DB_ROW_ID分别进行赋值,并且DB_ROLL_PTR的记录会指向undo log中的DB_ROW_ID的值。
如果此时又有一个事务对该记录进行了修改,则undo log日志中又会增加一条日志。
这样就是快照读版本的实现了。