Mysql锁模块

1、InnoDB和MyISAM引擎锁方面的区别

1. InnoDB

InnoDB默认支持行级锁,也支持表级锁。mysql

InnoDB在sql中用到索引时使用的时行级锁;没有用到索引的时候,或者索引不明确时(>,<,like)使用的是表级锁。算法

InnoDB(增删改)时会自动加锁,select操做时不加锁(默认是用的非锁定读),须要显示加写锁(for update)和读所(lock in share mode)sql


2. MyISAN

MyISAM默认支持表级锁,不支持行级锁。数据库

MyISAM(增删改查)都会自动上锁。并发

MyISAM不支持事务mvc

 

2、数据库事务四大特效

1.原子性

2.隔离性

3.一致性

4.持久性

 

3、Mysql事务隔离级别,以及各级别下的并发访问问题

更新丢失--mysql全部事务隔离级别在数据库层面上都可避免函数

脏读--READ COMMITTED事务隔离级别以上可避免高并发

不可重复读--REPEATABLE READ事务隔离级别以上可避免性能

幻读--SERIALIZABLE事务隔离级别可避免spa

 

1. READ UNCOMMITTED (未提交读)

事务中的修改,即便没有提交,对其余事务也都是可见的。

事务能够读取未提交的数据,出现脏读(dirty read)(读取别的事务还未提交的数据)

 

2. READ COMMITTED (提交读)

一个事务从开始直到提交前,所作的任何修改对其余事务都是不可见的;也叫不可重复读(nonrepeatable read),由于两次相同的查询可能会获得不同的结果。

大多数数据库系统(Sql Server , Oracle)的默认隔离级别 READ COMMITTED(msyql不是)。

出现不可重复读问题: 在当前事务中屡次读取同一数据结果不一致(侧重与同一数据的修改)

A: start transaction .   B: start transaction
A: select 100;     
  B: update 100 + 100
A: select  100 ;     
  B: commit;
A: select 200;  
A: commit;  

 

3. REPEATABLE READ (可重复读)

mysql默认事务隔离级别

InnoDB和XtraDB引擎经过多版本并发控制(MVCC, Multiversion Concurrency Control)解决了幻读

解决了不可重复读;

A: start transaction .   B: start transaction
A: select 100;     
  B: update 100 + 100
A: select  100 ;     
  B: commit;
A: select 100;  
A: update + 100  
A: select 300  

出现幻读(侧重于新增和删除),当某个事务在读取某个范围内数据时,另一个事务又在该范围内插入了新的记录,当以前的事务再次读取该范围内记录时,会产生幻行。

repeatable read隔离级别下

A: start transaction .   B: start transaction
A: select  ... lock in share mode(当前读);     
 

B: insert into .. value()

A使用的是当前读,阻塞没法插入(避免了幻读)

A: commit

 
A: start transaction .   B: start transaction

A: select  10条 (当前读)

 
  B: insert into ...value()
  B: commit
A: update ...(修改了11条)  
A: commit  

select 某记录是否存在,不存在,准备插入此记录,但执行 insert 时发现此记录已存在,没法插入,此时就发生了幻读。 

A: start transaction .   B: start transaction

A: select  where id = 1;   empty

 
  B: insert into value(1)
  B: commit
A: insert into value(1);  error  
A: select where id = 1; empty  
A: commit  

read committed隔离级别下 

A: start transaction .   B: start transaction
A: select  ... lock in share mode;(3行)   
 

B: insert into .. value()(插入1行)

(实际状况:read committed 自动变为repeatable read 级别,阻塞没法插入)

  B: commit;
A: update (更新了4行)  
A: commit  

4. SERIALIZABLE  (可串行化)

SERIALIZABLE 最高的隔离级别;

经过强制事务串行执行,避免了幻读问题;SERIALIZABLE会在读取的每一行数据上都加锁,因此可能致使大量的超时和锁争用问题。

实际应用中不多用到这种隔离级别,只有在很是须要确保数据一致性并且接受没有并发的状况下,才考虑采用该级别

 

 

4、死锁

死锁:指两个或者多个事务在同一资源上相互占有,并请求对方占用的资源

InnoDB目前处理死锁的方法是:将持有最少行级锁的事务进行会滚

 

5、RC、RR级别下的InnoDB的非阻塞读(快照读)如何实现

数据行里隐藏字段的DB_TRX_ID、DB_ROLL_PTR、DB_ROW_ID字段

DB_TRX_ID:该字段用来标识最近一次对本行记录作修改(update ,delete)(最后一次修改本行记录的事务id)

DB_ROLL_PTR: 回滚指针

DB_ROW_ID: 隐示建立的自增主键字段

undo日志:对记录变动操做时产生undo记录,存储的是老版数据,当一个久的事务须要读取事务时,为了可以读取老版本的数据,须要顺着undo链找到其知足可见性的记录,分为insert(事务回滚时须要,并在事务提交后当即丢弃)和update undo log

insert undo log: 事务回滚时须要,并在事务提交后当即丢弃

update undo log:事务对记录进行delete 或update操做时产生的undo log, 在事务回滚时和快照读时须要

1. 锁住该行日志,

