频 道 直 达 - 新闻 - 培训 - 软件 - 教程 - 前沿 - 组网 - 系统应用 - 安全 - 编程 - 存储 - 操作系统 - 数据库 - 服务器 - 专题 - 产品 - 案例库 - 读书 - 博客 - BBS
51CTO.COM_中国最大的网络技术网站
找资料:

20.3.6 恢复和复制的需要,对InnoDB锁机制的影响

作者: 唐汉明 翟振兴 兰丽华 关宝军 申宝柱 出处:人民邮电出版社  2008-03-27 22:22    砖    好    评论   进入论坛
阅读提示:《深入浅出MySQL——数据库开发、优化与管理维护》从数据库的基础、开发、优化、管理4方面对MySQL进行了详细的介绍,其中每一部分都独立成篇,每一篇又包括多个章节。本书面向实用,内容覆盖广泛,讲解由浅入深,适合于各个层次的读者。本文介绍了InnoDB锁。

20.3.6 恢复和复制的需要,对InnoDB锁机制的影响

MySQL通过BINLOG录执行成功的INSERT、UPDATE、DELETE等更新数据的SQL语句,并由此实现MySQL数据库的恢复和主从复制(可以参见本书“管理篇”的介绍)。MySQL的恢复机制(复制其实就是在Slave Mysql不断做基于BINLOG的恢复)有以下特点。

·一是MySQL的恢复是SQL语句级的,也就是重新执行BINLOG中的SQL语句。这与Oracle数据库不同,Oracle是基于数据库文件块的。

·二是MySQL的Binlog是按照事务提交的先后顺序记录的,恢复也是按这个顺序进行的。这点也与Oralce不同,Oracle是按照系统更新号(System Change Number,SCN)来恢复数据的,每个事务开始时,Oracle都会分配一个全局唯一的SCN,SCN的顺序与事务开始的时间顺序是一致的。

从上面两点可知,MySQL的恢复机制要求:在一个事务未提交前,其他并发事务不能插入满足其锁定条件的任何记录,也就是不允许出现幻读,这已经超过了ISO/ANSI SQL92“可重复读”隔离级别的要求,实际上是要求事务要串行化。这也是许多情况下,InnoDB要用到间隙锁的原因,比如在用范围条件更新记录时,无论在Read Commited或是Repeatable Read隔离级别下,InnoDB都要使用间隙锁,但这并不是隔离级别要求的,有关InnoDB在不同隔离级别下加锁的差异在下一小节还会介绍。

另外,对于“insert  into target_tab select * from source_tab where ...”和“create  table new_tab ...select ... From  source_tab where ...(CTAS)”这种SQL语句,用户并没有对source_tab做任何更新操作,但MySQL对这种SQL语句做了特别处理。先来看如表20-14的例子。

表20-14    CTAS操作给原表加锁例子

session_1

session_2

mysql> set autocommit = 0;

Query OK, 0 rows affected (0.00 sec)

 

mysql> select * from target_tab;

Empty set (0.00 sec)

 

mysql> select * from source_tab where name = '1';

+----+------+----+

| d1 | name | d2 |

+----+------+----+

|  4 | 1    |  1 |

|  5 | 1    |  1 |

|  6 | 1    |  1 |

|  7 | 1    |  1 |

|  8 | 1    |  1 |

+----+------+----+

5 rows in set (0.00 sec)

mysql> set autocommit = 0;

Query OK, 0 rows affected (0.00 sec)

 

mysql> select * from target_tab;

Empty set (0.00 sec)

 

mysql> select * from source_tab where name = '1';

+----+------+----+

| d1 | name | d2 |

+----+------+----+

|  4 | 1    |  1 |

|  5 | 1    |  1 |

|  6 | 1    |  1 |

|  7 | 1    |  1 |

|  8 | 1    |  1 |

+----+------+----+

5 rows in set (0.00 sec)

 

mysql> insert into target_tab select d1,name from source_tab where name = '1';

Query OK, 5 rows affected (0.00 sec)

Records: 5  Duplicates: 0  Warnings: 0

 

 

 

 

 

 

 

 

mysql> update source_tab set name = '1' where name = '8';

等待

commit;

 

 

 

返回结果

commit;

在上面的例子中,只是简单地读source_tab表的数据,相当于执行一个普通的SELECT语句,用一致性读就可以了。ORACLE正是这么做的,它通过MVCC技术实现的多版本数据来实现一致性读,不需要给source_tab加任何锁。我们知道InnoDB也实现了多版本数据,对普通的SELECT一致性读,也不需要加任何锁;但这里InnoDB却给source_tab加了共享锁,并没有使用多版本数据一致性读技术!

MySQL为什么要这么做呢?其原因还是为了保证恢复和复制的正确性。因为不加锁的话,如果在上述语句执行过程中,其他事务对source_tab做了更新操作,就可能导致数据恢复的结果错误。为了演示这一点,我们再重复一下前面的例子,不同的是在session_1执行事务前,先将系统变量innodb_locks_unsafe_for_binlog的值设置为“on”(其默认值为off),具体结果如表20-15所示。

