Mysql锁模块

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

1. InnoDB

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

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

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


2. MyISAN

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

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

MyISAM不支持事务

 

二、数据库事务四大特效

1.原子性

2.隔离性

3.一致性

4.持久性

 

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

更新丢失--mysql所有事务隔离级别在数据库层面上均可避免

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

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

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

 

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会在读取的每一行数据上都加锁,所以可能导致大量的超时和锁争用问题。

实际应用中很少用到这种隔离级别,只有在非常需要确保数据一致性而且接受没有并发的情况下,才考虑采用该级别

 

916f3d0cd1c4b932bb50d9331c1619a2803.jpg2d337b00c4b88b9c878d49cf9137f4be50d.jpg

 

四、死锁

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

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

 

五、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中修改前的行

adec1aed99cfe9b462a52e8c197d4f0d522.jpg

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越多,递增

 

六、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锁住 

 

七、关键语法

1. 统计相关函数

count, sum, max, min, avg

2. group by

4d81ce2efa67fb3704cb7ef35bfac300280.jpg

3.HAVING

通常和group by子句一起使用

没有grup by子句,having和where的作用一样

where过滤行,having过滤组

出现在同一sql中的顺序 where > group by > having

5039c7227c0d908cf3330be2538720454f6.jpg

09bdbc8b71ee8c722f631343c84f7274d19.jpg

转载于:https://my.oschina.net/u/4000872/blog/3094190

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值