事务处理是全部大型数据库产品的一个关键问题,各数据库厂商都在这个方面花费了很大精力,不一样的事务处理方式会致使数据库性能和功能上的巨大差别。事务处理也是数据库管理员与数据库应用程序开发人员必须深入理解的一个问题,对这个问题的疏忽可能会致使应用程序逻辑错误以及效率低下。
下面咱们针对Oracle及SQL Server这两种当前普遍使用的大型数据库产品,探讨一下它们在事务处理方面的一些差别。如没有特殊说明,本文内容适用的数据库产品版本为Oracle9i及SQL Server 2000,其中的示例SQL语句,对于Oracle是在SQL*Plus中执行,而对于SQL Server 2000是在osql中执行。sql
1. 事务的概念
事务能够看做是由对数据库的若干操做组成的一个单元,这些操做要么都完成,要么都取消,从而保证数据知足一致性的要求。事务的一个典型例子是银行中的转账操做,账户A把必定数量的款项转到账户B上,这个操做包括两个步骤,一个是从账户A上把存款减去必定数量,二是在账户B上把存款加上相同的数量。这两个步骤显然要么都完成,要么都取消,不然银行就会受损失。显然,这个转账操做中的两个步骤就构成一个事务。
数据库中的事务还有以下ACID特征。
ACID分别是四个英文单词的首写字母,这四个英文单词是Atomicity、Consistency、Isolation、Durability,分别翻译为原子性、一致性、隔离性、持久性。
原子性:指事务中的操做,或者都完成,或者都取消。
一致性:指事务中的操做保证数据库中的数据不会出现逻辑上不一致的状况,一致性通常会隐含的包括在其余属性之中。
隔离性:指当前的事务与其余未完成的事务是隔离的。在不一样的隔离级别下,事务的读取操做,能够获得的结果是不一样的。
持久性:指对事务发出COMMIT命令后,即便这时发生系统故障,事务的效果也被持久化了。与此相反的是,当在事务执行过程当中,系统发生故障,则事务的操做都被回滚,即数据库回到事务开始以前的状态。
对数据库中的数据修改都是在内存中完成的,这些修改的结果可能已经写到硬盘也可能没有写到硬盘,若是在操做过程当中,发生断电或系统错误等故障,数据库能够保证未结束的事务对数据库的数据修改结果即便已经写入磁盘,在下次数据库启动后也会被所有撤销;而对于结束的事务,即便其修改的结果还未写入磁盘,在数据库下次启动后会经过事务日志中的记录进行“重作”,即把丢失的数据修改结果从新生成,并写入磁盘,从而保证结束事务对数据修改的永久化。这样也保证了事务中的操做要么所有完成,要么所有撤销。数据库
2. 事务设置及类型的区别
在SQL Server中有三种事务类型,分别是:隐式事务、显式事务、自动提交事务,缺省为自动提交。
自动提交:是指对于用户发出的每条SQL语句,SQL Server都会自动开始一个事务,而且在执行后自动进行提交操做来完成这个事务,也能够说在这种事务模式下,一个SQL语句就是一个事务。
显式事务:是指在自动提交模式下以Begin Transaction开始一个事务,以Commit或Rollback结束一个事务,以Commit结束事务是把事务中的修改永久化,即便这时发生断电这样的故障。例以下面是SQL Server中的一个显式事务的例子。
Begin Tran
Update emp Set ename=’Smith’ Where empno=7369
Insert Into dept Values(60,’HR’,’GZh’)
Commit
隐式事务:是指在当前会话中用Set Implicit_Transactions On命令设置的事务类型,这时任何DML语句(Delete、Update、Insert)都会开始一个事务,而事务的结束也是用Commit或Rollback。
在Oracle中没有SQL Server的这些事务类型,缺省状况下任何一个DML语句都会开始一个事务,直到用户发出Commit或Rollback操做,这个事务才会结束,这与SQL Server的隐式事务模式类似。
3. 事务隔离级别
在SQL92标准中,事务隔离级别分为四种,分别为:Read Uncommitted、Read Committed、Read Repeatable、Serializable,其中Read Uncommitted与Read Committed为语句级别的,而Read Repeatable与Serializable是针对事务级别的。
在Oracle和SQL Server中设置事务隔离级别的语句是相同的,都使用SQL92标准语法,即:Set Transaction Isolation Level Read Committed
上面示例中的Read Committed能够被替换为其余三种隔离级别中的任意一种。
1) SQL Server中的隔离级别及实现机制
在SQL Server中提供了全部这四种隔离级别。下面咱们讨论在SQL Server中,这几种隔离级别的含义及其实现方式。
Read Uncommitted:一个会话能够读取其余事务未提交的更新结果,若是这个事务最后以回滚结束,这时的读取结果就多是错误的,因此多数的数据库应用都不会使用这种隔离级别。
Read Committed:这是SQL Server的缺省隔离级别,设置为这种隔离级别的事务只能读取其余事务已经提交的更新结果,不然,发生等待,可是其余会话能够修改这个事务中被读取的记录,而没必要等待事务结束,显然,在这种隔离级别下,一个事务中的两个相同的读取操做,其结果可能不一样。
Read Repeatable:在一个事务中,若是在两次相同条件的读取操做之间没有添加记录的操做,也没有其余更新操做致使在这个查询条件下记录数增多,则两次读取结果相同。换句话说,就是在一个事务中第一次读取的记录保证不会在这个事务期间发生改变。SQL Server是经过在整个事务期间给读取的记录加锁实现这种隔离级别的,这样,在这个事务结束前,其余会话不能修改事务中读取的记录,而只能等待事务结束,可是SQL Server不会阻碍其余会话向表中添加记录,也不阻碍其余会话修改其余记录。
Serializable:在一个事务中,读取操做的结果是在这个事务开始以前其余事务就已经提交的记录,SQL Server经过在整个事务期间给表加锁实现这种隔离级别。在这种隔离级别下,对这个表的全部DML操做都是不容许的,即要等待事务结束,这样就保证了在一个事务中的两次读取操做的结果确定是相同的。
2) Oracle中的隔离级别及实现机制
在Oracle中,没有Read Uncommitted及Repeatable Read隔离级别,这样在Oracle中不容许一个会话读取其余事务未提交的数据修改结果,从而避免了因为事务回滚发生的读取错误。Oracle中的Read Committed和Serializable级别,其含义与SQL Server相似,可是实现方式却大不同。
在Oracle中,存在所谓的回滚段(Oracle9i以前版本)或撤销段(Oracle9i版本),Oracle在修改数据记录时,会把这些记录被修改以前的结果存入回滚段或撤销段中,就是由于这种机制,Oracle对于事务隔离级别的实现与SQL Server大相径庭。在Oracle中,读取操做不会阻碍更新操做,更新操做也不会阻碍读取操做,这样在Oracle中的各类隔离级别下,读取操做都不会等待更新事务结束,更新操做也不会由于另外一个事务中的读取操做而发生等待,这也是Oracle事务处理的一个优点所在。
Oracle缺省的设置是Read Committed隔离级别(也称为语句级别的隔离),在这种隔离级别下,若是一个事务正在对某个表进行DML操做,而这时另一个会话对这个表的记录进行读取操做,则Oracle会去读取回滚段或撤销段中存放的更新以前的记录,而不会象SQL Server同样等待更新事务的结束。
在Serializable隔离级别(也称为事务级别的隔离),事务中的读取操做只能读取这个事务开始以前已经提交的数据结果。若是在读取时,其余事务正在对记录进行修改,则Oracle就会在回滚段或撤销段中去寻找对应的原来未经更改的记录(并且是在读取操做所在的事务开始以前存放于回滚段或撤销段的记录),这时读取操做也不会由于相应记录被更新而等待。
4. DDL语句对事务的影响
1) Oracle中DDL语句对事务的影响
在Oracle中,执行DDL语句(如Create Table、Create View等)时,会在执行以前自动发出一个Commit命令,并在随后发出一个Commit或者Rollback命令,也就是说,DDL会象以下伪码同样执行:
Commit;
DDL_Statement;
If (Error) then
Rollback;
Else
Commit;
End if;
咱们经过分析下面例子来看Oracle中,DDL语句对事务的影响:
Insert into some_table values(‘Before’);
Creaate table T(x int);
Insert into some_table values(‘After’);
Rollback;
因为在Oracle执行Create table语句以前进行了提交,而在Create table执行后也会自动发出Commit命令,因此只有插入After的行被回滚,而插入Before的行不会被回滚,Create table命令的结果也不会被回滚,即便Create table语句失败,所进行的Before插入也会被提交。若是最后发出Commit命令,由于插入Before及Create table的操做结果已经在以前提交,因此Commit命令影响的只有插入After的操做。
2) SQL Server中DDL语句对事务的影响
在SQL Server中,DDL语句对事务的影响与其余DML语句相同,也就是说,在DML语句发出以前或以后,都不会自动发出Commit命令。
在SQL Server 2000中,对于与上面Oracle一样的例子,最后发出Rollback后,数据库会回滚到插入Before以前的状态,即插入Before和After的行都会被回滚,数据表T也不会被建立。
若是最后发出Commit操做,则会把三个操做的结果所有提交。
5.用户断开数据库链接对事务的影响
另外,对应于Oracle的管理客户端工具SQL*Plus,在SQL Server 2000中是osql,两种管理工具都是命令行工具,使用方式及做用也相似,可是在SQL*Plus中,用户退出链接时,会自动先发出Commit命令,而后再退出,而在osql中,若是用户退出链接,会自动发出Rollback命令,这对于SQL Server的自动提交模式没有什么影响,但若是处于隐式事务模式,其影响是显而易见的。对于两种数据库产品的其余客户端管理工具也有相似的不一样之处。工具