事务(Transaction)是由一系列对系统中数据进行访问与更新的操做所组成的一个程序 执行逻辑单元(Unit)。数据库
狭义上的事务特指数据库事务。一方面,当多个应用程序并发访问数据库时,事务能够在这些应用程序之间提供一个隔离方法,以防止彼此的操做互相干扰。session
另外一方面,事务为数据库操做序列提供了一个从失败中恢复到正常状态的方法, 同时提供了数据库即便在异常状态下仍能保持数据一致性的方法。多线程
事务具备四个特征,分别足原子性(Atomicity )、一致性(Consistency )、隔离性(Isolation) 和持久性(Durability),简称为事务的ACID特性。并发
一、原子性(Atomicity )
事务的原子性是指事务必须是一个原子的操做序列单元。事务中包含的各项操做在一次执行过程当中,只容许出现如下两种状态之一。
•所有成功执行。
•所有不执行。spa
任何一项操做失败都将致使整个事务失败,同时其余已经被执行的操做都将被撤销并回滚,只打全部的操做所有成功,整个事务才算是成功完成。线程
二、一致性(Consistency )
事务的一致性是指事务的执行不能破坏数据库数据的完整性和一致性,一个事务在执行以前和执行以后,数据库都必须处于一致性状态。也就是说,事务执行的结果必须是使数据库从一个一致性状态转变到另外一个一致性状态,所以当数据库只包含成功事务提交 的结果时,就能说数据库处于一致性状态。而若是数据库系统在运行过程当中发生故障, 有些事务还没有完成就被迫中断,这些未完成的事务对数据库所作的修改有一部分已写入物理数据库,这时数据库就处于一种不正确的状态,或者说是不一致的状态。code
三、隔离性(Isolation)
事务的隔离性是指在并发环境中,并发的事务是相互隔离的,一个事务的执行不能被其余事务干扰。也就是说,不一样的事务并发操纵相同的数据时,每一个事务都有各自完整的数据空间,即一个事务内部的操做及使用的数据对其余并发事务是隔离的,并发执行的 各个事务之间不能互相干扰。对象
在标准SQL规范中,定义了 4个事务隔离级别,不一样的隔离级别对事务的处理不一样, 如未受权读取、受权读取、可重复读取和串行化
①未受权读取
未受权读取也被称为读未提交(Read Uncommitted),该隔离级别容许脏读取,其隔离级別最低。换句话说,若是一个事务正在处理某一数据,并对其进行了更新,但同时还没有完成事务,所以尚未进行事务提交,而与此同时,容许另外一个事务也可以访问该数据。举个例子来讲,事务A和事务B同时进行,事务A在整个执行阶段,会将某数据项的值从1开始,作一系列加法操做(好比说加1操做)直到变成10以后进行事务提交,此时,事务B可以看到这个数据项在事务A操做过程当中的全部中间值(如1变成二、2变成3等),而对这一系列的中间值的读取就是未受权读取。blog
②受权读取
受权读取也被称为读已提交(Read Committed),它和未受权读取很是相近,惟一的区别就是受权读取只容许获取已经被提交的数据。一样以上面的例子来讲,事务 A和事务同时进行,事务A进行与上述一样的操做,此时,事务B没法看到这个数据项在事务A操做过程当中的全部中间值,只能看到最终的10。事务
另外,若是说有一个事务C,和事务A进行很是相似的操做,只是事务C是将数据项从10加到 20,此时事务B也一样能够读取到20,即受权读取容许不可重复读取。
③可重复读取
可重复读取(Repeatable Read),简单地说,就是保证在事务处理过程当中,屡次读取同一个数据时,其值都和事务开始时刻是一致的。所以该事务级別禁止了不可重复读取和脏读取,可是有可能出现幻影数据。所谓幻影数据,就是指一样的事务操做,在先后两个时间段内执行对同一个数据项的读取,可能出现不一致的结果。在上面的例子,可重复读取隔离级别可以保证事务B在第一次事务操做过程当中,始终对数据项读取到 1,可是在下一次事务操做中,即便事务 B (注意,事务名字虽然相同,可是指的是另外一次事务操做)采用一样的查询方式,就吋能会读取到10或20。
④串行化
串行化( Serializable)是最严格的事务隔离级別。它要求全部事务都被串行执行,即事务只能一个接一个地进行处理,不能并发执行。
四、持久性(Durability)
事务的持久性也被称为永久性,是指一个事务一旦提交,它对数据库中对应数据的状态变动就应该是永久性的。换句话说,一旦某个事务成功结束,那么它对数据库所作的更新就必须被永久保存下来——即便发生系统崩溃或机器宕机等故障,只要数据库可以从新启动,那么必定可以将其恢复到事务成功结束时的状态。
以上介绍完事务的四大特性(简称ACID),如今重点来讲明下事务的隔离性,当多个线程都开启事务操做数据库中的数据时,数据库系统要能进行隔离操做,以保证各个线程获取数据的准确性,在介绍数据库提供的各类隔离级别以前,咱们先看看若是不考虑事务的隔离性,会发生的几种问题:
脏读是指在一个事务处理过程里读取了另外一个未提交的事务中的数据。
当一个事务正在屡次修改某个数据,而在这个事务中这屡次的修改都还未提交,这时一个并发的事务来访问该数据,就会形成两个事务获得的数据不一致。例如:用户A向用户B转帐100元,对应SQL命令以下
update account set money=money+100 where name=’B’; (此时A通知B) update account set money=money - 100 where name=’A’;
当只执行第一条SQL时,A通知B查看帐户,B发现确实钱已到帐(此时即发生了脏读),
而以后不管第二条SQL是否执行,只要该事务不提交,则全部操做都将回滚,那么当B之后再次查看帐户时就会发现钱其实并无转。
不可重复读是指在对于数据库中的某个数据,一个事务范围内屡次查询却返回了不一样的数据值,这是因为在查询间隔,被另外一个事务修改并提交了。
例如事务T1在读取某一数据,而事务T2立马修改了这个数据而且提交事务给数据库,事务T1再次读取该数据就获得了不一样的结果,发送了不可重复读。
不可重复读和脏读的区别是,脏读是某一事务读取了另外一个事务未提交的脏数据,而不可重复读则是读取了前一事务提交的数据。
在某些状况下,不可重复读并非问题,好比咱们屡次查询某个数据固然以最后查询获得的结果为主。但在另外一些状况下就有可能发生问题,例如对于同一个数据A和B依次查询就可能不一样,A和B就可能打起来了……
幻读是事务非独立执行时发生的一种现象。例如事务T1对一个表中全部的行的某个数据项作了从“1”修改成“2”的操做,这时事务T2又对这个表中插入了一行数据项,而这个数据项的数值仍是为“1”而且提交给数据库。而操做事务T1的用户若是再查看刚刚修改的数据,会发现还有一行没有修改,其实这行是从事务T2中添加的,就好像产生幻觉同样,这就是发生了幻读。
幻读和不可重复读都是读取了另外一条已经提交的事务(这点就脏读不一样),所不一样的是不可重复读查询的都是同一个数据项,而幻读针对的是一批数据总体(好比数据的个数)。
如今来看看MySQL数据库为咱们提供的四种隔离级别:
① Serializable (串行化):可避免脏读、不可重复读、幻读的发生。
② Repeatable read (可重复读):可避免脏读、不可重复读的发生。
③ Read committed (读已提交):可避免脏读的发生。
④ Read uncommitted (读未提交):最低级别,任何状况都没法保证。
以上四种隔离级别最高的是Serializable级别,最低的是Read uncommitted级别,固然级别越高,执行效率就越低。像Serializable这样的级别,就是以锁表的方式(相似于Java多线程中的锁)使得其余的线程只能在锁外等待,因此平时选用何种隔离级别应该根据实际状况。在MySQL数据库中默认的隔离级别为Repeatable read (可重复读)。
在MySQL数据库中,支持上面四种隔离级别,默认的为Repeatable read (可重复读);而在Oracle数据库中,只支持Serializable (串行化)级别和Read committed (读已提交)这两种级别,其中默认的为Read committed级别。
在MySQL数据库中查看当前事务的隔离级别:
select @@tx_isolation;
在MySQL数据库中设置事务的隔离 级别:
set [glogal | session] transaction isolation level 隔离级别名称; set tx_isolation=’隔离级别名称;’
例1:查看当前事务的隔离级别:
例2:将事务的隔离级别设置为Read uncommitted级别:
或:
记住:设置数据库的隔离级别必定要是在开启事务以前!
若是是使用JDBC对数据库的事务设置隔离级别的话,也应该是在调用Connection对象的setAutoCommit(false)方法以前。
调用Connection对象的setTransactionIsolation(level)便可设置当前连接的隔离级别,至于参数level,可使用Connection对象的字段:
在JDBC中设置隔离级别的部分代码:
后记:隔离级别的设置只对当前连接有效。对于使用MySQL命令窗口而言,一个窗口就至关于一个连接,当前窗口设置的隔离级别只对当前窗口中的事务有效;
对于JDBC操做数据库来讲,一个Connection对象至关于一个连接,而对于Connection对象设置的隔离级别只对该Connection对象有效,与其余连接Connection对象无关。