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. mac学习Python第一天:安装、软件说明、运行python的三种方法

    一.Python安装 从Python官网下载Python 3.x的安装程序,下载后双击运行并安装即可: Python有两个版本,一个是2.x版,一个是3.x版,这两个版本是不兼容的. MAC 系统一般 ...

  2. NetCore实现全局模型绑定异常信息统一处理

    本文主要讲解NetCore如何使用中间件捕获模型绑定的异常信息 场景 在.NET Core 中请求中,如果参数的类型错误,我们在控制器的定义的方法是不会执行的,当我们需要捕获模型绑定的异常信息时,可以 ...

  3. Codeforces 567D:One-Dimensional Battle Ships(二分)

    time limit per test : 1 second memory limit per test : 256 megabytes input : standard input output : ...

  4. 昆泰CH7511B方案|EDP转LVDS资料|CS5211pin to pin 替代CH7511B电路设计

    Chrontel的CH7511B是一种低成本.低功耗的半导体器件,它将嵌入式DisplayPort信号转换为LVDS(低压差分信号).这款创新的DisplayPort接收机带有集成LVDS发射机,专为 ...

  5. 排列组合 "n个球放入m个盒子m"问题 总结

    求,盒子都可以分成是否不能区分,和能区分,还能分成是否能有空箱子,所以一共是8种情况,我们现在来一一讨论. 1.球同,盒不同,无空箱 C(n-1,m-1), n>=m0, n<m 使用插板 ...

  6. XML解析和创建的JAXB方式

    1.说明 JAXB是Java Architecture for XML Binding, 即用于XML绑定的Java体系结构, JAXB作为JDK的一部分, 能便捷地将Java对象与XML进行相互转换 ...

  7. SpringCloud创建Config Client配置读取

    1.说明 本文详细介绍配置中心客户端使用方法, 即Config Client到Config Server读取配置, 这里以创建Config Client服务为例, 基于已经创建好的Config Ser ...

  8. mysql编译报错

    1.make报错现象 Warning: Bison executable not found in PATH 解决办法 yum -y install bison 2.make报错现象 ake Erro ...

  9. unittest_skip跳过用例执行(3)

    在执行测试用例时,有时候有些用例是不需要执行的,比如版本迭代用例弃用,测试周期短只需要执行优先级高的用例,那我们怎么办呢?难道删除这些用例?那下次执行时如果又需要执行这些用例时,又把它补回来?这样操作 ...

  10. Python 元类实现ORM

    ORM概念 ORM(Object Ralational Mapping,对象关系映射)用来把对象模型表示的对象映射到基于 SQL  的关系模型数据库结构中去.这样,我们在具体的操作实体对象的时候,就不 ...