要想知道什么是数据库事务,首先要知道为什么数据库需要事务管理。
要说事务的例子,最简单的就是银行转账,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,这是服务器层实现的,和存储引擎无关。