MySQL的事务处理及隔离级别

932 阅读5分钟

要想知道什么是数据库事务,首先要知道为什么数据库需要事务管理。

要说事务的例子,最简单的就是银行转账,A向B转账100,首先要将A记录中的金额减去100,再将B记录中的金额加上100,这才算是完成一次转账。可是,程序运行中可能出现各种不可控因素,如果在A减去100之后,银行停电或者地震之类的,各种原因导致程序停止,并没有执行对B账户的操作,A减去了100,可是B没有加上。这时候就需要事务管理。

一、事务的四个特性

1、一般来说,事务是必须满足4个条件(ACID)

原子性(Autmic):事务在执行性,就是说不允许事务部分得执行,一个事务是一个不可分割的工作单位。即使因为故障而使事务不能完成,rollback后也要回退到对数据库进行操作前的状态。

一致性(Consistency):事务必须是使数据库从一个一致性状态变到另一个一致性状态。一致性与原子性是密切相关的。比如A,B账户相互转账之后,总金额不变。

隔离性(Isolation):一个事务的执行不能被其他事务干扰,当多个事务并发执行时,各个事务不会互相影响。

持久性(Durability):持续性也称永久性(permanence),指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。

2、事务的四个特性(ACID)是由关系数据库管理系统(RDBMS,数据库系统)来实现的。数据库管理系统采用日志来保证事务的原子性、一致性和持久性。日志记录了事务对数据库所做的更新,如果某个事务在执行过程中发生错误,就可以根据日志,撤销事务对数据库已做的更新,使数据库退回到执行事务前的初始状态。

数据库管理系统采用锁机制来实现事务的隔离性。当多个事务同时更新数据库中相同的数据时,只允许持有锁的事务能更新该数据,其他事务必须等待,直到前一个事务释放了锁,其他事务才有机会更新该数据。

二、关于脏读,不可重复读、幻读

1、脏读(DirtyReads):所谓脏读就是对脏数据(Drity Data)的读取,而脏数据所指的就是未提交的数据。一个事务正在对一条记录做修改,在这个事务完成并提交之前,这条数据是处于待定状态的(可能提交也可能回滚),这时,第二个事务来读取这条没有提交的数据, 并据此做进一步的处理,就会产生未提交的数据依赖关系。

2、不可重复读(Non-RepeatableReads):一个事务先后读取同一条记录,期间另一个事务修改了数据,并且已经commit,所以两次读取的数据不同,称之为不可重复读。 3、幻读(PhantomReads):一个事务先后读取同一个表,期间其他事务插入了新的数据,并且已经commit,这种现象就称为幻读。 它和不可重复读的区别:不可重复读的重点是修改,幻读重点是新增和修改。

三、隔离级别

既然知道了事务会有脏读,不可重复读和幻读的现象,那就需要去控制他们,所以有了隔离级别。 一般隔离级别有四级:

  READ UNCOMMITTED:幻读,不可重复读和脏读均允许

如果数据库的隔离级别为REAE UNCOMMITTED, 则其他线程可以看到未提交的数据, 因此就出现脏读。

  READ COMMITTED:允许幻读和不可重复读,但不允许脏读

如果数据库隔离级别设为READ_COMMITTED,即没提交的数据别人是看不见的,就避免了脏读.但是,正在读取的数据只获得了读取锁,读完之后就解锁,不管当前事务有没有结束,这样就容许其他事务修改本事务正在读取的数据。导致不可重复读。

  REPEATABLE READ:允许幻读,但不允许不可重复读和脏读

REPEATABLE READ因为对正在操作的数据加锁,并且只有等到事务结束才放开锁, 则可以避免不可重复读。

  SERIALIZABLE:幻读,不可重复读和脏读都不允许

SERIALIZABLE因为获得范围锁,且事务是一个接着一个串行执行,则保证了不会发生幻读。

隔离级别 脏读可能性 不可重复读可能性 幻读可能性 加锁读
READ UNCOMMITTED YES YES YES NO
READ COMMITTED NO YES YES NO
REPEATABLE READ NO NO YES NO
SERIALIZABLE NO NO NO YES

所以说,READ UNCOMMITTED级别最低,SERIALIZABLE级别最高。 级别越高肯定对于维护事务的四个特性就越好,但是它牺牲的是数据库的效率,因为SERIALIZABLE的实现是类似于java中的线程锁。

ORACLE默认的是 READ COMMITTED,默认事务管理是开启的,使用DML语言对数据操作需要提交(commit),出错后可以回滚(rollback)。MYSQL默认的是 REPEATABLE READ,事务默认自动提交,若想开启事务,使用set autocommit 命令。

Mysql提供了两种事务型的存储引擎:InnoDB和NDB Cluster.通过执行SET TRANSACTION ISOLATION LEVEL 设置隔离级别。新的隔离界别会在下一个事务开始时生效,也可以在配置文件中设置整个数据库的隔离级别。

mysql>SET SESSION TRANSACTION ISOLATION LEVEL  READ COMMITTED

四、隐式和显式锁定

1.InnoDB采用的是两阶段锁定协议。事务执行过程中,随时都可以锁定,在执行COMMIT或者ROLLBACK的时候才会释放。InnoDB还会根据隔离级别在需要的时候自动加锁。

2.InnoDB也支持通过特定的语句进行显示锁定。

SELECT XXX LOCK IN SHARE MODE

SELECT XXX FOR UPDATE

MYSQL也支持LOCK TABLES 和UNLOCK TABLES,这是服务器层实现的,和存储引擎无关。