第16章事务的控制与管理在实际对数据库的使用中,会出现多个用户同时对某一个数据表进行访问或者的修改的情况。当多个用户在同一时间修改对同一张数据表都进行读取或者修改操作时,处理不当,就可能会导致数据发生冲突的问题。例如,两个人在同一城市的不同地点同时都想买一张飞往大连的飞机票,而在联网的售票系统中,飞往大连的飞机票只有一张,如果售票系统不够完善,就会出现两个人购买了同一航班的同一座位的机票,这样的事情显然是不希望发生的。为了解决类似这样的问题,就需要使用事务的控制和管理机制。SQL语言也支持使用事务。本章就来介绍与事务控制和管理有关的内容。第16章事务的控制与管理事务的概念及其ACID属性;事务的控制;并发事务的工作流程;并发事务中存在的问题;事务的隔离级别;设置隔离级别和事务访问模式的方法。16.1事务的概念事务是指单个逻辑工作单元执行的操作的集合。通过事务处理,保证了数据库中数据的一致性。事务需要满足ACID属性,即Atomicity(原子性)、Consistency(一致性)、Isolation(隔离性)和Durability(持久性)。本节就来事务的这4个基本属性。16.1.1原子性(Atomicity)所谓事务的原子性是指同一个事务中所有执行的操作,要么全部成功,要么全都不会执行,即会退回到这个操作执行之前的状态。例如,有两个用户,用户user1持有一个帐户A,用户user2持有一个帐户B,在数据库中,有一个用来存储帐户信息的表accountTable,在这个数据表中保护有两个列,列cashValue表示帐户中存储的现金数,列accoutUser表示指定的帐户信息。现在用户user1希望将帐户A中的1000元钱转账给用户user2持有的帐户B中,这个操作需要分为以下两个步骤:16.1.1原子性(Atomicity)(1)修改帐户A中的现金数。将帐户A中的现金数减掉1000,其SQL语句如下:UPDATEaccountTableSETcashValue=cashValue-1000WHEREaccoutUser=‘A’(2)修改帐户B中的现金数。将帐户B中的现金数增加1000,其SQL语句如下:UPDATEaccountTableSETcashValue=cashValue+1000WHEREaccoutUser=‘B’16.1.2一致性(Consistency)所谓事务的一致性是指一个事务操作执行完成之后,数据库中数据必须处于合法一致的状态中。如果事务在执行时,数据库中的数据没有保持合法一致的状态,即出现了非法的数据,那么数据库管理系统就会把数据库恢复到该事务执行之前的那个合法的状态中。16.1.2一致性(Consistency)例如,用户user1只有一个帐户A,帐户A中共有5000元钱,用户user2持有一个帐户B,帐户B中也有5000元钱,帐户A和帐户B中一共有10000元钱,现在用户user1将帐户A中的1000元钱转账给用户user2持有的帐户B中,当转账操作执行完成之后,帐户A中应该还有4000元钱,帐户B中应该有6000元钱。帐户A和帐户B在转账完成之后余款的总和还应该是10000元钱。也就是说,当执行完成这个交易操作之后,数据库从一个合法状态转到了另外一个合法状态中。两个合法状态中帐户A和帐户B的余款总和保持一致。16.1.3隔离性(Isolation)所谓事务的隔离性是指事务看到的数据库中数据要么是这个事务被修改之前的状态,要么是这个事情被修改之后的状态。多个事务可以并发执行,在执行过程中彼此不会受到影响。事务的隔离性为事务的并发操作中数据的安全性提供了保证。但是隔离级别与数据库的并发性是成反比的。隔离级别越低,数据库的并发性就越好,访问速度越快;隔离级别越高,会导致数据库的并发性越差,访问速度越慢。SQL92中定义了4种不同的隔离级别,不同的隔离级别在解决并发事务时会出现不同的结果。不同的数据库系统也有这不同的默认隔离级别。有关事务的4种隔离级别将在16.3.3节小事务的隔离级别中介绍。16.1.4持久性(Durability)所谓事务的持久性是指如果一个事务被成功的修改,其结果在数据库中不会因为软件、硬件、系统等故障而改变,也不会因为数据库中的其他操作而受到影响。也就是说,事务一旦成功提交,在数据库中的数据就会永久的保持下来。16.2控制事务事务控制包括STARTTRANSCATION、COMMIT、ROLLBACK等语句。使用STARTTRANSCATION或者BEGIN等语句可以开始一个事务;使用COMMIT语句可以提交一个事务;使用ROLLBACK语句可以回滚一个事务。这一节就介绍这几种控制事务的方法。16.2.1开始事务开始一个事务有两种方式,一种是显式开始,一种是隐式开始。使用STARTTRANSCATION或者BEGIN等语句开始一个事务,属于显式开始一个事务;在前面讲过的SQL语句中,每一个SQL语句都可以作为包含一条命令的事务,这属于隐式开始一个事务。1.显式开始一个新事务STARTTRANSCATION[事务名]2.隐式开始一个事务16.2.2提交事务提交事务可以有三种方式,显式提交、隐式提交和自动提交。显式提交是通过使用COMMIT语句完成的事务的提交;隐式提交是指通过使用SQL语句就可以完成事务的提交;自动提交指通过设置AUTOCOMMIT命令完成事务的提交。下面就来介绍这3种提交方式。1.显式提交COMMIT[事务名]2.隐式提交通过使用SQL语句就可以完成事务的提交。3.自动提交通过设置AUTOCOMMIT命令完成事务的提交16.2.2提交事务例16.1开始并提交一个事务。STARTTRANSACTIONINSERTINTOaccountTableVALUES('A',5000);UPDATEaccountTableSETcashValue=cashValue+1000WHEREaccoutUser='A';COMMIT16.2.2提交事务设置自动提交的方式如下:SETAUTOCOMMIT=1SETAUTOCOMMITON这里提供了两种设置事务自动提交的方式,第一种方式是将AUTOCOMMIT的值设置为1,第二种方式是将AUTOCOMMIT值设置为ON。如果要想关闭自动提交方式,可以将将AUTOCOMMIT设置为0或者OFF。关闭自动提交的语法规则如下:SETAUTOCOMMIT=0SETAUTOCOMMITOFF16.2.3回滚事务回滚事务是表示当事务执行失败时,数据库将回恢复到该事务操作之前的那一个合法状态中,并撤销该事务对数据库所做的包括增加、修改和删除数据在内的所有更新操作。回滚事务可以使用ROLLBACK语句来完成。回滚事务的语法规则如下:ROLLBACK[TO保存点]其中,ROLLBACK表示用于事务回滚的关键字;TO保存点是可选的。这里的保存点用来表示回滚部分事务的一种机制。设置保存点后,在执行包括增加、修改和删除数据在内的更新操作时,如果执行过程中没有错误,就继续执行后面的语句;如果执行过程中出现错误,事务就会取消保存点后面的操作,回滚到更新操作之前的保存点。16.2.3回滚事务在数据库中,可以设置保存点。Oracle数据库和MicrosoftSQLServer数据库中设置保存点的方法有所不同。在Oracle数据库中,设置保存点的语法规则如下:SAVEPOINT保存点其中,SAVEPOINT表示设置保存点的关键字;关键字SAVEPOINT后面跟的是保存点的名字。在MicrosoftSQLServer数据库中,设置保存点的语法规则如下:SAVETRANSCATION保存点其中,SAVETRANSCATION表示设置保存点的关键字;关键字SAVETRANSCATION后面跟的是保存点的名字。16.2.3回滚事务例16.2回滚事务并为事务设置保存点。STARTTRANSACTIONINSERTINTOaccountTableVALUES('A',5000);SAVEPOINTa1;INSERTINTOaccountTableVALUES('B',5000);SAVEPOINTa2;INSERTINTOaccountTableVALUES('C',5000);SAVEPOINTa3;ROLLBACKTOa2;COMMIT16.3事务的并发控制事务的并发控制是指多个用户同时对同一个数据对象(例如,数据表、视图等)进行更新操作。在执行并发操作的过程中,可能会带来一些问题。这一节就来介绍并发事务的工作流程以及并发事务带来的问题,最后给出了解决事务并发处理中存在问题的方法,并介绍如何在数据库中设置隔离级别与事务访问模式。16.3.1并发事务的工作流程在讲解如何对事务进行并发控制之前,有必要要先了解一下并发事务的工作流程。为了模拟多个事务的并发操作,需要对同一个数据表建立两个连接,然后让两个用户试图同时修改数据表中的数据。在模拟事务的并发操作之前,首先需要做一些准备工作。这里首先需要创建一个用于测试并发事务的数据库test_transaction。其创建test_transaction数据库的SQL语句如下:CREATEDATABSEtest_transaction;16.3.1并发事务的工作流程然后在这个test_transaction数据库中创建一个数据表accountTable,该数据表用来表储用户帐户信息。其创建accountTable表的SQL语句如下:CREATETABLEaccountTable(accoutUserVARCHAR(10)PRIMARYKEY,cashValueINT,CHECK(cashValue=0))16.3.1并发事务的工作流程16.3.1并发事务的工作流程16.3.2事务并发处理中存在问题从上面的并发事务的工作流程中,读者可能会看出一些问题。确实,事务的并发操作虽然可以提高数据库管理系统对数据处理的效率,但同时事务并发处理中也存在一些问题。事务并发处理中主要存在以下3个方面的问题。1.读脏数据2.不能重复读3.幻象读16.3.3事务的隔离级别为了解决事务并发处理中存在问题,SQL92中定义了4种级别的事务隔离。通过使用事务的隔离级别来解决16.3.2节提到的事务并发处理中存在的问题。READUNCOMMITTED:未提交读。READCOMMITTED:提交读。REPEATABLEREAD:可重复读。SERIALIZABLE:可串行化。16.3.4在数据库中设置隔离级别在数据库中可以使用SQL语句设置隔离级别,可以为一个事务设置隔离级别,也可以为一个会话中的每个事务设置隔离级别。1.为一个事务设置隔离级别2.为一个会话中的事务设置隔离级别16.3.4在数据库中设置隔离级别1.为一个事务设置隔离级别在数据库中,可以使用SQL语句设置一个事务的隔离级别。使用SQL语句设置事务的隔离级别的语法规则如下:SETTRANSACTIONISOLATIONLEVEL隔离级别其中,SETTRANSACTION表示为当前的事务设置特性;ISOLATIONLEVEL表示为事务设置隔离级别的关键字;在SETTRANSACTIONISOLATIONLEVEL关键字后,需要指定隔离级别。16.3.4在数据库中设置隔离级别例16.3设置事务的隔离级别为可重复读。SETTRANSACTIONISOLATIONLEVELREPEATABLEREAD这段SQL语句是将事务的隔离级别设置为可重复读。其中REPEATABLEREAD表示隔离级别为可重复读。16.3.4在数据库中设置隔离级别2.为一个会话中的事务设置隔离级别在数据库中,除了可以使用SQL语句为一个事务设置隔离级别,还可以为一个会话中的事务设置隔离级别。如果要在MySQL数据库中为一个会话中的事务设置隔离级别。可以使用下面的SQL语句。SETSESSIONTRANSACTIONISOLATIONLEVEL[READUNCOMMITTED|READCOMMITTED|REPEATABLEREA