- 浏览: 1336722 次
- 性别:
- 来自: 成都
文章分类
- 全部博客 (471)
- 原创文章 (4)
- Database (84)
- J2SE (63)
- Web (26)
- Javascript (30)
- Lucene (11)
- os (13)
- 算法 (8)
- Webservice (1)
- Open projects (18)
- Hibernate (18)
- Spring (15)
- Css (2)
- J2ee (2)
- 综合技术 (18)
- 安全管理 (13)
- PatternsInJava (27)
- NIO (5)
- Ibatis (2)
- 书籍收藏 (1)
- quartz (7)
- 并发编程 (15)
- oracle问题 (2)
- ios (60)
- coco2d-iphone (3)
- C++ (6)
- Zookeeper (2)
- golang (4)
- animation (2)
- android (1)
最新评论
-
dandingge123:
【引用】限制UITextField输入长度的方法 -
qja:
...
对List顺序,逆序,随机排列实例代码 -
安静听歌:
现在在搞这个,,,,,哎~头都大了,,,又freemarker ...
通用大型网站页面静态化解决方案(一) -
springdata-jpa:
java quartz定时任务demo教程源代码下载,地址:h ...
Quartz 配置参考 -
马清天:
[b][/b][list][*]引用[u][/u][/list ...
通用大型网站页面静态化解决方案(一)
1. MySQL 中并发和隔离控制机制
- Meta-data元数据锁:在table cache 缓存里实现的,为DDL(Data Definition Language)提供隔离操作。一种特别的meta-data元数据类型,叫Name Lock 。(SQL层)
- 表级table-level数据锁(SQL层)
- 存储引擎特有机制 — row locks行锁,page locks页锁,table locks表级,版本控制(在引擎中实现)
- 全局读锁 — FLUSH TABLES WITH READ LOCK (SQL层)
2.在语句执行中表的生命周期
DML(Data Manipulation Language):
- 计算语句使用到的所有表
- 在每个表:打开open表 — 从table cache 缓存里得到TABLE对象,并在此表加上meta-data元数据锁
- 等待全局读锁后改变数据
- 在每个表:锁lock 表 — 在表加上table-level数据锁
- 执行语句:调用:handler::write_row()/read_rnd()/read_index(),等;隐式地调用引擎级engine-level锁机制
- 在每个表:释放表的数据锁
- 在每个表:释放表的DDL锁并把表放回table cache 缓存里
- DDL语句也是一样,没有典型的执行计划。
3.获取meta-data元数据锁
- meta-data元数据锁的实现作为TABLE对象的一个属性,TABLE对象代表了table cache 缓存。
- meta-data元数据锁为如下任何一种:
4.表缓存(table cache )
- 是一个HASH变量,叫open_cache
- TABLE对象是HASH元素
- 以HASH的操作被LOCK_open mutex互斥量保护
4.1内部结构(The table cache : internal structure)
- 在缓存里,每个物理表可能被多个TABLE实例表示
- 相同表的所有TABLE实例,通过相连的列(a linked list)连接着
- 每个TABLE实例有一个table cache 缓存版本的复制 — TABLE实例保存的版本不会和当前table cache 缓存版本一致,而是保存旧的和从缓存删除的
- 被某些语句使用的TABLE实例被会标记为对其它的语句来说是无效的 — 这就是meta-data元数据锁的本质
- 在缓存中的TABLE实例通常地有一个有效的句柄实例连接着它
4.2内部运算(The table cache : operations)
- 主要的代码在:sql/sql_base.cc,sql/lock .cc,sql/table.h,sql/sql_table.cc
- 主要的方法:open_table(),close_thread_tables(),close_cached_table(),lock_table_names()
- 事实上,一个概念/对象组合不仅用于缓存或锁定:LOCK_open mutex互斥量也用到其它的操作,如:使磁盘上和处理中的表创建的原子性
- 典型的操作,来自隔离等级Pov的重要(注:isolation PoV没研究出是什么意思):语句查询时,打开和关闭表 — shared共享锁;强制和等待直到表的所有实例被关闭 — exclusive独享(但不完全);Name Lock — 特殊地情况,当手上没有TABLE实例,只能使用一个特殊的占位符(甚至表可能不存在)。
4.4锁多表(The table cache : locking multiple tables)
- 使用一种尝试和回退(try and back-off)的技术来避免死锁(乐观锁)
- 为了DDL操作的一套诀窍,如使锁升级或者防止DDL失效
- LOCK_open问题
- Lock_open互斥量:
- 保护table cache 缓存内的结构
- 分组存储引擎内的表和对象的.frm文件的创建,也为RENAME操作提供原子性操作
- 在每个语句访问表时会使用它两次:在open_tables()和close_thread_tables()
- 在使用DDL操作时,磁盘读写和甚至同步(sync)都会使用它
5.ALTER TABLE例子
ALTER TABLE执行的简化计划:
- 以TL_WRITE_ALLOW_READ的打开和加锁表(新版 InnoDB Plugin 已改为:TL-READ-NO-INSERT)
- 创建一个以临时名字的被ALTER的复制表
- 强制并等待直到表的所有实例都关闭(锁升级)
- 交换新和旧的版本
- 删除旧的版本
这是一般情况,当然还有优化的情况。
A debug trace for ALTER TABLE
- T@8: | query: alter table t1 add column k int
- T@8: | >mysql_parse
- T@8: | | >mysql_execute_command
- T@8: | | | >mysql_alter_table
- T@8: | | | | >open_ltable
- T@8: | | | | | >open_table
- T@8: | | | | | <open_table
- T@8: | | | | | >mysql_lock_tables
- T@8: | | | | | | >get_lock_data
- T@8: | | | | | | | >ha_innobase::store_lock
- T@8: | | | | | | | <ha_innobase::store_lock
- T@8: | | | | | | <get_lock_data
- T@8: | | | | | | >lock_external
- T@8: | | | | | | | >ha_innobase::external_lock
- T@8: | | | | | | | | enter: lock_type: 1
- T@8: | | | | | | | | >trans_register_ha
- T@8: | | | | | | | | | enter: stmt
- T@8: | | | | | | | | <trans_register_ha
- T@8: | | | | | | | <ha_innobase::external_lock
- T@8: | | | | | | <lock_external
- T@8: | | | | | | >thr_multi_lock
- T@8: | | | | | | | >thr_lock
- T@8: | | | | | | | <thr_lock
- T@8: | | | | | | <thr_multi_lock
- T@8: | | | | | <mysql_lock_tables
- T@8: | | | | <open_ltable
- T@8: | | | | >mysql_create_table
- T@8: | | | | <mysql_create_table
- T@8: | | | | >open_temporary_table
- T@8: | | | | | >openfrm
- T@8: | | | | | | >handler::ha_open
- T@8: | | | | | | | enter: name: ./test/#sql-3081_1 db_type: 12 db_stat: 7 mode: 2 lock_test: 2
- T@8: | | | | | | | >ha_innobase::open
- T@8: | | | | | | | <ha_innobase::open
- T@8: | | | | | | <handler::ha_open
- T@8: | | | | | <openfrm
- T@8: | | | | <open_temporary_table
- T@8: | | | | >copy_data_between_tables
- T@8: | | | | <copy_data_between_tables
- T@8: | | | | >closefrm
- T@8: | | | | <closefrm
- T@8: | | | | >close_cached_table
- T@8: | | | | | enter: table: t1
- T@8: | | | | | >wait_while_table_is_used
- T@8: | | | | | | >get_lock_data
- T@8: | | | | | | <get_lock_data
- T@8: | | | | | | >thr_abort_locks
- T@8: | | | | | | <thr_abort_locks
- T@8: | | | | | | >remove_table_from_cache
- T@8: | | | | | | | enter: Table: ‘test.t1′ flags: 2
- T@8: | | | | | | <remove_table_from_cache
- T@8: | | | | | <wait_while_table_is_used
- T@8: | | | | | >mysql_unlock_tables
- T@8: | | | | | | >thr_multi_unlock
- T@8: | | | | | | | lock : data: 0×8b7f9b0 count: 1
- T@8: | | | | | | | >thr_unlock
- T@8: | | | | | | | <thr_unlock
- T@8: | | | | | | <thr_multi_unlock
- T@8: | | | | | | >unlock_external
- T@8: | | | | | | | >ha_innobase::external_lock
- T@8: | | | | | | | <ha_innobase::external_lock
- T@8: | | | | | | <unlock_external
- T@8: | | | | | <mysql_unlock_tables
- T@8: | | | | | >unlink_open_table
- T@8: | | | | | | >hash_delete
- T@8: | | | | | | | >free_cache_entry
- T@8: | | | | | | | | >closefrm
- T@8: | | | | | | | | | >ha_innobase::close
- T@8: | | | | | | | | | <ha_innobase::close
- T@8: | | | | | | | | <closefrm
- T@8: | | | | | | | <free_cache_entry
- T@8: | | | | | | <hash_delete
- T@8: | | | | | <unlink_open_table
- T@8: | | | | <close_cached_table
- T@8: | | | | >mysql_rename_table
- T@8: | | | | | >ha_innobase::rename_table
- T@8: | | | | | <ha_innobase::rename_table
- T@8: | | | | <mysql_rename_table
- T@8: | | | | >mysql_rename_table
- T@8: | | | | | >ha_innobase::rename_table
- T@8: | | | | | <ha_innobase::rename_table
- T@8: | | | | <mysql_rename_table
- T@8: | | | | >my_delete
- T@8: | | | | | my: name ./test/#sql2-3081-1.frm MyFlags 0
- T@8: | | | | <my_delete
- T@8: | | | | >ha_delete_table
- T@8: | | | | | >ha_innobase::delete_table
- T@8: | | | | | <ha_innobase::delete_table
- T@8: | | | | <ha_delete_table
- T@8: | | | | >ha_commit_trans T@8: | | | | <ha_commit_trans T@8: | | | | >ha_commit_trans T@8: | | | | <ha_commit_trans T@8: | | | <mysql_alter_table
- T@8: | | <mysql_execute_command
- T@8: | <mysql_parse
- T@8: <dispatch_command
6.RENAME TABLE例子
- 得到源表和目的表的name-lock 锁:在table cache 缓存内插入特殊的TABLE实例的占位符并等待直到这些表的所有实例都关闭
- 重命名这些表的.frm文件和调用handler::rename_table()方法
- 删除name-lock 锁
在整个解析过程中,都使用LOCK_open
Simplified debug trace for RENAME TABLE
- T@10: | query: rename table t1 to t2
- T@10: | >mysql_parse
- T@10: | | >mysql_execute_command
- T@10: | | | >mysql_rename_tables
- T@10: | | | | >lock_table_names
- T@10: | | | | | >lock_table_name
- T@10: | | | | | | enter: db: test name: t1
- T@10: | | | | | <lock_table_name
- T@10: | | | | | >remove_table_from_cache
- T@10: | | | | | | enter: Table: ‘test.t1′ flags: 0
- T@10: | | | | | | >hash_delete
- T@10: | | | | | | | >free_cache_entry
- T@10: | | | | | | | | >closefrm
- T@10: | | | | | | | | | >ha_innobase::close
- T@10: | | | | | | | | | <ha_innobase::close
- T@10: | | | | | | | | <closefrm
- T@10: | | | | | | | <free_cache_entry
- T@10: | | | | | | <hash_delete
- T@10: | | | | | <remove_table_from_cache
- T@10: | | | | | >lock_table_name
- T@10: | | | | | | enter: db: test name: t2
- T@10: | | | | | <lock_table_name
- T@10: | | | | | >remove_table_from_cache
- T@10: | | | | | | enter: Table: ‘test.t2′ flags: 0
- T@10: | | | | | <remove_table_from_cache
- T@10: | | | | <lock_table_names
- T@10: | | | | >rename_tables
- T@10: | | | | | >do_rename
- T@10: | | | | | | >mysql_rename_table
- T@10: | | | | | | | >ha_innobase::rename_table
- T@10: | | | | | | | <ha_innobase::rename_table
- T@10: | | | | | | | >my_rename
- T@10: | | | | | | | | my: from ./test/t1.frm to ./test/t2.frm MyFlags 16
- T@10: | | | | | | | <my_rename
- T@10: | | | | | | <mysql_rename_table
- T@10: | | | | | <do_rename
- T@10: | | | | <rename_tables
- T@10: | | | | >unlock_table_names
- T@10: | | | | | >unlock_table_name
- T@10: | | | | | | >hash_delete
- T@10: | | | | | | | >free_cache_entry
- T@10: | | | | | | | <free_cache_entry
- T@10: | | | | | | <hash_delete
- T@10: | | | | | <unlock_table_name
- T@10: | | | | | >unlock_table_name
- T@10: | | | | | | >hash_delete
- T@10: | | | | | | | >free_cache_entry
- T@10: | | | | | | | <free_cache_entry
- T@10: | | | | | | <hash_delete
- T@10: | | | | | <unlock_table_name
- T@10: | | | | <unlock_table_names
- T@10: | | | <mysql_rename_tables
- T@10: | | <mysql_execute_command
- T@10: | <mysql_parse
7.表级table-level锁
- 主要源代码见:sql/lock .cc,mysys/thr_lock.cc。mysql_lock/unlock_tables()(SQL层操作)和thr_multi_lock()/thr_lock()(锁兼容逻辑lock -compatibility logic)
- 表是以打开着被加锁的。被加锁的对象被句柄关联着;存储引擎会调整锁的类型。如innodb /bdb,事实上大量的对象被加锁的,如merge/partition,见handler::store_lock()方法。
- 使用锁等级避免死锁。所有表一次性加锁;如果存储引擎调整锁造成死锁,由存储引擎负责
- 在一些情况下,表会更早地被解锁
8 .预加锁(pre-locking)
- 历史上避免死锁方案用于表级table-level数据锁,是要求一次性加锁一个语句内的所有表
- 因此,对语句使用的函数/触发,我们不得不打开所有直接地或间接地用到的表,且对它们加锁。为这个,我们建立一个被使用表的可传送闭包
- 为了有效实现,我们混合层次和访问(layers and access)成某些解析/语句上下文(parser/statement context),这些上下文来自主要处理表的模板
9.全局读锁(global read lock )
- 实现为FLUSH TABLES WITH READ LOCK ,用来备份
- 从执行上防止DDL和DML
- 建议:每个DDL/DML语句检查是否有一个正挂着的全局读锁和停止是否有任何一个。
- 通过直接调用wait_if_global_read_lock()(在这个情况我们会设置来自全局读锁的保护,且只有调用start_waiting_global_read_lock()来消除这个保护,通常在这情况下没有打开的表);
- 或者通过mysql_lock_tables()(在后一种情况下,我们还重新打开表)
- 线程操作FLUSH TABLES WITH READ LOCK 来设置一个全局读锁的标识,初始一个FLUSH TABLES语句,然后等待直到所有的表缓存都清空
发表评论
-
mysql主从热备配置(含innodb)终极版
2012-12-25 13:10 2659转自 http://blogread.cn/it/articl ... -
sqlite3中的数据类型
2012-12-10 21:37 1351(转)http://www.cnblogs.com/kfqco ... -
Mac下MySql卸载方法
2012-09-10 23:57 1064Mac下MySql卸载方法 mac下mysql的D ... -
mac os x mysql数据库utf8配置
2012-09-10 23:29 2292进入mysql console: 输入 mysql& ... -
ON DUPLICATE KEY UPDATE
2012-08-07 01:47 1101(转自)http://blog.csdn.net/kesaih ... -
MySQL单列索引和组合索引的区别介绍
2012-08-07 01:31 1113(转自)http://blog.cs ... -
centos下MySQL主从同步配置
2012-08-03 13:14 1566(转自)http://apps.hi.baidu.com ... -
sql语句中left join、inner join中的on与where的区别
2012-06-13 13:24 1270table a(id, type): id t ... -
分组取前N记录
2012-05-31 16:24 1134(转)http://blog.csdn.net/ac ... -
如何一条sql语句取出分组数据中值最大的
2012-05-30 23:59 2376--按某一字段分组取最大(小)值所在行的数据(2007-10- ... -
存储过程与函数的区别
2011-09-28 19:35 1169... -
RMAN备份方案
2011-07-21 10:29 2067RMAN备份方案 RMAN也可以进行联机备份,而且备份与恢 ... -
oracle
2011-04-06 17:46 1055学习笔记 -
PLSQL Developer + Oracle客户端简易安装方法
2011-03-17 00:10 14398Oracle 10g绿色客户端 pl ... -
SELECT INTO FROM与INSERT INTO SELECT
2011-01-26 15:52 34161.INSERT INTO SELECT语句 ... -
浅谈unique列上插入重复值的MySQL解决方案
2011-01-25 11:33 1785本文的unique列上插入重复值解决方案,主要基于MySQL平 ... -
:Oracle 中对Merge语句的增强 和去重复新增
2011-01-25 11:11 2333在Oracle 10g之前,merge语句支持匹配更新和不匹配 ... -
单行函数(仅对单个表达式或一行进行处理)
2011-01-23 18:49 1281例如:select sum(qty) from sales ... -
oracle中的事务控制命令
2011-01-23 18:45 2129事务提交有显示提交:使用commit命令来提交所有未提交的更新 ... -
oracle全文检索
2011-01-23 18:18 61661.全文检索和普通检索的区别 不使用Oracle text功 ...
相关推荐
MySQL锁机制_管理(并发锁,行锁,表锁,预加锁,全局锁等等).mht
全局锁、表锁和行锁是MySQL中常见的三种锁定级别,分别在不同场景下使用。 全局锁(Global Lock)是指对整个数据库实例加锁,最常用的实现方式是`FLUSH TABLES WITH READ LOCK`(FTWRL)。使用全局锁后,数据库将...
MySQL数据库中的锁机制是用于管理和控制并发访问的重要工具,它确保了数据的完整性和一致性,同时尽可能地提高系统性能。本文主要介绍了全局锁、表级锁和行锁三种类型的锁。 **全局锁**,全称是全局读锁(Global ...
不同的隔离级别对应不同的并发控制策略,例如,可重复读级别通过行级锁防止不可重复读和幻读,而串行化级别通过全局锁确保所有事务按顺序执行,以避免并发问题。 锁机制是实现事务隔离级别的基础。MySQL中的锁可以...
MySQL数据库应用与开发中,事务管理和锁机制是确保数据一致性、完整性和隔离性的关键组成部分,尤其在多用户环境下的数据库操作中显得尤为重要。以下是从给定文件中提取并详细展开的知识点: ### 事务的机制 事务...
MySQL中的锁结构是数据库管理系统中用于控制并发操作的重要机制,主要分为三种类型:表级锁、行级锁和页面锁。 1. **表级锁**: - 表级锁是一种全局锁,对整个表进行锁定,加锁速度快,不会出现死锁。但是它的锁定...
- **页面锁**:介于表锁和行锁之间,锁定的是数据页,锁定粒度和性能处于两者之间。 2. **表格类型**: - **MyISAM**:不支持事务,但每个查询都是原子的。使用表级锁,适合读多写少的场景。存储文件包括索引文件...
- 探讨了next-key锁机制及其对并发插入性能的影响。 - **13.6 隔离级别对并发插入的影响** - 说明了不同的事务隔离级别如何影响并发插入操作。 - **13.7 如何减少锁冲突** - 提供了一系列减少锁竞争的策略。 **...
填写全局数据库名,管理口令 6. 步骤5/8:先决条件检查 如果你的电脑满足要求但仍然显示检查失败,这时候直接忽略,勾选全部忽略 7. 步骤6/8:概要信息 核对将要安装数据的详细信息,并保存响应文件,以备以后...