表20-15            CTAS操作不给原表加锁带来的安全问题例子

session_1

 

session_2

 

mysql> set autocommit = 0;

Query OK, 0 rows affected (0.00 sec)

 

mysql>set innodb_locks_unsafe_for_binlog='on'

Query OK, 0 rows affected (0.00 sec)

mysql> select * from target_tab;

Empty set (0.00 sec)

 

mysql> select * from source_tab where name = '1';

+----+------+----+

| d1 | name | d2 |

+----+------+----+

|  4 | 1    |  1 |

|  5 | 1    |  1 |

|  6 | 1    |  1 |

|  7 | 1    |  1 |

|  8 | 1    |  1 |

+----+------+----+

5 rows in set (0.00 sec)

mysql> set autocommit = 0;

Query OK, 0 rows affected (0.00 sec)

 

mysql> select * from target_tab;

Empty set (0.00 sec)

 

mysql> select * from source_tab where name = '1';

+----+------+----+

| d1 | name | d2 |

+----+------+----+

|  4 | 1    |  1 |

|  5 | 1    |  1 |

|  6 | 1    |  1 |

|  7 | 1    |  1 |

|  8 | 1    |  1 |

+----+------+----+

5 rows in set (0.00 sec)

 

mysql> insert into target_tab select d1,name from source_tab where name = '1';

Query OK, 5 rows affected (0.00 sec)

Records: 5  Duplicates: 0  Warnings: 0

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

session_1未提交,可以对session_1select的记录进行更新操作。

mysql> update source_tab set name = '8' where name = '1';

Query OK, 5 rows affected (0.00 sec)

Rows matched: 5  Changed: 5  Warnings: 0

 

mysql> select * from source_tab where name = '8';

+----+------+----+

| d1 | name | d2 |

+----+------+----+

|  4 | 8    |  1 |

|  5 | 8    |  1 |

|  6 | 8    |  1 |

|  7 | 8    |  1 |

|  8 | 8    |  1 |

+----+------+----+

5 rows in set (0.00 sec)

 

 

 

更新操作先提交

mysql> commit;

Query OK, 0 rows affected (0.05 sec)

插入操作后提交

mysql> commit;

Query OK, 0 rows affected (0.07 sec)

 

 

 

此时查看数据,target_tab中可以插入source_tab更新前的结果,这符合应用逻辑:

mysql> select * from source_tab where name = '8';

+----+------+----+

| d1 | name | d2 |

+----+------+----+

|  4 | 8    |  1 |

|  5 | 8    |  1 |

|  6 | 8    |  1 |

|  7 | 8    |  1 |

|  8 | 8    |  1 |

+----+------+----+

5 rows in set (0.00 sec)

 

mysql> select * from target_tab;

+------+------+

| id   | name |

+------+------+

| 4    | 1.00 |

| 5    | 1.00 |

| 6    | 1.00 |

| 7    | 1.00 |

| 8    | 1.00 |

+------+------+

5 rows in set (0.00 sec)

mysql> select * from tt1 where name = '1';

Empty set (0.00 sec)

 

mysql> select * from source_tab where name = '8';

+----+------+----+

| d1 | name | d2 |

+----+------+----+

|  4 | 8    |  1 |

|  5 | 8    |  1 |

|  6 | 8    |  1 |

|  7 | 8    |  1 |

|  8 | 8    |  1 |

+----+------+----+

5 rows in set (0.00 sec)

 

mysql> select * from target_tab;

+------+------+

| id   | name |

+------+------+

| 4    | 1.00 |

| 5    | 1.00 |

| 6    | 1.00 |

| 7    | 1.00 |

| 8    | 1.00 |

+------+------+

5 rows in set (0.00 sec)

从上可见,设置系统变量innodb_locks_unsafe_for_binlog的值为“on”后,InnoDB不再对source_tab加锁,结果也符合应用逻辑,但是如果分析BINLOG的内容:

......
SET TIMESTAMP=1169175130;
BEGIN;
# at 274
#070119 10:51:57 server id 1  end_log_pos 105   Query  
thread_id=1     exec_time=0     error_code=0
SET TIMESTAMP=1169175117;
update source_tab set name = '8' where name = '1';
# at 379
#070119 10:52:10 server id 1  end_log_pos 406   Xid = 5
COMMIT;
# at 406
#070119 10:52:14 server id 1  end_log_pos 474   Query  
thread_id=2     exec_time=0     error_code=0
SET TIMESTAMP=1169175134;
BEGIN;
# at 474
#070119 10:51:29 server id 1  end_log_pos 119   Query  
thread_id=2     exec_time=0     error_code=0
SET TIMESTAMP=1169175089;
insert into target_tab select d1,name from source_tab where name = '1';
# at 593
#070119 10:52:14 server id 1  end_log_pos 620   Xid = 7
COMMIT;
......

可以发现,在BINLOG中,更新操作的位置在INSERT...SELECT之前,如果使用这个BINLOG进行数据库恢复,恢复的结果与实际的应用逻辑不符;如果进行复制,就会导致主从数据库不一致!

