文档章节

MySQL的事务处理以及隔离级别

半夏alvin
 半夏alvin
发布于 2015/01/06 15:16
字数 2274
阅读 94
收藏 0

最近接触了数据并发这块,就来说下关于数据的事务处理以及隔离级别的相关知识。

1. 事务必须满足4个条件:

原子性(Autmic):事务在执行性,要做到“要么不做,要么全做!”,就是说不允许事务部分得执行。即使因为故障而使事务不能完成,在rollback时也要消除对数据库得影响!
一致性(Consistency):事务操作之后,数据库所处的状态和业务规则是一致的;比如a,b账户相互转账之后,总金额不变!
隔离性(Isolation):如果多个事务并发执行,应像各个事务独立执行一样!
持久性(Durability):事务提交后被持久化到数据库.

2. MySQL处理事务有两种方法

1) 用BEGIN,ROLLBACK,COMMIT来实现
开始:START TRANSACTION或BEGIN语句可以开始一项新的事务
提交:COMMIT可以提交当前事务,是变更成为永久变更
回滚:ROLLBACK可以回滚当前事务,取消其变更

2) 直接用set来改变mysql的自动提交模式
MYSQL默认是自动提交的,也就是你提交一个QUERY,它就直接执行!
我们可以通过set autocommit=0 禁止自动提交 
set autocommit=1 开启自动提交来实现事务的处理。
但注意当你用 set autocommit=0 的时候,你以后所有的SQL都将做为事务处理,直到你用commit确认或rollback结束,并且只用于当前连接
※ MYSQL中只有INNODB和BDB类型的数据表才能支持事务处理!其他的类型是不支持!

3. 事务中一些有问题的读取:脏读,不可重复读,幻读

※脏读:一个事务读取了另一个未提交的并行事务写的数据。
(事务T1更新了一行记录的内容,但是并没有提交所做的修改。事务T2读取更新后的行,然后T1执行回滚操作,取消了刚才所做的修改。现在T2所读取的行就无效了。)
 
exp:
小明的分数为89,事务A中把他的分数改为98,但事务A尚未提交。
与此同时,事务B正在读取小明的分数,读取到小明的分数为98。
随后,事务A发生异常,而回滚了事务。小明的分数又回滚为89。
最后,事务B读取到的小明的分数为98的数据即为脏数据,事务B做了一次脏读。
 (大部分数据库缺省的事物隔离级别都不会出现这种状况)

※不可重复读:一个事务重新读取前面读取过的数据,发现该数据已经被另一个已提交的事务修改过。
 (事务T1读取一行记录,紧接着事务T2修改了T1刚才读取的那一行记录。然后T1又再次读取这行记录,发现与刚才读取的结果不同。这就称为“不可重复”读,因为T1原来读取的那行记录已经发生了变化。)
exp:
在事务A中,读取到小明的分数为89,操作没有完成,事务还没提交。
与此同时,事务B把小明的分数改为98,并提交了事务。
随后,在事务A中,再次读取小明的分数,此时工资变为98。在一个事务中前后两次读取的结果并不致,导致了不可重复读。

※幻读:一个事务重新执行一个查询,返回一套符合查询条件的行,发现这些行因为其他最近提交的事务而发生了改变。
 (事务T1读取一条指定的WHERE子句所返回的结果集。然后事务T2新插入 一行记录,这行记录恰好可以满足T1所使用的查询条件中的WHERE 子句的条件。然后T1又使用相同的查询再次对表进行检索,但是此时却看到了事务T2刚才插入的新行。这个新行就称为“幻像”,因为对T1来说这一行就像突 然出现的一样。)
exp:
目前分数为90分以上的的学生有15人,事务A读取所有分数为90分以上的的学生人数有15人。
此时,事务B插入一条分数为99的学生记录。
这是,事务A再次读取90分以上的的学生,记录为16人。此时产生了幻读。
(大部分数据库缺省的事物隔离级别都会出现这种状况,此种事物隔离级别将带来表级锁)

