mysql隔离级别与sql blocking之间的关系

本文详细介绍了MySQL数据库中四种不同的事务隔离级别:read committed、read uncommitted、repeatable read及serializable的特点与行为差异,并通过具体示例展示了不同级别下脏读、不可重复读和幻读等现象。
a、隔离级别为:read commit(不允许脏读)


session 1 window:
set autocommit=0
update table1 set field = new value where condition_field=condition_value;


session 2 window:
select @@global.tx_isolation(此时的隔离级别应该为read commit)
select * from table1;
这个时候你会发现,session 1 update的数据,在session 2的select 里面是看不到修改的,因为此时的隔离级别是不允许脏读的

在session 1 window中commit,然后再次在session 2中执行检索sql,可以检索到最新的修改




b、隔离级别修改:set global transaction isolation level read uncommitted(允许脏读);


session 1 window:
set autocommit=0
update table1 set field = new value where condition_field=condition_value; 

session 2 window:
select @@global.tx_isolation(确认此时的mysql global transaction isolation level is read uncommitted[可脏读])
select * from table1;
这个时候即使我没有在session 1 window里面commit,但是也可以看到update的数据。



C、隔离级别的修改:set global transaction isolation level repeatable read;(可重复读隔离级别)
PS:这个地方要特别注意下,mysql这里的可重复读跟别的数据库不一样,mysql的可重复读隔离级别是不会出现幻读的,什么意思呢?看效果

session 1 window:
同样,autocommit为off(0)状态
insert into table1 values (......);

session 2 window:
select @@global.tx_isolation(确认为repeatable-read模式)
select * from test;

这个时候,你会发现,在session 1没有做commit的时候,在session 2 window执行select的时候,是看不到在session 1 window执行的insert但未commit的数据的。因为mysql这里的repeatable-read的隔离级别就是不允许幻读的。在session 1 window中执行commit之后,再在session 2 Window中执行select之后,在session 1 window中做的修改就都可以看到了,恩,对的,在这个地方能够看到修改就是有问题了,因为在repeatable read(mysql)里面,这个隔离级别是可重复读的,即使我们session 1 window做了commit之后,session 2 window应该也是不能看到的。除非,session 2 window也做了commit,具体的读者可以自己动手实验一把,只需要在session 2 windows的开始也将autocommit设置为0.


D、隔离级别修改:set global transaction isolation level serializable(修改隔离级别为串行话,串行话的隔离级别,每次读都需要获得表级共享锁,继续看实验)

session 1 window:
set autocommit=0;
select @@global.tx_isolation(确认隔离级别修改有效)
update table1 set field_name = new value where condition_field_name = condition_value;

session 2 window:
select * from table1(这个时候select 是木有问题的)
但是,这个时候,我们在session 2 window里面执行update这样的写操作的时候,update一下看:yes。出现了:Lock wait timeout exceeded,这个时候就出现了阻塞,因为在此隔离级别的情况下,会自动的加上一个共享锁,只能读不允许写的,写会被阻塞。

如果此时,在session 2报错之前,session 1 进行了commit呢?请读者自己动手实验一把吧。

