当前位置:首页 > 文章列表 > 数据库 > MySQL > MySQL的insert会阻塞update吗

MySQL的insert会阻塞update吗

来源:51cto 2023-04-17 17:44:33 0浏览 收藏

在数据库实战开发的过程中,我们经常会遇到一些这样那样的问题,然后要卡好半天,等问题解决了才发现原来一些细节知识点还是没有掌握好。今天golang学习网就整理分享《MySQL的insert会阻塞update吗》,聊聊MySQL、Oracle、update,希望可以帮助到正在努力赚钱的你。

某银行客户在从Oracle迁移到MySQL的开发中,MySQL在READ-COMMITTED隔离级别下,出现了insert阻塞update的情况,但同样的情况下,Oracle的insert则不会阻塞update。本文通过复现该问题,分析MySQL的锁信息,确认是MySQL与Oracle在并发事务处理上的差异,在进行数据库迁移改造的程序开发应予以关注。

1.问题复现

1.1.环境准备

MySQL版本的8.0.26,隔离级别是READ-COMMITTED ,测试表t的字段a为主键。

mysql> select version();
+-----------+
| version() |
+-----------+
| 8.0.26    |
+-----------+
1 row in set (0.02 sec)

mysql> show variables like 'transaction_isolation';
+-----------------------+----------------+
| Variable_name         | Value          |
+-----------------------+----------------+
| transaction_isolation | READ-COMMITTED |
+-----------------------+----------------+
1 row in set (0.00 sec)

mysql> desc t;
+-------+------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+------+------+-----+---------+-------+
| a     | int  | NO   | PRI | NULL    |       |
| b     | int  | YES  |     | NULL    |       |
+-------+------+------+-----+---------+-------+
2 rows in set (0.01 sec)

mysql> select * from t;
+---+------+
| a | b    |
+---+------+
| 7 |    7 |
+---+------+
1 row in set (0.00 sec)

1.2. insert阻塞update的操作步骤

insert语句未提交时,update同样主键的数据会被阻塞。

session1

session2

插入一条数据(a=8)后未提交。

mysql> begin;

Query OK, 0 rows affected (0.00 sec)

mysql> insert into t values(8,8);

Query OK, 1 row affected (0.01 sec)

更改数据,条件是a=8,将会被阻塞

mysql> update t set b=0 where a=8;

2.分析原因

2.1.检查事务锁信息

mysql> select * from information_schema.innodb_trxG
*************************** 1. row ***************************
                   trx_id: 3795
                trx_state: LOCK WAIT
              trx_started: 2022-10-11 16:03:38
    trx_requested_lock_id: 139727275779216:52:4:3:139724882995456
         trx_wait_started: 2022-10-11 16:03:38
               trx_weight: 2
      trx_mysql_thread_id: 9346
                trx_query: update t set b=0 where a=8
      trx_operation_state: starting index read
        trx_tables_in_use: 1
        trx_tables_locked: 1
         trx_lock_structs: 2
    trx_lock_memory_bytes: 1128
          trx_rows_locked: 1
        trx_rows_modified: 0
  trx_concurrency_tickets: 0
      trx_isolation_level: READ COMMITTED
        trx_unique_checks: 1
   trx_foreign_key_checks: 1
trx_last_foreign_key_error: NULL
trx_adaptive_hash_latched: 0
trx_adaptive_hash_timeout: 0
         trx_is_read_only: 0
trx_autocommit_non_locking: 0
      trx_schedule_weight: 1
*************************** 2. row ***************************
                   trx_id: 3790
                trx_state: RUNNING
              trx_started: 2022-10-11 16:03:29
    trx_requested_lock_id: NULL
         trx_wait_started: NULL
               trx_weight: 3
      trx_mysql_thread_id: 9320
                trx_query: NULL
      trx_operation_state: NULL
        trx_tables_in_use: 0
        trx_tables_locked: 1
         trx_lock_structs: 2
    trx_lock_memory_bytes: 1128
          trx_rows_locked: 1
        trx_rows_modified: 1
  trx_concurrency_tickets: 0
      trx_isolation_level: READ COMMITTED
        trx_unique_checks: 1
   trx_foreign_key_checks: 1
trx_last_foreign_key_error: NULL
trx_adaptive_hash_latched: 0
trx_adaptive_hash_timeout: 0
         trx_is_read_only: 0
trx_autocommit_non_locking: 0
      trx_schedule_weight: NULL