4. 事务隔离级别的描述

从级别低到高依次为:
READ UNCOMMITTED: 幻像读、不可重复读和脏读都允许。
READ COMMITTED: 允许幻像读、不可重复读,但不允许脏读。
REPEATABLE READ: 允许幻像读,但不允许不可重复读和脏读。InnoDB默认级别
SERIALIZABLE: 幻像读、不可重复读和脏读都不允许。

ORACLE默认的是 READ COMMITTED。
MYSQL默认的是 REPEATABLE READ。
但是InnoDB的可重复读隔离级别和其他数据库的可重复读是有区别的,不会造成幻象读(phantom read)。
ORACLE数据库支持 READ COMMITTED 和 SERIALIZABLE ,不支持 READ UNCOMMITTED 和 REPEATABLE READ 。

如果数据库的隔离级别为REAE_UNCOMMITTED, 则其他线程可以看到未提交的数据, 因此就出现脏读;
如果数据库隔离级别设为READ_COMMITTED,即没提交的数据别人是看不见的,就避免了脏读;但是,正在读取的数据只获得了读取锁,读完之后就解锁,不管当前事务有没有结束,这样就容许其他事务修改本事务正在读取的数据。导致不可重复读。
如果数据库隔离级别设置为REPEATABLE READ,因为对正在操作的数据加锁,并且只有等到事务结束才放开锁, 则可以避免不可重复读;
REPEATABLE READ只能保证正在被本事务操作的数据不被其他事务修改,却无法保证有其他事务提交新的数据。 则有可能线程1在操作表T1的时候(特别是统计性的事务),其他线程仍然可以提交新数据到表T1,这样会导致线程1两次统计的结果不一致,就像发生幻觉一样。
SERIALIZABLE因为获得范围锁,且事务是一个接着一个串行执行,则保证了不会发生幻读。
由此可见,隔离级别越高,受其他事物干扰越少,并发性能越差。

5. 修改事务隔离级别

在MySQL中默认事务隔离级别是可重复读(Repeatable read).可通过SQL语句查询;
查看InnoDB系统级别的事务隔离级别:SELECT @@global.tx_isolation;
查看InnoDB会话级别的事务隔离级别:SELECT @@tx_isolation;


修改事务隔离级别:
mysql> set global transaction isolation level read committed;
mysql> set session transaction isolation level read committed;

6. MySQL数据库下测试结果


1)并发更新, 表tab1 的一条记录id=1 num=1,两个session分别执行事务1,2
分别输入下面的语句

事务1 (session1) :

    start transaction;

    update tab1 set num=num+1 where id=1;

=========

一条记录被更新,select发现num=2;

事务2 (session2):

    start transaction;

    update tab1 set num=num+1 where id=1;

=========

事务2会被阻塞,然后session1输入commit;提交事务1。此时事务2更新成功。

session1 select一下会发现num还是2(不允许脏读 );session2 select 一下 num 为3(update可以得到最新提交过的数据然后更新,但是如果没有update,一直是select 的话select得到的num一直是1 ),然后commit;

session1 select 发现num为3 ,session2 select 发现num为3;

所以,事务中update是有行写锁(排他锁)的,不会发生: 脏读和不可重复读(对于自身有update的事务,update之后是可以读到最新数据的,这属于例外?^_^ )

2)关于幻象读 ,innodb默认事务隔离级别是不会出现的;摘自网上,测试通过:

mysql> set autocommit=off;
Query OK, 0 rows affected (0.00 sec)

session 1 创建表并插入测试数据

mysql> create table test(i int) engine=innodb;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into test values(1);
Query OK, 1 row affected (0.00 sec)
session 2 查询,没有数据,正常,session1没有提交,不允许脏读

mysql> select * from test;
Empty set (0.00 sec)
session 1 提交事务