PS:以上均建立在mysql数据库,存储引擎为innodb,锁级别为行级锁的基础上。
<think>我们正在讨论的是MySQL中查看阻塞SQL的方法。根据引用[1]、[3]和[4],我们可以获取以下信息: 引用[1]提到:当造成阻塞的SQL已经执行完成但未提交时,在information_schema.INNODB_TRX中无法查看,但可以通过performance_schema.events_statements_current查询。 引用[3]提供了一个查询,可以找出当前被阻塞的事务以及阻塞它的语句。这个查询连接了多个系统视图(INNODB_TRX, innodb_lock_waits, performance_schema.threads, performance_schema.events_statements_current)。 引用[4]指出:如果blocking_query(阻塞查询)为空,可能是因为该SQL已经不在历史会话记录中,这时需要调整performance_schema_events_statements_history_size的大小。 因此,我们可以总结出两种主要方法: 方法1:使用information_schema和performance_schema联合查询(如引用[3]所示)。 方法2:当阻塞事务已经结束(无法在INNODB_TRX中找到)时,可能需要通过调整配置并查询performance_schema的历史记录来获取。 下面我将详细说明这两种方法。 ### 方法1:查询当前阻塞情况(推荐) 使用以下SQL可以查看当前被阻塞的事务以及阻塞它的SQL语句: ```sql SELECT btrx.trx_id AS 被阻塞事务id, btrx.trx_wait_started AS 被阻塞时间, btrx.trx_mysql_thread_id AS 被阻塞线程id, btrx.trx_query AS 被阻塞语句, trx.SQL_TEXT AS 阻塞语句 FROM information_schema.INNODB_TRX btrx LEFT JOIN information_schema.innodb_lock_waits bw ON btrx.trx_id = bw.requesting_trx_id LEFT JOIN ( SELECT trx.trx_id, trx.trx_mysql_thread_id, sc.SQL_TEXT FROM information_schema.INNODB_TRX trx LEFT JOIN performance_schema.threads t ON trx.trx_mysql_thread_id = t.PROCESSLIST_ID LEFT JOIN performance_schema.events_statements_current sc ON sc.thread_id = t.THREAD_ID ) trx ON bw.blocking_trx_id = trx.trx_id WHERE btrx.trx_state = 'LOCK WAIT'; ``` **解释**: - `INNODB_TRX` 表提供了当前InnoDB事务的信息。 - `innodb_lock_waits` 表记录了锁等待的关系。 - 通过子查询,我们关联了阻塞事务(blocking_trx_id)在`performance_schema.events_statements_current`中当前正在执行的SQL语句(如果有的话)。 - 过滤条件`btrx.trx_state = 'LOCK WAIT'`确保只查看正在等待锁的事务。 ### 方法2:处理阻塞事务已结束的情况 如果阻塞事务已经结束(即提交或回滚),那么上述查询中的阻塞语句可能为空(blocking_query为空)。此时,我们可以尝试: 1. **增加历史SQL记录的保存条数**:修改`performance_schema_events_statements_history_size`系统变量(需要重启实例或动态设置,但动态设置可能只对新会话有效)。 ```sql -- 查看当前设置 SHOW VARIABLES LIKE 'performance_schema_events_statements_history_size'; -- 设置全局值(例如增加到100条) SET GLOBAL performance_schema_events_statements_history_size = 100; ``` 2. **查询历史语句表**:通过`performance_schema.events_statements_history`表查看历史SQL记录(注意:需要启用performance_schema,并且该表记录的是每个线程最近的语句,数量由上述变量控制)。 修改上述查询,将`events_statements_current`替换为`events_statements_history`,并可能需要调整关联条件。 ### 注意事项 - 需要具有足够的权限访问`information_schema`和`performance_schema`中的表。 - `performance_schema`默认是启用的,但确保它已开启(可通过`SHOW VARIABLES LIKE 'performance_schema';`查看,值为`ON`)。 - 如果阻塞事务已经结束,那么可能无法追溯阻塞源头的SQL语句,因此及时监控是关键。 ### 监控建议 定期运行上述查询(方法1)可以帮助及时发现阻塞问题。另外,使用MySQL的企业监控工具(如MySQL Enterprise Monitor)或第三方监控工具(如Percona Monitoring and Management)可以设置告警。 --- §§相关问题§§ 1. 如何预防MySQL中的锁阻塞问题? 2. 除了阻塞查询,还有哪些方法可以分析MySQL锁竞争? 3. 如何设置MySQL的锁等待超时时间? 4. 事务隔离级别对锁阻塞有什么影响? [^1]: 当造成阻塞的SQL已经执行完成但未提交时,在information_schema.INNODB_TRX中无法查看,但可以通过performance_schema.events_statements_current查询。 [^3]: 该查询通过连接多个系统视图来获取阻塞信息。 [^4]: 如果阻塞查询为空,可能需要调整performance_schema_events_statements_history_size。 </think>### 如何在MySQL中查看阻塞的SQL语句 以下是查看MySQL阻塞SQL的完整方法,包含实战案例和注意事项: #### 方法1:实时阻塞查询(推荐) ```sql SELECT btrx.trx_id AS 被阻塞事务ID, TIMEDIFF(NOW(), btrx.trx_wait_started) AS 阻塞持续时间, btrx.trx_mysql_thread_id AS 被阻塞线程ID, btrx.trx_query AS 被阻塞SQL, trx.SQL_TEXT AS 阻塞源SQL FROM information_schema.INNODB_TRX btrx LEFT JOIN information_schema.innodb_lock_waits bw ON btrx.trx_id = bw.requesting_trx_id LEFT JOIN ( SELECT trx.trx_id, trx.trx_mysql_thread_id, esc.SQL_TEXT FROM information_schema.INNODB_TRX trx JOIN performance_schema.threads t ON trx.trx_mysql_thread_id = t.PROCESSLIST_ID JOIN performance_schema.events_statements_current esc ON esc.thread_id = t.THREAD_ID ) trx ON bw.blocking_trx_id = trx.trx_id WHERE btrx.trx_state = 'LOCK WAIT'; ``` **输出示例**: ``` +------------------+-------------------+------------------+-------------------------------------+---------------------------+ | 被阻塞事务ID | 阻塞持续时间 | 被阻塞线程ID | 被阻塞SQL | 阻塞源SQL | +------------------+-------------------+------------------+-------------------------------------+---------------------------+ | 12345 | 00:05:23 | 42 | UPDATE orders SET status=1 WHERE id=100 | DELETE FROM orders WHERE id=100 | +------------------+-------------------+------------------+-------------------------------------+---------------------------+ ``` #### 方法2:历史阻塞分析 当阻塞SQL已执行完成时: ```sql -- 1. 增大历史记录缓存 SET GLOBAL performance_schema_events_statements_history_size = 10000; -- 2. 查询历史阻塞 SELECT thr.processlist_id AS 阻塞线程ID, stmt.SQL_TEXT AS 阻塞SQL, thr.PROCESSLIST_TIME AS 执行时长(秒) FROM performance_schema.events_statements_history stmt JOIN performance_schema.threads thr ON stmt.thread_id = thr.thread_id WHERE stmt.SQL_TEXT LIKE '%UPDATE%' -- 替换为实际关键词 AND thr.PROCESSLIST_TIME > 10; -- 长时间运行查询 ``` #### 关键技巧: 1. **阻塞源识别**:方法1能精准定位阻塞源头SQL和被阻塞SQL[^3] 2. **历史阻塞处理**:当`阻塞源SQL`为空时,增大`performance_schema_events_statements_history_size`[^4] 3. **事务分析**:补充查询查看未提交事务: ```sql SELECT * FROM information_schema.INNODB_TRX WHERE trx_state = 'RUNNING' AND trx_started < NOW() - INTERVAL 5 MINUTE; ``` #### 注意事项: 1. 需要开启performance_schema(默认开启) 2. 监控长时间运行事务:`trx_started`超过5分钟应重点检查[^2] 3. 生产环境建议定期检查锁等待: ```sql SHOW ENGINE INNODB STATUS; -- 查看LATEST DETECTED DEADLOCK部分 ``` ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值