浅谈mysql中不同事务隔离级别下数据的显示效果
事 务是一组原子性的SQL查询语句,也可以被看做一个工作单元。如果数据库引擎能够成功地对数据库应用所有的查询语句,它就会执行所有查询,如果任何一条查 询语句因为崩溃或其他原因而无法执行,那么所有的语句就都不会执行。也就是说,事务内的语句要么全部执行,要么一句也不执行。
consisitency:一致性,事务执行前的总和和事务执行后的总和是不变的
isolation:隔离性, 某个事务的结果只有在完成之后才对其他事务可见
durability:持久性,一旦事务成功完成,系统必须保证任何故障都不会引起事务表现出不一致性
事务的状态:
活动
部分提交
失败
中止
提交
事务在某一时刻,一定处于上边五种状态中的一种,事务各状态之间的转换如下所示:
幻读(Phantom Read):在一个事务的两次查询中数据不一致,例如有一个事务查询了几列(Row)数据,而另一个事务却在此时插入了新的几列数据,先前的事务在接下来的查询中,就会发现有几列数据是它先前所没有的。
多版本并发控制: Multiversion concurrency control,MVCC
每个用户操作数据时都是源数据的时间快照,当用户操作完成后,依据各快照的时间点在合并到源数据中
页锁:锁定某个页
行锁:锁定某行
上边之所以介绍那么多理论知识,是为了便于理解。在上边的表格中已经列出来了,在不同隔离级别下,数据的显示效果可能出现的问题,现在在linux上安装好mysql,通过我们的实验来一起看一下在不同隔离级别下数据的显示效果吧。
本次实验的所有操作均在虚拟机中完成,通过Xmanager连接虚拟机,然后打开两个会话连接,在两个会话中,同时更改隔离级别,然后查看数据的显示效果。
次实验中mysql采用源码编译安装的方式安装mysql,你也可以使用rpm包的方式直接安装mysql。具体源码安装的方式及过程,这里不再演示,在
前面的博客中,我已经介绍了很多次。如果你采用源码编译安装的方式,不知道如何安装mysql,可参看我以前写的博客,里边都有介绍。采用源码编译安装的
方式,在mysql的配置文件中,最好启用每表一个表空间。这里我们直接启用。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
|
[root@mysql ~] # mysql -uroot -p #使用该命令进入mysql,因为没有设置密码,在要求输入密码时直接按回车键即可 Enter password: Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 2 Server version: 5.6.10 MySQL Community Server (GPL) Copyright (c) 2000, 2013, Oracle and /or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and /or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> show variables like '%iso%' ; #查看mysql默认的事务隔离级别,默认为可重读。也可以使用select @@tx_isolation命令查看 +-----------------+------------------+ | Variable_name | Value | +-----------------+------------------+ | tx_isolation | REPEATABLE-READ | +-----------------+------------------+ 1 row in set (0.36 sec) mysql> show databases; #查看系统已经存在的数据库 +---------------------+ | Database | +---------------------+ | information_schema | | mysql | | performance_schema | | test | +---------------------+ 4 rows in set (0.00 sec) 现在导入我们实验所使用的数据库。 [root@mysql ~] # mysql < jiaowu.sql #导入实验所用的jiaowu数据库 [root@mysql ~] # mysql -uroot -p Enter password: Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 7 Server version: 5.6.10 MySQL Community Server (GPL) Copyright (c) 2000, 2013, Oracle and /or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and /or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> show databases; #查看导入的jiaowu数据库是否存在 +----------------------+ | Database | +----------------------+ | information_schema | | jiaowu | | mysql | | performance_schema | | test | +----------------------+ 5 rows in set (0.01 sec) |
我
们在mysql命令界面下,没有明确启用事务时,输入的每个命令都是直接提交的,因为mysql中有个变量的值,可实现自动提交。也就是说我们每输入一个
语句,都会自动提交,这会产生大量的磁盘IO,降低系统的性能。在我们做实验时,因为我们要明确使用事务,所以,建议关闭自动提交的功能,如果不关闭也没
有关系,但是如果你没有明确使用事务,想要做下边的实验,那就需要关闭此功能了。这里,我们明确使用事务,且关闭自动提交功能。假如你关闭了自动提交功
能,需明确使用事务,否则你输入的所有语句会被当成一个事务进行处理。命令如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
mysql> select @@autocommit; #查看该值,为1表示启动自动提交 +--------------+ | @@autocommit | +--------------+ | 1 | +--------------+ 1 row in set (0.00 sec) mysql> set autocommit=0; #关闭自动提交功能 Query OK, 0 rows affected (0.00 sec) mysql> select @@autocommit; #重新查看该值,为0表示关闭自动提交功能 +--------------+ | @@autocommit | +--------------+ | 0 | +--------------+ 1 row in set (0.00 sec) |
现在打开两个会话,在这两个会话中分别进入mysql,首先记得要就修改两个回话中的autocommit变量,关闭自动提交功能,然后查看事务的隔离级别,默认为REPEATABLE-READ。在两个会话中都需要修改隔离级别。我们先从最低的隔离级别开始演示。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
mysql> select @@tx_isolation; +-------------------+ | @@tx_isolation | +-------------------+ | REPEATABLE-READ | +-------------------+ 1 row in set (0.00 sec) mysql> set tx_isolation= 'read-uncommitted' ; #修改隔离级别,将隔离级别可重读改为读未提交 Query OK, 0 rows affected (0.00 sec) mysql> select @@tx_isolation; +-------------------+ | @@tx_isolation | +-------------------+ | READ-UNCOMMITTED | +-------------------+ 在两个回话中,修改完隔离级别后,使用导入的数据库,用tutors表来验证显示效果。 mysql> use jiaowu; #使用jaiowu数据库 Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A Database changed mysql> show tables; #查看该数据库中都有那些表 +-------------------+ | Tables_in_jiaowu | +-------------------+ | courses | | scores | | students | | tutors | +-------------------+ 4 rows in set (0.00 sec) |
在
会话1中,我们来修改tutors中的数据,在会话2中我们来查看数据,看会是什么情况。本打算使用tutors表来演示下边的实验,但修改完数据截图时
比较麻烦,所以,自己就写了个脚本,比着tutors表的各字段创建了一个新表teachers。脚本写的有点拙劣,有兴趣可自己动手写个更好的脚本来实
现创建及插入数据。创建表及插入数据的脚本如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
#!/bin/bash # #Author: hulunbeier, http://lq2419.blog.51cto.com/ #Description: creating table and inserting data # let B=0 mysql -e "use jiaowu;create table teachers like tutors;" read -p "Input a number to create NUMBER data. You choice : " NUM #执行该脚本是,会让输入一个数字,因为是实验,所以我们这里进插入5行数据,读者可自行修改 for I in ` seq 1 $NUM`; do NAME=tech$I A=` echo $RANDOM /365 | bc ` until [ $A - ge 40 ] && [ $A - le 100 ]; do A=` echo $RANDOM /365 | bc ` done B=` echo $RANDOM%2 | bc ` if [ $B = 0 ]; then GD=F else GD=M fi mysql -e "insert into jiaowu.teachers (Tname,Gender,Age) values ('$NAME','$GD',$A);" echo "create tech$I success." done |
执行上边的脚本即可创建相应表及插入数据。查看下我们创建的新表是否成功,里边是否有数据。查询命令及显示结果如下所示:
创建的新表已经存在,且插入数据也已成功,现在我们就用teachers表来演示以下各实验。演示实验从低隔离级别开始,到高隔离级别结束。
首先,修改两个会话中的自动提交功能,将其关闭,然后修改系统默认的隔离级别,从低级别开始,将默认的可重读改为读未提交。
以
上修改在两个会话中完成后,我们明确启动事务,查询下表中的所有数据信息,显示TID为5的老师的年龄为61,然后在会话1中更新teachers表中
TID为5的老师的年龄,将原来的61改为50,接着,在两个会话中在重新查询下所有的数据,看TID为5的老师的年龄是多少。命令及显示效果如下所示:
当
我们在会话1中使用rollback回滚之后,再在两个会话中查看数据,发现还是61。从上边两个会话的显示效果,可以看到,在隔离级别为读未提交时,当
我们开启一个事务时,在该事务中修改了某个数据行的信息,且在该事务中,并未提交,但在另一个事务中,如果都是对同一个数据集的操作,会发现我们前后两次
查询的结果不一样了,在同一个事务中,两次查询得到的结果不一样,这种情况是不允许出现。此时就出现了脏读、不可重复读及幻读的现象。
现
在,在会话1中,我们使用commit命令提交事务,然后再会话2中,查看下显示效果,看又是怎么样的。结果会发现,在会话2中,TID为5的老师的年龄
变成了40。从上边的显示效果,会发现,当隔离级别为read-committed(读提交)时,当我们在会话1中开启事务,并修改了某一行数据的信息
时,在会话1中可以看到修改后的效果,但在会话2中并不会看到修改后的结果。当我们在会话1中提交事务后,在再会话2中查询,会发现,跟我们上次查询的不
一样了,显示的是会话1修改后的结果。在该隔离级别下,虽然可以避免脏读的现象发生,但还是会出现不可重复读和幻读的现象。
从
上边的显示结果会发现,在该隔离级别下,当我们在会话1中修改了某个值时,会话1会立即显示修改后的结果,而会话2中不会显示。当我们在会话1中提交事务
后,得到永久结果,在会话1中在查看,还是修改后的结果,但在会话2中,还是原来的结果。但当我们在会话2中提交事务后,再来查询,发现是会话1中修改后
的结果,在会话2中,我们没做任何修改,我一提交事务,发现,数据竟然变了。起码,事务提交前和提交后看到的数据是不一样的。此时就出现了幻读的现象。
在
上边的显示效果中,发现,在可串行隔离级别下,当我们启动两个事务时,如果在其中一个事务中,修改了某个数据行,在另一个事务中,我们是无法查询到该数据
集的信息的,也就是说系统不会显示出任何信息,除非在修改的事务中,我们提交了,或者是执行了rollback命令。假如在修改的事务中,我们既没有执行
commit命令提交,也没有执行rollback命令回滚,那么,在另一个事务中,当我们查询时,会一直卡着不动,直到锁时间超时,然后提示我们重新开
启事务。在上图中,发现,在会话1中,当我们启动一个事务,并修改了一个数据后,在会话2中,我们是不能查询到任何信息的,当我们在会话1中执行了
rollback命令后,会话2中才会显示查询结果,此时的查询所用时间会比以前查询所用时间长很多。因为在可串行级别下,是不允许通知开启多个事务的,
或者说是不允许对同一个数据集执行任何操作的。此时,既不会出现脏读、不可重复读,也不会出现幻读现象。但是此时的并发性会受影响。
上所述,在低隔离级别下,当有多个事务并发执行时,虽然会产生很多问题,如脏读、不可重复读、幻读等现象,但事务的并发性较好,可同时执行多个事务;在高
隔离级别下,当有多个事务并发执行时,因在高隔离级别下,不支持多事务并发执行,虽然不会出现诸如脏读、不可重复读及幻读等现象,但并发性较低。
InnoDB默认的隔离级别是repeatable-read(可重读),而在大多数的数据库中,oracle等多数数据库,一般默认的隔离级别是
read-committed(读提交)。一般来说在实际应用中,除了在银行、股票等对数据安全要求较高的场景外,必须使用较高隔离级别外,其他对数据要
求不高的场合,可采用低隔离级别,以提高并发性。然而,究竟哪种隔离级别更适合,那就需要看你对数据的安全性要求有多高了。
本文出自 “呼伦贝尔—写在人生路上” 博客,请务必保留此出处http://lq2419.blog.51cto.com/1365130/1226000
浅谈mysql中不同事务隔离级别下数据的显示效果的更多相关文章
- mysql中不同事务隔离级别下数据的显示效果--转载
事务是一组原子性的SQL查询语句,也可以被看做一个工作单元.如果数据库引擎能够成功地对数据库应用所有的查询语句,它就会执行所有查询,如果任何一条查询语句因为崩溃或其他原因而无法执行,那么所有的语句就都 ...
- 在MySQL中设置事务隔离级别有2种方法:
在MySQL中设置事务隔离级别有2种方法: 1 在my.cnf中设置,在mysqld选项中如下设置 [mysqld] transaction-isolation = READ-COMMITTED 2 ...
- mysql中的事务隔离级别
事务是逻辑上的一组操作,要么都执行,要么都不执行. 事务最经典的.经常被拿出来说的例子就是转账了.假如小花要给小白转账1000元,这个转账会涉及到两个关键操作就是:将小花的余额-1000,将小白的余额 ...
- MySQL InnoDB中的事务隔离级别和锁的关系
前言: 我们都知道事务的几种性质,数据库为了维护这些性质,尤其是一致性和隔离性,一般使用加锁这种方式.同时数据库又是个高并发的应用,同一时间会有大量的并发访问,如果加锁过度,会极大的降低并发处理能力. ...
- 重新学习MySQL数据库9:Innodb中的事务隔离级别和锁的关系
重新学习MySQL数据库9:Innodb中的事务隔离级别和锁的关系 Innodb中的事务隔离级别和锁的关系 前言: 我们都知道事务的几种性质,数据库为了维护这些性质,尤其是一致性和隔离性,一般使用加锁 ...
- 谈谈MySQL支持的事务隔离级别,以及悲观锁和乐观锁的原理和应用场景?
在日常开发中,尤其是业务开发,少不了利用 Java 对数据库进行基本的增删改查等数据操作,这也是 Java 工程师的必备技能之一.做好数据操作,不仅仅需要对 Java 语言相关框架的掌握,更需要对各种 ...
- 第36讲 谈谈MySQL支持的事务隔离级别,以及悲观锁和乐观锁的原理和应用场景
在日常开发中,尤其是业务开发,少不了利用 Java 对数据库进行基本的增删改查等数据操作,这也是 Java 工程师的必备技能之一.做好数据操作,不仅仅需要对 Java 语言相关框架的掌握,更需要对各种 ...
- Innodb中的事务隔离级别和锁的关系
前言: 我们都知道事务的几种性质,数据库为了维护这些性质,尤其是一致性和隔离性,一般使用加锁这种方式.同时数据库又是个高并发的应用,同一时间会有大量的并发访问,如果加锁过度,会极大的降低并发处理能力. ...
- Innodb中的事务隔离级别和锁的关系(转)
原文:http://tech.meituan.com/innodb-lock.html 前言: 我们都知道事务的几种性质,数据库为了维护这些性质,尤其是一致性和隔离性,一般使用加锁这种方式.同时数据库 ...
随机推荐
- 使用openssl库实现des,3des加密
原文地址: 使用openssl库实现des,3des加密 主要是调整了一下格式,以及一些变量的类型,以解决在VC2008下无法编译通过的问题. #include <stdio.h> #in ...
- 域名的MX设置及校验方法
国内私募机构九鼎控股打造APP,来就送 20元现金领取地址:http://jdb.jiudingcapital.com/phone.html内部邀请码:C8E245J (不写邀请码,没有现金送)国内私 ...
- [Practical Git] Compare file changes with git diff
It can be helpful to see the changes between two sets of code; git diff lets us do this by comparing ...
- iOS开发——网络编程OC篇&Socket编程
Socket编程 一.网络各个协议:TCP/IP.SOCKET.HTTP等 网络七层由下往上分别为物理层.数据链路层.网络层.传输层.会话层.表示层和应用层. 其中物理层.数据链路层和网络层通常被称作 ...
- C++类的定义之作用域
每个类都定义了自己的新作用域和唯一的类型.在类的定义体内声明内成员,将成员名引入类的作用域.两个不同的类具有两个不同的类作用域. 例如: Class First { int memi; double ...
- 配置SQL Server 2008管理器
SQl Server 配置管理器(简称为配置管理器)包含了SQL Server 2008服务.SQL Server 2008网络配置和SQL Native Client配置3个工具,供数据库管理人员做 ...
- 结合 category 工作原理分析 OC2.0 中的 runtime
绝大多数 iOS 开发者在学习 runtime 时都阅读过 runtime.h 文件中的这段代码: struct objc_class { Class isa OBJC_ISA_AVAILABILI ...
- Java基础知识强化之多线程笔记05:Java程序运行原理 和 JVM的启动是多线程的吗
1. Java程序运行原理: Java 命令会启动Java 虚拟机,启动 JVM,等于启动了一个应用程序,也就是启动了一个进程.该进程会自动启动一个 “主线程” ,然后主线程去调用某个类的 m ...
- Android(java)学习笔记133:ListViewProject案例(ListView + BaseAdapter + CheckBox)
这个案例可能稍微复杂一点,我会讲述详细一点: 1.首先是AndroidManifest.xml: <?xml version="1.0" encoding="utf ...
- multithread synchronization use mutex and semaphore
#include <malloc.h> #include <pthread.h> #include <semaphore.h> struct job { /* Li ...