mysql> commit;
Query OK, 0 rows affected (0.00 sec)
session 2 查询,还是没有数据,没有产生幻象读

mysql> select * from test;
Empty set (0.00 sec)

3)最后,现在应该知道数据库并发控制并不复杂,交给数据库的事务就行,mysql 选用innodb引擎,不会出现“不可重复读”。

在实际使用的过程中,会碰到多用户并发操作数据库导致数据错误的问题,解决方案下次再单独写篇博客记录。

© 著作权归作者所有

共有 人打赏支持
半夏alvin
粉丝 41
博文 48
码字总数 43348
作品 0
浦东
程序员
私信 提问
mysql 开发进阶篇系列 6 锁问题

一.概述   在数据库中,数据是属于共享资源,为了保证并发访问的一致性,有效性,产生了锁。接下来重点讨论mysql锁机制的特点,常见的锁问题,以及解决mysql锁问题的一些方法或建议。 相比...

花阴偷移
2018/07/23
0
0
MySQL专题8之MySQL 事务、ALTER命令

1、MySQL 事务 - MySQL事务主要用于处理操作量大,复杂度高的数据。比如说,在人员管理系统上,你删除一个人员,你即需要删除人员的基本资料,也要删除和该人员的相关的信息。比如信箱,文章...

极客微信条
2017/11/18
0
0
mysql事务和锁 SELECT FOR UPDATE

事务: 当然有的人用begin /begin work .推荐用START TRANSACTION 是SQL-99标准启动一个事务。 当用set autocommit = 0 的时候,你以后所有的sql都将作为事务处理,直到你用commit确认或 ro...

SibylY
2016/08/22
172
0
浅谈数据库事物的四大特性(ACID)以及事物的隔离级别

事物的四大特性  如果一个数据库声称支持事务的操作,那么该数据库必须要具备以下四个特性: ⑴ 原子性(Atomicity)   原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚,因...

HenrySun
2016/08/20
107
0
数据库事务的四大特性以及事务的隔离级别

本篇讲诉数据库中事务的四大特性(ACID),并且将会详细地说明事务的隔离级别。   如果一个数据库声称支持事务的操作,那么该数据库必须要具备以下四个特性: ⑴ 原子性(Atomicity)  原...

1071954237
2017/10/27
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Linux iptables之mangle表使用案例

mangle表的用途 mangle表的主要功能是根据规则修改数据包的一些标志位,以便其他规则或程序可以利用这种标志对数据包进行过滤或策略路由。 mangel表使用示例 示例1-策略路由1 内网的客户机通...

月下狼
37分钟前
2
0
OSChina 周日乱弹 —— 兼职我想去学学布偶戏

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @clouddyy : 《火炎 - 女王蜂》 《火炎 - 女王蜂》 手机党少年们想听歌,请使劲儿戳(这里) @小鱼丁 :还在睡觉突然接到一个小哥哥电话“x...

小小编辑
49分钟前
46
3
租房软件隐私保护如同虚设

近日,苏州市民赵先生向江苏新闻广播新闻热线025-84658888反映,他在“安居客”手机应用软件上浏览二手房信息,并且使用该软件自动生成的虚拟号码向当地一家中介公司进行咨询。可电话刚挂不久...

linux-tao
今天
3
0
分布式项目(五)iot-pgsql

书接上回,在Mapping server中,我们已经把数据都整理好了,现在利用postgresql存储历史数据。 iot-pgsql 构建iot-pgsql模块,这里我们写数据库为了性能考虑不在使用mybatis,换成spring jd...

lelinked
今天
6
0
一文分析java基础面试题中易出错考点

前言 这篇文章主要针对的是笔试题中出现的通过查看代码执行结果选择正确答案题材。 正式进入题目内容: 1、(单选题)下面代码的输出结果是什么? public class Base { private Strin...

一看就喷亏的小猿
今天
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部