2 rows in set (0.00 sec)

说明:通过InnoDB的事务表innodb_trx查询到thread_id=9346的事务3795正在等待锁(trx_state: LOCK WAIT),
thread_id=9320的事务3790正在执行(trx_state: RUNNING)。

mysql> select * from performance_schema.data_locksG
*************************** 1. row ***************************
              ENGINE: INNODB
      ENGINE_LOCK_ID: 139727275779216:1113:139724882998560
ENGINE_TRANSACTION_ID: 3795
           THREAD_ID: 9441
            EVENT_ID: 5000
       OBJECT_SCHEMA: testdb
         OBJECT_NAME: t
      PARTITION_NAME: NULL
   SUBPARTITION_NAME: NULL
          INDEX_NAME: NULL
OBJECT_INSTANCE_BEGIN: 139724882998560
           LOCK_TYPE: TABLE
           LOCK_MODE: IX
         LOCK_STATUS: GRANTED
           LOCK_DATA: NULL
*************************** 2. row ***************************
              ENGINE: INNODB
      ENGINE_LOCK_ID: 139727275779216:52:4:3:139724882995456
ENGINE_TRANSACTION_ID: 3795
           THREAD_ID: 9441
            EVENT_ID: 5012
       OBJECT_SCHEMA: testdb
         OBJECT_NAME: t
      PARTITION_NAME: NULL
   SUBPARTITION_NAME: NULL
          INDEX_NAME: PRIMARY
OBJECT_INSTANCE_BEGIN: 139724882995456
           LOCK_TYPE: RECORD
           LOCK_MODE: X,REC_NOT_GAP
         LOCK_STATUS: WAITING
           LOCK_DATA: 8
*************************** 3. row ***************************
              ENGINE: INNODB
      ENGINE_LOCK_ID: 139727275781640:1113:139724883017072
ENGINE_TRANSACTION_ID: 3790
           THREAD_ID: 9415
            EVENT_ID: 15467
       OBJECT_SCHEMA: testdb
         OBJECT_NAME: t
      PARTITION_NAME: NULL
   SUBPARTITION_NAME: NULL
          INDEX_NAME: NULL
OBJECT_INSTANCE_BEGIN: 139724883017072
           LOCK_TYPE: TABLE
           LOCK_MODE: IX
         LOCK_STATUS: GRANTED
           LOCK_DATA: NULL
*************************** 4. row ***************************
              ENGINE: INNODB
      ENGINE_LOCK_ID: 139727275781640:52:4:3:139724883013968
ENGINE_TRANSACTION_ID: 3790
           THREAD_ID: 9441
            EVENT_ID: 5007
       OBJECT_SCHEMA: testdb
         OBJECT_NAME: t
      PARTITION_NAME: NULL
   SUBPARTITION_NAME: NULL
          INDEX_NAME: PRIMARY
OBJECT_INSTANCE_BEGIN: 139724883013968
           LOCK_TYPE: RECORD
           LOCK_MODE: X,REC_NOT_GAP
         LOCK_STATUS: GRANTED
           LOCK_DATA: 8
4 rows in set (0.00 sec)
说明:事务3795正在等待LOCK_TYPE: RECORD,LOCK_MODE:X,REC_NOT_GAP,等待的主键值为8;
事务3790已获取主键值为8的LOCK_TYPE: RECORD,LOCK_MODE:X,REC_NOT_GAP锁。

mysql> select * from sys.innodb_lock_waitsG
*************************** 1. row ***************************
               wait_started: 2022-10-11 16:03:38
                   wait_age: 00:02:50
              wait_age_secs: 170
               locked_table: `testdb`.`t`
        locked_table_schema: testdb
          locked_table_name: t
     locked_table_partition: NULL
  locked_table_subpartition: NULL
               locked_index: PRIMARY
                locked_type: RECORD
             waiting_trx_id: 3795
        waiting_trx_started: 2022-10-11 16:03:38
            waiting_trx_age: 00:02:50
    waiting_trx_rows_locked: 1
  waiting_trx_rows_modified: 0
                waiting_pid: 9346
              waiting_query: update t set b=0 where a=8
            waiting_lock_id: 139727275779216:52:4:3:139724882995456
          waiting_lock_mode: X,REC_NOT_GAP
            blocking_trx_id: 3790
               blocking_pid: 9320
             blocking_query: NULL
           blocking_lock_id: 139727275781640:52:4:3:139724883013968
         blocking_lock_mode: X,REC_NOT_GAP
       blocking_trx_started: 2022-10-11 16:03:29
           blocking_trx_age: 00:02:59
   blocking_trx_rows_locked: 1
 blocking_trx_rows_modified: 1
    sql_kill_blocking_query: KILL QUERY 9320