通过上面的例子,我们就不难理解为什么MySQL在处理“Insert  into target_tab select * from source_tab where ...”和“create  table new_tab ...select ... From  source_tab where ...”时要给source_tab加锁,而不是使用对并发影响最小的多版本数据来实现一致性读。还要特别说明的是,如果上述语句的SELECT是范围条件,InnoDB还会给源表加间隙锁(Next-Lock)。

因此,INSERT...SELECT...和CREATE TABLE...SELECT...语句,可能会阻止对源表的并发更新,造成对源表锁的等待。如果查询比较复杂的话,会造成严重的性能问题,我们在应用中应尽量避免使用。实际上,MySQL将这种SQL叫作不确定(non-deterministic)的SQL,不推荐使用。

如果应用中一定要用这种SQL来实现业务逻辑,又不希望对源表的并发更新产生影响,可以采取以下两种措施:

·一是采取上面示例中的做法,将innodb_locks_unsafe_for_binlog的值设置为“on”,强制MySQL使用多版本数据一致性读。但付出的代价是可能无法用binlog正确地恢复或复制数据,因此,不推荐使用这种方式。

·二是通过使用“select * from source_tab ... Into outfile”和“load data infile ...”语句组合来间接实现,采用这种方式MySQL不会给source_tab加锁。


回书目   上一节   下一节
专题
Sun以10亿美元并购开源数据库厂商MySQL
Oracle数据库开发之PL/SQL基础应用
Oracle数据库开发基础教程
2006年数据库频道热点关注
数据库安全技术专题
我也说两句

匿名发表

(如果看不清请点击图片进行更换)


中 国 最 大 的 网 络 技 术 网 站 ·
技 术 成 就 梦 想
订阅技术快讯
电子杂志下载
名称:SQL Server数据库管理精品黄皮书
简介:书中文章经过精挑细选,便于用户能根据自己的实际工作和学习,快速在本书寻找到相关资料。内容涵盖了SQL Server的安装与升级、语句查询、数据备份和恢复、自动化任务、数据同步、数据字典、安全和预防、性能和优化、集群等各方面应用信息,以及DBA管理人员在数据库管理工作中
名称:2007路由技术大全
简介:《2007路由技术大全》由51CTO.com网站特别策划制作,该书包括路由器技术、路由器产品、路由器配置、安全设置、路由器故障处理、路由器密码恢复,以及广大网友在实践使用中的心得经验和技巧文章,内容注重实用性,适用于初学者入门,也适合多年从业者提高,是一本实践和理论完
名称:网络安全精品应用黄皮书
简介:《2007精品网络安全黄皮书》包括了9个大类24个小类, 800余篇文章,内容包含了熊猫烧香病毒、DDOS攻击、ARP病等热点问题的介绍及解决方案。从病毒查杀、防范、系统、数据等各方面的安全设置到黑客技术的了解、防范,涉及到了安全应用的全部领域, 由浅至深内容全面。
SOA 面向服务架构
SOA 面向服务架构
CISSP认证成长之路
CISSP认证成长之路
隐私保护技术探讨
隐私保护技术探讨
· 隐私保护技术探讨
· WCF开发基础
· 珊瑚虫QQ作者侵权案开庭
· SQL Server 2008/2005..
· 华为员工自杀频频拷问..
· 计算机网络维护入门
· 开源虚拟化技术Xen
· 贝恩资本携手华为22亿..
· 如何优化IT 控制能耗
· VMware技术应用
· 打造安全服务器
· iSCSI应用与发展
· FTTx光纤接入
· Windows Server 2008专..
· Linux——从菜鸟到高手
· 微软出价446亿美元收购..
清除流氓软件——51CTO特别专题
清除流氓软件——51CTO特别专..
ARP攻击防范与解决方案
ARP攻击防范与解决方案
iSCSI应用与发展
iSCSI应用与发展
· iSCSI应用与发展
· SQL Server 2008/2005..
· SOA 面向服务架构
· SQL Server 2008/2005..
· iSCSI应用与发展
· RAID——磁盘阵列基础
· 中间件应用技术专题
· 病毒查杀专题
· 国际文档格式标准开战
· Linux防火墙
· 打造安全服务器
· Sniffer安全技术从入门..
· SOA 面向服务架构
· ADSL应用面面俱到
· 入侵防护系统(IPS)初探
· TCP/IP协议专题
ARP攻击防范与解决方案
ARP攻击防范与解决方案
SQL Server 2008/2005全解
SQL Server 2008/2005全解
iSCSI应用与发展
iSCSI应用与发展
· iSCSI应用与发展
· 中间件应用技术专题
· SQL Server 2008/2005..
· SOA 面向服务架构
· iSCSI应用与发展
· RAID——磁盘阵列基础
· 身份认证技术
· 病毒查杀专题
· 清除流氓软件——51CTO..
· Sniffer安全技术从入门..
· SOA 面向服务架构
· 了解统一威胁管理(UTM)..
· ADSL应用面面俱到
· ADSL应用面面俱到
· 反垃圾邮件技术应用
· TCP/IP协议专题