2. 并将数据拷贝一份到undo log,

3. 修改当前行的值,

4. 填写事务id(DB_TRX_ID),

5. 使用回滚指针(DB_ROLL_PTR)指向undo log中修改前的行

read view :作可见性判断,当执行快照读select时,会针对查询的数据建立一个read view,来决定当前事务能看到的是哪一个版本的数据(多是最新数据,也可能只容许看undo log某个版本的数据),read view遵循一个可见性算法,将要修改的数据DB_TRX_ID取出来与系统其余活跃事务id作对比,若是大于或等于这些事务id,就经过DB_ROLL_PTR指针去取出undo log上一层的DB_TRX_ID直到小于这些活跃事务id为止,保证了获取到的数据版本是当前可见的最稳定的版本。

mysql源码,保存活动事务的地方,m_low_limit_id(活动事务最大id),m_up_imit_id(活动事务最小id)。start transtaction,越新开启的事务id越多,递增

 

6、InnoDB可重复读隔离级别下如何避免幻读

表象:快照读(非阻塞读)--伪MVCC,(并非多版本共存,undo log是串行化的结果),读不加锁,读写不冲突

内在:next-key锁(行锁+gap锁)

        (不管是当前读仍是快照读,在innodb的RR的事务隔离级别下均可以免幻读。在快照读的状况下,innodb经过mvcc来避免幻读;在当前读的状况下,innodb经过next-key锁来避免幻读)

 

当前读:加了锁的增删改查, (不论是共享锁仍是排他锁均为当前读,insert, delete, update, select ... for update, select ... lock in share mode)

            读取的是记录的最新版本,而且读取以后还须要保证其余并发事务不能修改当前记录,对读取的记录加锁。

快照读:不加锁的非阻塞读,select;;

            serializable隔离级别下是串行读,快照读退化成当前读;

            快照读的实现基于多版本并发控制(MVCC),避免了加锁操做,提升并发性能, 开销更低;

            快照读有可能读到的数据并非最新版本,多是以前的 历史版本

read committed级别下,当前读和快照读的结果同样的,数据版本同样,(读取的是另外一个事务提交后的结果)

A: start transaction .   B: start transaction
A: select 100 (快照读);   建立新的快照read view  
  B: update 100 + 100
  B: commit
A: select(快照读) 200; 建立新的快照read view  
A: select lock in share mode(当前读) 200  
A: commit  

repeatable read级别下,快照读(读取的多是数据未修改前的版本,建立快照读的时机决定了读取数据的版本),当前读(读取的是数据的最新版本)

A: start transaction .   B: start transaction
A: select 100(快照读)  ,会建立一个快照read view,将当前系统活跃的事务id记录起来  
  B: update 100 + 100
  B: commit

A: select (快照读) 100,读到的是历史版本;事务开启后未作读取操做,则此时读取的是最新版本 200

使用的是前一个快照的read view

 
A: select lock in share mode(当前读) 200,最新版本  
A: commit  

READ COMMITTD在每一次进行普通SELECT操做前都会
生成一个ReadView,而REPEATABLE READ只在第一次进行普通SELECT操做前生成一个ReadView,以后的查
询操做都重复使用这个ReadView就行了

 

next-key锁(行锁 + gap锁)

gap锁,间隙锁,锁定一个范围但不包括记录自己,防止同一事务的两次当前读出现幻读的状况

gap锁, read uncommitted, read committed 级别下没有 ,没法避免幻读

gap lock会用在非惟一索引和不走索引的当前读,以及仅命中检索条件的部分结果集;主键索引和惟一索引的当前读中;

 

repeatable read级别下当前读(删改查)对主键索引或者惟一索引会用gap锁吗?

1.对于主键索引和惟一索引的当前读,若是where条件所有命中(精确查询时全部记录都有),则不会用gap锁,只会加行锁,若是范围条件部分命中或者都不命中,则使用Gap锁。

2.对于主键索引和惟一索引的当前读,用相等条件检索数据时,存在使用行锁,不存在使用gap锁///

3.对于非惟一索引的当前读:使用Gap锁

4.对于不走索引的当前读:使用Gap锁(至关于锁表)

总结:插入操做对查询结果有影响就gap锁 + 行锁,没有只加行锁

select * from table where id in (1,3,5),  id为1,3,5均在该table中存在,所有命中, 事务B新增一条数据在事务A查询的范围以外,事务B提交后,事务A再作当前读仍是原来的数据,不会出现幻读。

A: start transaction .   B: start transaction

A: delete from tb where id=9 (主键索引或惟一索引);

 
 

B: insert into tb value(10),

id=9数据存在,插入成功;不存在失败阻塞,id=9数据周围的间隙被锁住了

A: rollback  

数据库中数据:4,5,80, 100

当前读要查询数据90;(80,90] 和(90,100] 区间会被gap锁住 

 

7、关键语法

1. 统计相关函数

count, sum, max, min, avg

2. group by

3.HAVING

一般和group by子句一块儿使用

没有grup by子句,having和where的做用同样

where过滤行,having过滤组

出如今同一sql中的顺序 where > group by > having

相关文章
相关标签/搜索