sql_kill_blocking_connection: KILL 9320
1 row in set (0.01 sec)
说明:事务3795等待testdb.t上的rec_not_gap独占锁,事务3790持有该独占锁。
mysql> select distinct,* from sys.processlist where conn_id in (select trx_mysql_thread_id from information_schema.innodb_trx)G
*************************** 1. row ***************************
               thd_id: 9441
              conn_id: 9346
                 user: admin@172.17.128.73
                   db: testdb
              command: Query
                state: updating
                 time: 141
    current_statement: update t set b=0 where a=8
    statement_latency: 2.37 min
             progress: NULL
         lock_latency: 431.00 us
        rows_examined: 0
            rows_sent: 0
        rows_affected: 0
           tmp_tables: 0
      tmp_disk_tables: 0
            full_scan: NO
       last_statement: NULL
last_statement_latency: NULL
       current_memory: 140.15 KiB
            last_wait: wait/io/table/sql/handler
    last_wait_latency: Still Waiting
               source: handler.cc:3250
          trx_latency: 13.30 min
            trx_state: ACTIVE
       trx_autocommit: NO
                  pid: 9632
         program_name: mysql
*************************** 2. row ***************************
               thd_id: 9415
              conn_id: 9320
                 user: admin@172.17.128.73
                   db: testdb
              command: Sleep
                state: NULL
                 time: 801
    current_statement: NULL
    statement_latency: NULL
             progress: NULL
         lock_latency: 288.00 us
        rows_examined: 0
            rows_sent: 0
        rows_affected: 1
           tmp_tables: 0
      tmp_disk_tables: 0
            full_scan: NO
       last_statement: insert into t values(8,8)
last_statement_latency: 765.23 us
       current_memory: 218.19 KiB
            last_wait: wait/io/socket/sql/client_connection
    last_wait_latency: Still Waiting
               source: viosocket.cc:146
          trx_latency: 13.52 min
            trx_state: ACTIVE
       trx_autocommit: NO
                  pid: 9600
         program_name: mysql
说明:被阻塞事务执行的sql语句update t set b=0 where a=8
阻塞事务执行的sql语句是insert into t values(8,8)

说明:

MySQL的隔离级别是通过索引上的锁实现并发事务控制的。在READ-COMMITTED隔离级别下,session1在执行insert语句时,在主键索引上获取了a=8的行记录独占锁,以禁止插入相同主键的数据;session2如果同时插入相同的主键数据被阻塞,容易理解(Oracle也同样阻塞)。出于同样的原因session2执行update时,由于无法获取a=8的行记录独占锁,同样也会被阻塞。

2.2.验证MySQL事务未提交时已写入数据文件

验证事务未提交时,insert语句已将数据写入数据文件,索引数据也已生成。

测试表test1
mysql> CREATE TABLE `test1` (
   ->   `id` int NOT NULL AUTO_INCREMENT,
   ->   `k` int NOT NULL DEFAULT '0',
   ->   `c` char(120) NOT NULL DEFAULT '',
   ->   `pad` char(60) NOT NULL DEFAULT '',
   ->   PRIMARY KEY (`id`),
   ->   KEY `k_1` (`k`)
   -> ) ;
Query OK, 0 rows affected (0.07 sec)

开启一个事务,插入10万条数据。
mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into test1 select * from sbtest1;
Query OK, 100000 rows affected (1.44 sec)
Records: 100000  Duplicates: 0  Warnings: 0

检查表的data_length和index_length
mysql> show table status where name like 'test1'G
*************************** 1. row ***************************
          Name: test1
        Engine: InnoDB
       Version: 10
    Row_format: Dynamic
          Rows: 98712
Avg_row_length: 228
   Data_length: 22593536
Max_data_length: 0
  Index_length: 2637824
     Data_free: 4194304
Auto_increment: 100001
   Create_time: 2022-10-11 22:14:50
   Update_time: NULL
    Check_time: NULL
     Collation: utf8mb4_0900_ai_ci
      Checksum: NULL
Create_options:
       Comment:
