MySQL 版本:5.7

安装环境:MAC OS

一、测试数据

测试数据库:test;测试表:tt

CREATE TABLE `tt` (
`id` int(11) DEFAULT NULL,
`name` varchar(100) DEFAULT NULL,
KEY `name_idx` (`name`),
KEY `id_idx` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

插入测试数据:

insert into tt value(1, "a”);
insert into tt value(1, "b”);
insert into tt value(2, “b");

二、事务隔离级别设置

1、查询当前事务隔离级别

mysql> select @@transaction_isolation;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| READ-UNCOMMITTED |
+-------------------------+

2、设置当前事务隔离级别

set global transaction_isolation = 'read-uncommitted';

设置隔离级别后,后续开启的连接 Session 才会生效。

三、读未提交(READ-UNCOMMITTED)

开启两个连接 Session:

Session 1 Session 2

开启事务,更新 id 为 2 的记录 name 为 “ss" ,保持事务未提交:

Query OK, 0 rows affected (0.00 sec)
mysql> select * from tt;
+------+------+
| id | name |
+------+------+
| 1 | a |
| 1 | b |
| 2 | b |
+------+------+
3 rows in set (0.00 sec)
mysql> update tt set name = 'ss' where id = 2;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
 
 

开启事务,查询 id 为 2 的记录 name 值:

mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from tt where id = 2;
+------+------+
| id | name |
+------+------+
| 2 | ss |
+------+———+ 

事务 2 可以查询到事务 1 未提交的数据变更。对于事务 2 来说,这条数据是脏数据。

四、读已提交(READ-COMMITTED)

解决 READ-UNCOMMITTED 隔离级别下产生的脏读现象。

设置事务隔离级别:

mysql> set global transaction_isolation = 'read-committed';
Query OK, 0 rows affected (0.00 sec)

重新开启测试 Session,查询事务隔离级别:

mysql> select @@transaction_isolation;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| READ-COMMITTED |
+-------------------------+
 
Session 1 Session 2
开启事务,更新 id 为 2 的记录 name 为 “ssr”:
mysql> begin;
Query OK, 0 rows affected (0.00 sec) mysql> update tt set name = 'ssr' where id = 2;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1 Changed: 1 Warnings: 0 mysql> select * from tt where id = 2;
+------+------+
| id | name |
+------+------+
| 2 | ssr |
+------+------+
1 row in set (0.01 sec)
 
 
查询数据,无法查询到 事务 1 未提交的数据:
mysql> begin;
Query OK, 0 rows affected (0.00 sec) mysql> select * from tt where id = 2;
+------+------+
| id | name |
+------+------+
| 2 | b |
+------+------+
1 row in set (0.00 sec) 
提交事务:
mysql> commit ;
Query OK, 0 rows affected (0.01 sec)
 
 
查询数据,得到的是事务 1 中已提交的数据变更:
mysql> select * from tt where id = 2;
+------+------+
| id | name |
+------+------+
| 2 | ssr |
+------+------+
1 row in set (0.00 sec)
 
对于事务 2 来说,在事务 1 提交前后,获取到的数据是不一样的,即不可重复读问题。

五、可重复读(REPEATABLE-READ)

解决 READ-COMMITTED 隔离级别下产生的不可重复读现象。

Session 1中 设置事务隔离级别:

mysql> set global transaction_isolation = 'repeatable-read';
Query OK, 0 rows affected (0.01 sec)

重新开启事务,查询隔离级别:

mysql> select @@transaction_isolation;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| REPEATABLE-READ |
+-------------------------+
1 row in set (0.00 sec)
Session 1 Session 2

Session 2 开启事务,查询数据:

mysql> begin;
Query OK, 0 rows affected (0.00 sec)
Database changed
mysql> select * from tt where id = 2;
+------+------+
| id | name |
+------+------+
| 2 | b |
+------+------+
1 row in set (0.00 sec)

更新 id 为 2 的记录 name 为 “ssrr”, 并提交事务:

mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> update tt set name = 'ssrr' where id = 2;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> commit;
Query OK, 0 rows affected (0.01 sec)
mysql> select * from tt where id = 2;
+------+------+
| id | name |
+------+------+
| 2 | ssrr |
+------+------+
1 row in set (0.00 sec)  

Session 2 重新查询数据:

mysql> select * from tt where id = 2;
+------+------+
| id | name |
+------+------+
| 2 | b |
+------+------+

当前数据未变。

但是问题是,事务 1 已经进行了数据变更,并且提交,事务 2 无法获取所查记录最新变更信息。

为什么事务 2 前后两次相同查询所得的数据是一样的?

一致性读(consistent read)查询模式:基于【某一时刻】的【数据快照】提供读查询结果。无论查询的数据是否被其它事务所改变。这个【某一时刻】在 repeatable-read 隔离级别下为事务中第一次执行查询操作的时间点,read-committed 隔离级别下,数据快照会在每一次执行一致性读操作时进行重置。

幻读

如何避免:加X锁

Next-key lock:Record lock + Gap lock

六、关于 Next-key lock 加锁

调整表 tt 索引及数据:

mysql> show create table tt;
+-------+-------------------------------------------------------+
| Table | Create Table |
+-------+-------------------------------------------------------+
| tt | CREATE TABLE `tt` (
`id` int(11) NOT NULL,
`name` varchar(100) DEFAULT NULL,
`age` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idx_age` (`age`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
+-------+-------------------------------------------------------+
1 row in set (0.00 sec)
mysql> select * from tt;
+-----+------+------+
| id | name | age |
+-----+------+------+
| 90 | aa | 10 |
| 102 | bb | 15 |
| 108 | cc | 20 |
| 130 | dd | 25 |
| 150 | ee | 30 |
+-----+------+------+

1、等值条件

对于使用唯一性索引:加的锁为 Record lock

Session 1 Session 2

开启事务,查询 id 为 108 记录加 X lock:

mysql> begin;
Query OK, 0 rows affected (0.00 sec) mysql> select * from tt where id = 108 for update;
+-----+------+------+
| id | name | age |
+-----+------+------+
| 108 | cc | 20 |
+-----+------+------+
1 row in set (0.01 sec)
 
 

开启事务,记录前后紧邻 gap 插入记录:

mysql> begin;
Query OK, 0 rows affected (0.00 sec) mysql> insert into tt value(106, 'bc', 16);
Query OK, 1 row affected (0.00 sec) mysql> insert into tt value(110, 'cd', 22);
Query OK, 1 row affected (0.00 sec)
记录均可成功插入

对于使用非唯一性索引:加的锁为 Record lock + Gap lock 前后紧邻 gap

:首先加锁 (15, 20],因为是非唯一索引,继续向后查找到第一个不满足条件的元素 25 加 gap lock (20, 25)

Session 1 Session 2

开启事务,查询 age 为 20 记录加 X lock:

mysql> begin;
Query OK, 0 rows affected (0.00 sec) mysql> select * from tt where age = 20 for update;
+-----+------+------+
| id | name | age |
+-----+------+------+
| 108 | cc | 20 |
+-----+------+------+
1 row in set (0.00 sec)
 
 

开启事务,记录紧邻前后 gap 插入记录:

mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> insert into tt value(106, 'bc', 18); ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction mysql> insert into tt value(110, 'cd', 22); ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

操作均被 block。

紧邻 gap 以外插入记录:

mysql> insert into tt value(100, 'ab', 12);
Query OK, 1 row affected (0.00 sec) mysql> insert into tt value(140, 'de', 27);
Query OK, 1 row affected (0.00 sec)

记录均可成功插入

对于不使用索引的:加锁为全部记录及gap

Session1
Session2

开启事务,查询 name 为 ‘cc’ 记录加 X lock:

mysql> begin;
Query OK, 0 rows affected (0.00 sec) mysql> select * from tt where name = 'cc' for update;
+-----+------+------+
| id | name | age |
+-----+------+------+
| 108 | cc | 20 |
+-----+------+------+
 
 

开启事务,各个间隙尝试插入记录:

mysql> begin;
Query OK, 0 rows affected (0.00 sec) mysql> insert into tt value(80, 'pa', 5);
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql> insert into tt value(95, 'ab', 13);
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql> insert into tt value(105, 'bc', 18);
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql> insert into tt value(120, 'cd', 23);
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql> insert into tt value(140, 'de', 28);
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql> insert into tt value(160, 'en', 35);
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

操作均被 block。

更新记录:

mysql> update tt set age = 21 where name = 'cc';
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql> update tt set age = 16 where name = 'bb';
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

操作均被 block。

MySQL 事务的隔离级别及锁操作的一点点演示的更多相关文章

  1. Mysql数据库事务的隔离级别和锁的实现原理分析

    Mysql数据库事务的隔离级别和锁的实现原理分析 找到大神了:http://blog.csdn.net/tangkund3218/article/details/51753243 InnoDB使用MV ...

  2. MySQL事务学习-->隔离级别

    MySQL事务学习-->隔离级别 6 事务的隔离级别 设置的目的 在数据库操作中,为了有效保证并发读取数据的正确性,提出的事务隔离级别. 数据库是要被广大客户所共享访问的,那么在数据库操作过程中 ...

  3. MySQL事务及隔离级别详解

    MySQL事务及隔离级别详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.MySQL的基本架构 MySQL的基本架构可以分为三块,即连接池,核心功能层,存储引擎层. 1> ...

  4. [转]MySQL事务学习-->隔离级别

    From : http://blog.csdn.net/mchdba/article/details/12837427 6 事务的隔离级别 设置的目的 在数据库操作中,为了有效保证并发读取数据的正确性 ...

  5. MySQL事务及隔离级别(读书小结)

    标签: MySQL事务 隔离 0.什么是事务? 事务是指MySQL的一些操作看做是一个不可分割的执行单元.事务的特点是要么所有操作都执行成功,要么一个都不执行.也就是如果一个事务有操作执行失败,那么就 ...

  6. MySQL事务的隔离级别

    为什么需要隔离 当多个线程都开启事务操作数据库中的数据时,数据库系统要能进行隔离操作,以保证各个线程获取数据的准确性,在介绍数据库提供的各种隔离级别之前,我们先看看如果不考虑事务的隔离性,会发生的几种 ...

  7. 高性能MySQL--innodb中事务的隔离级别与锁的关系

    最近买了<高性能MySQL>这本书回来看,从中收益颇多!我来一吐为快! 我们都知道事务,那么在什么情况下我们需要使用事务呢? 银行应用是解释事务的一个经典例子.假设一个银行的数据库有两张表 ...

  8. mysql 事务、隔离级别

    一.事务的四大特性(ACID) 1.原子性(Atomicity):事务开始后所有操作,要么全部做完,要么全部不做,不可能停滞在中间环节.事务执行过程中出错,会回滚到事务开始前的状态,所有的操作就像没有 ...

  9. MySQL——事务ACID&隔离级别

    数据库事务ACID&隔离级别 什么是事务 事务是用户定义的一个数据库操作序列.这些操作要么全执行,要么全不执行,是一个不可分割的工作单元.在关系型数据库中,事务可以是一条SQL语句,也可以是一 ...

随机推荐

  1. 「算法笔记」CRT 与 exCRT

    一.扩展欧几里得 求解方程 \(ax+by=\gcd(a,b)\). int exgcd(int a,int b,int &x,int &y){ if(!b) return x=1,y ...

  2. Capstone CS5268 Type-C转HDMI+VGA带PD快充+USB3.1扩展坞方案

    CS5268是一种高度集成的单芯片,适用于多个细分市场和显示应用,如拓展坞.扩展底座等. 2.CS5268参数说明 总则 USB Type-C规范1.2 HDMI规范v2.0b兼容发射机,数据速率高达 ...

  3. MyBatis 一级缓存实现详解及使用注意事项

    一级缓存介绍 在应用运行过程中,我们有可能在一次数据库会话中,执行多次查询条件完全相同的SQL,MyBatis提供了一级缓存的方案优化这部分场景,如果是相同的SQL语句,会优先命中一级缓存,避免直接对 ...

  4. [学习笔记] Oracle字段类型、建表语句、添加约束

    SQL语句介绍 数据定义语言(DDL),包括 CREATE. ALTER. DROP等. 数据操纵语言(DML),包括 INSERT. UPDATE. DELETE. SELECT - FOR UPD ...

  5. Python基础案例练习:制作学生信息管理系统

    一.前言 学生信息管理系统,相信大家或多或少都有做过 最近看很多学生作业都是制作一个学生信息管理系统 于是,今天带大家做一个简单的学生信息管理系统 二.开发环境: 我用到的开发环境 Python 3. ...

  6. 初识python: 继承

    继承:可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展. 通过继承创建的新类称为"子类"或"派生类". 被继承的类称为"基 ...

  7. CentOS 7安装Etherpad(在线协作编辑)

    Etherpad 是一个线上共制平台,是基于网络的实时合作文档编辑器,三.四个人可以坐在自己电脑前,同时对一份文档修改,也同时能看到其他人的修改. CentOS 7 安装 Etherpad 1.先安装 ...

  8. 安装Apache-storm-0.9.1-incubating图解教程

    注:图片如果损坏,点击文章链接:https://www.toutiao.com/i6596214331988247054/ 安装步骤 (1) 安装Zookeeper集群,可以参考前一篇文章,本文已安装 ...

  9. java基础06-变量、常量、作用域

    java基础06-变量.常量.作用域 一.变量 变量是什么:就是可以变化的量! java是一种强类型语言,每个变量都必须声明其类型. java是一种强类型语言,每个变量都是必须声明其类型. java变 ...

  10. leeetcode 20. 有效的括号

    20. 有效的括号 问题描述 给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效. 有效字符串需满足: 左括号必须用相同类型的右括号闭合. 左括号必须以正确的 ...