第六节:select语句的锁行和锁表功能
前言
本文选自网站小册子《My家双雄:深度学习MySQL与MyBatis》:http://www.mybatis.cn/324.html。此书从数据访问存储层为入口,将延伸到分布式、高并发方面的关键技术。希望这本书能对每一个做Java Web开发的读者带来帮助,也欢迎大家提出更多的修改建议。
1、插入测试数据
drop table if exists person;
CREATE TABLE person (
id int primary key,name
VARCHAR ( 20 )
);
insert into person values(1,'A');
insert into person values(2,'B');
insert into person values(3,'C');
2、事务设置
查看是否是自动提交,如下所示:
select @@autocommit;
然后,取消SQL语句的自动提交功能
set autocommit=0;
3、Select的表锁和行锁
默认情况下,select语句是不会对数据加写锁的,也就是不会阻止写入(update delete),通过使用 for update可以对数据加写锁。
3.1 行锁
如果是按照主键查询的话,那么加的是行锁。请看下面的验证过程。
第一步:在第一个MySQL连接窗口中,执行:
begin;
select * from person where id =1 for update;
第二步:在第二个MySQL连接窗口中,执行:
update person set name='a' where id=1 ;
可以看到第二个连接的update语句一直在等待
第三步:在第三个MySQL连接窗口中,执行:
update person set name='b' where id=2;
执行结果为,瞬间更新成功:
Affected rows: 1
时间: 0.014s
说明按主键查询的话,加的是行锁。
第四步:在第一个MySQL连接窗口中,执行:
commit;
第一个连接commit之后,这时可以看到,第二个MySQL连接窗口中的update语句执行成功。
3.2 表锁
如果查询条件不是按主键查询,那么会对整个表加表锁。
第一步:在第一个MySQL连接窗口中,执行:
begin;
select * from person where name='a' for update;
第二步:在第二个MySQL连接窗口中,执行:
update person set name='c' where id=3;
可以看到,虽然 连接1中where name='a'的条件只能匹配id=1的一行,但是锁定了整张表。
第三步:在第一个MySQL连接窗口中,执行:
commit;
第一个连接commit之后,这时可以看到,第二个连接中的update语句执行成功。
4、InnoDB行锁和表锁实现方式
InnoDB行锁是通过索引上的索引项来实现的,这一点MySQL与Oracle不同,后者是通过在数据中对相应数据行加锁来实现的。InnoDB这种行锁实现特点意味者:只有通过索引条件检索数据,InnoDB才会使用行级锁,否则,InnoDB将使用表锁!在实际应用中,要特别注意InnoDB行锁的这一特性,不然的话,可能导致大量的锁冲突,从而影响并发性能。