1 rows in set (0.01 sec)

回滚insert操作
mysql> rollback;
Query OK, 0 rows affected (1.35 sec)

更新统计信息
mysql> analyze table test1;

再次检查表的data_length和index_length
mysql> show table status where name like 'test1'G
*************************** 1. row ***************************
          Name: test1
        Engine: InnoDB
       Version: 10
    Row_format: Dynamic
          Rows: 0
Avg_row_length: 0
   Data_length: 16384
Max_data_length: 0
  Index_length: 16384
     Data_free: 29360128
Auto_increment: 100001
   Create_time: 2022-10-11 22:22:36
   Update_time: NULL
    Check_time: NULL
     Collation: utf8mb4_0900_ai_ci
      Checksum: NULL
Create_options:
       Comment:
1 row in set (0.00 sec)

检查数据文件的大小
[root@host73 testdb]# ll *test1.ibd
-rw-r----- 1 greatdb greatdb 30408704 Oct 11 15:12 sbtest1.ibd
-rw-r----- 1 greatdb greatdb 33554432 Oct 11 22:24 test1.ibd

说明:

MySQL在执行insert 语句进行数据插入,未提交时,数据也已写入表的聚集索引,辅助索引也已生成。MySQL可以使用未提交数据的索引,通过锁机制实现事务的并发控制。

3.Oracle中insert没有阻塞update

在Oracle中,创建同样的测试表t,执行同样的insert和update,但insert不会阻塞update。

CREATE TABLE t (
 a int NOT NULL PRIMARY KEY ,
 b int DEFAULT NULL
);
insert into t values(7,7);
commit;

执行相同的insert和update语句。

session1

session2

SQL> insert into t values(8,8);

1 row created.

SQL> update t set b=0 where a=8;0 rows updated.

终于介绍完啦!小伙伴们,这篇关于《MySQL的insert会阻塞update吗》的介绍应该让你收获多多了吧!欢迎大家收藏或分享给更多需要学习的朋友吧~golang学习网公众号也会发布数据库相关知识,快来关注吧!

版本声明
本文转载于:51cto 如有侵犯,请联系study_golang@163.com删除
玩csgo最低什么显卡比较好玩csgo最低什么显卡比较好
上一篇
玩csgo最低什么显卡比较好
360浏览器记住密码怎么设置?360浏览器记住密码设置方法
下一篇
360浏览器记住密码怎么设置?360浏览器记住密码设置方法
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    542次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    508次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    497次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    484次学习
查看更多
AI推荐
  • 笔灵AI生成答辩PPT:高效制作学术与职场PPT的利器
    笔灵AI生成答辩PPT
    探索笔灵AI生成答辩PPT的强大功能,快速制作高质量答辩PPT。精准内容提取、多样模板匹配、数据可视化、配套自述稿生成,让您的学术和职场展示更加专业与高效。
    10次使用
  • 知网AIGC检测服务系统:精准识别学术文本中的AI生成内容
    知网AIGC检测服务系统
    知网AIGC检测服务系统,专注于检测学术文本中的疑似AI生成内容。依托知网海量高质量文献资源,结合先进的“知识增强AIGC检测技术”,系统能够从语言模式和语义逻辑两方面精准识别AI生成内容,适用于学术研究、教育和企业领域,确保文本的真实性和原创性。
    22次使用
  • AIGC检测服务:AIbiye助力确保论文原创性
    AIGC检测-Aibiye
    AIbiye官网推出的AIGC检测服务,专注于检测ChatGPT、Gemini、Claude等AIGC工具生成的文本,帮助用户确保论文的原创性和学术规范。支持txt和doc(x)格式,检测范围为论文正文,提供高准确性和便捷的用户体验。
    30次使用
  • 易笔AI论文平台:快速生成高质量学术论文的利器
    易笔AI论文
    易笔AI论文平台提供自动写作、格式校对、查重检测等功能,支持多种学术领域的论文生成。价格优惠,界面友好,操作简便,适用于学术研究者、学生及论文辅导机构。
    38次使用
  • 笔启AI论文写作平台:多类型论文生成与多语言支持
    笔启AI论文写作平台
    笔启AI论文写作平台提供多类型论文生成服务,支持多语言写作,满足学术研究者、学生和职场人士的需求。平台采用AI 4.0版本,确保论文质量和原创性,并提供查重保障和隐私保护。
    35次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议隐私政策
返回登录
  • 重置密码