在mysql innodb中的行锁分为共享锁和排他锁
共享锁:
名词解释:共享锁又叫做读锁,所有的事务只能对其进行读操作不能写操作,加上共享锁后在事务结束之前其他事务只能再加共享锁,除此之外其他任何类型的锁都不能再加了。
用法:SELECT `id` FROM table WHERE id in(1,2) LOCK IN SHARE MODE 结果集的数据都会加共享锁
排他锁:
名词解释:若某个事物对某一行加上了排他锁,只能这个事务对其进行读写,在此事务结束之前,其他事务不能对其进行加任何锁,其他进程可以读取,不能进行写操作,需等待其释放。
用法:SELECT `id` FROM mk_user WHERE id=1 FOR UPDATE
注意:由于在innodb中行锁,他是针对索引去锁定该条数据,而不是直接锁定该条数据的。
另外,在行锁中,如果没有设置索引,InnoDB只能使用表锁。下面就是例子:
首先我们先查看一下该表有哪些所以,然后把所有索引都删除。接着就开始没有索引的情况下进行行锁。
session 1开启事务,然后今天查询,同时进行行锁。但是不提交。
session 2session2中我们对id=2数据进行行锁,结果发现,在等待状态,说明这个时候,session1在行锁的时候,没有找到索引,就锁表了,这也是为什么session2处于等待状态,只有seesion1 commit的时候,才能获取数据。
session 1 session 2接着就看一下设置好索引以后得查询
首先设置主键索引:
设置主键索引接着开始行锁查询
session1行锁 session2行锁可以发现在行锁执行排他锁的时候,session1在没有commit的情况下,session2进行查询是处于等待状态。
接着我们查询不用数据得时候
session2可以看到,当查询不同数据的时候,就不会出现等待状态。由此可以知道,由于MySQL的行锁是针对索引加的锁,不是针对记录加的锁,所以虽然是访问不同行的记录,但是如果是使用相同的索引键,是会出现锁冲突的。应用设计的时候要注意这一点。怎么理解这句话呢,举个例子
给tel设置一个普通索引
设置索引我们用session1进行行锁,查询tel为123的 发现有两条数据
session1我们用session2进行行锁,查询tel为234的
session2发现没有等待状态,但是如果我们查询tel为123且name为33的呢?
session2就会发现处于等待状态,这就是如果是使用相同的索引键,是会出现锁冲突的的解释。因为你session查询tel 为123的,此时还没有提交,处于行锁状态,session2去查询tel为123 name为33的,就会出现等待。
另外当表有多个索引的时候,不同的事务可以使用不同的索引锁定不同的行,另外,不论是使用主键索引、唯一索引或普通索引,InnoDB都会使用行锁来对数据加锁。
解释一下:
session2由于前面session1用过行锁,查询tel为123的,有两条数据,分别id为1和3的,此时,这两条数据处于锁定状态,当session2查询id为3的时候,由于这条数据处于锁定状态,因此就出现了等待。
另外出现的就是一个死锁得问题,举个例子。
session 1 session2session1 锁定id为1的,session2锁定id为2的。此时,如果session1再去查找id为2的,session2去查找id为1的,会出现什么情况呢?
死锁这时候就出现了死锁的情况,逻辑上就是:session1在等待session2去commit ,session2在等待session1去commit。然后就进入死循环了。
看看到底有没有死锁呢,
show engine innodb status 查看一下mysql死锁日志。能看打死锁的原因,我因为我前面执行的两句导致得。
网友评论