mysql锁机制

1).mysql锁基础
锁等待现象
表级锁:锁住一张表的数据 =》myisam下的, innodb也可能有
页级锁:锁住一页的数据
行级锁:锁住一行的数据 =》 innodb下的
越往上,资源开销越小,但是越往上加锁速度越慢
锁冲突,表越往下的概率约低
并法度:行级锁并法度的概率最低

重点:innodb下的行级锁

2).排它锁与共享锁-重点:innodb下的行级锁

排它锁加锁语法: select * from user where id=1 for update;

for update表示对要查询的语句加排它锁

共享锁:select * from user where id=1 lock in share mode;

lock in share mode表示加共享锁

set autocommit=0; 关闭事务自动提交配置1为自动提交,0为取消自动提交

排它锁:右边锁等待现象(排它锁与排它锁不能一起使用)

只有左边commit后才能查询出来

共享锁:就没有锁等待现象,两把共享锁可以同时使用

锁与锁之间的影响

事务与事务之间会不会有什么影响

排它锁与共享锁不能一起使用

事务1加排它锁,事务2加共享锁,事务2会进行锁等待

事务1加共享锁,事务2加排它锁,事务2会进行锁等待

对于update, insert,alter等写操作,mysql在事务中会自动加上排它锁

select * from user where id=1;对于普通查询,对锁没有影响,它依然可以获取加锁后的数据

当前读取:加锁的select的查询
快照读取:没加锁的普通查询

写操作的普通mysql语句,其实在对于innodb会自带事务的开启以及提交(自带begin,commit)
update user set username=‘111’ where id=1;

锁机制:使我们的业务强制进入串行化

3).乐观锁与悲观锁的解释
悲观锁:不管是加什么锁,只要是上了锁都属于悲观锁(共享锁和排它锁都属于悲观锁)
乐观锁:乐观,不会加任何锁,比如说MVCC

MVCC - 多版本的并发控制

软删除的意思
同例子:秒杀操作

以下哪些不是mysql的锁机制?排它锁

共享锁
表级锁
页级锁
行级锁
悲观锁
乐观锁

答案:悲观锁和乐观锁不是,他们属于概念,悲观锁是真的加锁,乐观锁是通过其他手段达到加锁的效果

4).死锁的产生和处理:属于一个现象,两个事务都进入了锁等待现象
产生于两个或两个以上的进程当中
例子:事务2直接报错Deadlock退出,事务1修改成功

还有一种现象:不会报错,但是会发生等待,事务1在等待事务2,事务2在等待事务1,锁等待时间超时还会报出异常
锁等待的时间:wait_timeout=120 #设置的是锁等待的时间
锁等待时间结束之后,事务会有一个失败和一个成功
失败和成功的mysql的选择与事务的大小有关:select比较小,update比较大
一般原则:舍小保大
一般出现死锁的范围的:模糊查询,范围查询

5).间隙锁与行锁升级为表锁

间隙锁:当我们使用的是范围查询而不是等式查询,并请求或者排它锁的时候

危害:如果在查询中通过范围去查询,锁住的范围会是所有索引的键值。即使这个数据不存在

右边事务就进入了锁等待,因为左边事务中是间隙锁,包括了id=3

行锁升级为表锁(只有innodb下产生)

锁去锁住的数据=》是与索引有一定的联系
?如何会发生?
主键与唯一索引 几乎为0
普通索引:很大几率会数据出现重复
举例:此时事务1已经升级到表锁了

在不加索引的字段上(除主键以及唯一索引之外)进行数据的加锁,会升级为表锁

如果字段在加了索引之后,就是该字段为普通索引,则加锁为行级锁

另外一个升级表锁情况:

因为是范围查询between,索引失效,所以升级为表锁

在加了索引之后,加锁会根据普通索引的基础上去进行加锁,而一旦索引失效,又会升级为表锁

避免升级表锁

1.会尽可能是索引字段进行加锁
2.尽可能使用等式而不是范围性的查询

不只是排它锁,共享锁也是一样的道理

mysql事务

1.事务基础理论
应用领域:金钱交易,银行方面的业务,秒杀,订单生成

异常捕获 try catch,回滚
try{

select * from product where id=1 for update;
if(){
    echo “库存不足”;
    exit;
}
……
commit;

}catch(){

rollback;

}

事务的四大特性:
(1)原子性:要么全部执行成功,要么全部执行失败 -回滚日志
(2)一致性:在事务开始之前和结束之后,数据都必须保 持一致状态,必须保证数据库的完整性.也就是说,数据必须符合数 据库的规则.要求数据由一个状态转化为另一个状态 -回滚日志
(3)持久性:保证数据不丢失 -通过重做日志
(4)隔离性:事务与事务之间不会相互影响 -通过锁

提问:如果事务是手动开启,那么如何回滚数据,数据是否会自动回滚
答案:不会,只能通过手动执行rollback

2.事务通过锁实现隔离级别
每一个事物的开启,我们可以把它看成一个盒子

事务的隔离级别:
读取未提交
读取已提交
可重读取(rr)
在可重复读中,该sql第一次读取到数据后,就将这些数据加锁(悲观锁),其它事务无法修改这些数据,就可以实现可重复读了。但这种方法却无法锁住insert的数据,所以当事务A先前读取了数据,或者修改了全部数据,事务B还是可以insert数据提交,这时事务A就会发现莫名其妙多了一条之前没有的数据,这就是幻读,不能通过行锁来避免。需要Serializable隔离级别 ,读用读锁,写用写锁,读锁和写锁互斥,这么做可以有效的避免幻读、不可重复读、脏读等问题,但会极大的降低数据库的并发能力。

串行化:只能排队读取

3.事务的生命周期
原子性的实现
begin;
select * from user where id=1;
commit;
rollback

事务日志文件=》 重做日志 redo log=> ib_logfile0 重新执行

                    回滚日志 undo log=> ibdata      回滚数据

mysql 对于事物的执行 =》 日志先行 凡是sql执行都会执行事务
日志优先级大于实际操作的数据的 所有执行的sql都会先执行日志,再写数据

BEGIN
update user set username=‘111’ where id=1;
update user set username=‘111’ where id=2;

2~3步骤中: 重做日志的会是缓存 而 回滚才是实际的(操作一次,记录一次)

4.事务日志
事务的重做日志:事务的id
show master status;

show binlog events in “mysql-bin.000003”\G;


提交commit时候会有xid,就是事务id
举例:
insert into user(id, username, age)values(1,’df’,10);
写入磁盘时候断电了呢?
在mysql事务执行了commit提交之后,服务器断电(挂了)但是数据还没有写入到磁盘中去,mysql会在下一次重启时,根据重做日志写入数据到磁盘中去。

事务的回滚日志:事务id,操作的数据元素,操作前的数据,操作后的数据
ROLLBACK
insert into user(id, username, age)values(1,’df’,10);
=>(回滚时会执行) delete from user where id=1; —记录一条相反的日志
执行:手动ROLLBACK
在mysql事务没有执行commit提交,但是发生了异常,在下一次mysql重启服务的时候执行

回滚实现了事务的一致性和原子性
隔离性通过事务的锁来实现=》行级锁
持久性=〉通过事务的重做日志来实现


Anita💋Wynn
1 声望0 粉丝

宝马程序员的一生!