毛应爽,郑永春
MAO Ying-shuang,ZHENG Yong-chun
(长春工程学院 软件学院,长春 130012)
事务和锁是并发控制的主要机制。在关系型数据库中,事务可以确保用户对数据库逻辑操作的完整性和一致性。如有多个用户同时建立与数据库的会话,会发生多个事务互相干扰的问题,各种关系数据库都提供锁机制来保证所有事务在执行时都得到正确结果,以避免可能产生的幻读、脏读、不可重复读等错误。本文比较了Oralce和SQL Server数据库的事务处理和锁并说明它们对并发控制处理的异同点。
1.1 事务的类型
Oracle采用隐式开始一个事务,缺省情况下任何一个DML语句都会开始一个事务,直到用户发出Commit或Rollback命令,才会显式结束事务该事务。
而SQL Server有隐式事务和显式事务两种事务类型。默认情况下,SQL Server认为每个语句都是独立的一个事务并提交它,即隐式事务;如果某个事务需要包含多个语句,则需要使用显式事务,它必须封装在BEGIN TRAN和COMMIT TRAN或ROLLBACK TRAN语句组中。
1.2 DDL语句与事务控制
在Oracle中,Commit和Rollback语句只能应用于DML语句,而不应用于DDL语句,即一旦执行了DDL语句,则该语句首先隐含执行一个commit,在语句完成时也隐含执行一个commit命令,即将自动提交DDL语句前的事务和DDL语句本身的事务。因此,在执行了DDL命令后事务将无法回滚。例如在Oracle的sql*plus中执行以下代码:
Insert into myTable values(‘One’);
Create table test(x int);
Insert into myTable values(‘Two’);
Rollback;
由于在执行Create table语句时先隐含进行了提交,然后创建表,执行后又进行隐含提交,所以该程序只有第2条INSERT语句即插入数据Two的行被回滚,而插入One的行和创建的表都不被回滚,即使Create table语句失败,第1条INSERT语句也会被提交。如果最后Rollback更换成Commit命令,Commit命令也只影响第2条INSERT语句的操作。
相反,在Sql server的事务中如含有DDL语句,该DDL语句是可以被执行回滚操作的。将上例的代码在Sql server中执行,则代码应为:
Begin tran
Insert into myTable values(‘One’)
Create table test(x int)
Insert into myTable values(‘Two’)
Rollback tran
Sql server将这3条语句作为同一事务处理,因此在执行Rollback tran命令时会将插入myTable表中的One和Two以及新创建的表test都进行回滚。在事务执行过程中如果Create table语句失败,则第1条insert语句也被回滚。如将Rollback tran更换成Commit tran命令,它将影响整个事务的提交。
1.3 事务的提交模式
在Oracle和Sql server中都有“自动提交”模式。SQL Server中默认的事务管理模式为自动提交模式,即在使用 BEGIN TRANSACTION 语句启动显式事务或者隐式事务模式设置为开启之前,与数据库引擎实例的连接都以自动提交模式操作,因此,每个语句在完成时,都会被提交或回滚。而在Oracle中,通常只有在执行了DDL语句或者在SQL*Plus中退出(Quit)某个用户进程时才会出现自动提交,因为在DDL命令和quit命令的源代码中已内嵌了COMMIT命令。
1.4 事务的隔离级别
隔离级别定义了一个事务与其他事务的隔离程度,设置隔离级别,就为会话中的所有语句指定了缺省的锁定行为,这虽可使程序员面临的风险增加,但却可以更好地支持数据并发访问。在SQL92标准中,事务隔离级别分为Read Uncommitted、Read Committed、Read Repeatable、Serializable四种,其中Read Uncommitted与Read Committed为语句级别的,而Read Repeatable与Serializable是针对事务级别的。
1.4.1 Oracle的事务隔离级别
Oracle支持SQL92标准中的Read Committed 和Serializable两个隔离级别,并支持非SQL 92标准的Read Only和Read Write隔离级别。Read Committed是Oracle的默认隔离级别,Read Only是Serializable子集,都能避免非重复读和幻读,其区别在于Read Only是只读的,而在Serializable中可以进行DML操作。
Oralce事务处理的一个优势是它使用回滚段或撤销段来存放记录被修改前的结果,使读取和更新操作互不阻碍,快速进行,即读取操作不必等待更新事务结束,更新操作也不必因为另一事务中的读取操作而等待。
1.4.2 Sql server的事务隔离级别
SQL Server支持SQL92标准所定义的4种隔离级别,其缺省的隔离级别为 Read Committed,在这种隔离级别下,读取和更新操作有时是相互阻碍的,如一个会话正在对某表进行更新操作,而另一个会话同时对该表进行读取操作,则该会话需要等待更新事务结束后才能进行读取操作。另外SQL Server允许为事务设置Read Uncommitted隔离级别,该设置使一个会话可以读取其他事务未提交的更新结果,假如该事务最后以回滚结束,则读取的结果就可能是错误的。
锁是为防止其他事务访问指定的资源,对并发控制的事务进行的一种保护机制。当某个数据库对象正被其他进程或用户修改时,锁机制可以保护它不被修改,因而锁是实现并发控制的主要手段。
2.1 锁的粒度
锁粒度是指被锁定的数据对象的大小,要加快事务的处理速度并缩短事务的等待时间,就要使事务锁定的资源最小。
Oralce与SQL Server的锁粒度都包括行级锁、表级别锁、数据库级别锁。其中SQL Server还拥有页级锁和簇级锁。使用页级锁是因为SQL Server要求表中的行不能跨页存放,在事务操作过程中无论处理多少数据,每次都锁定一页。而簇级锁主要是当事务占用一个簇(8个连续页)时其他事务不能占用该簇,主要用于创建数据库和表时,系统用簇级锁分配物理空间。
2.2 锁类型
Oralce 和SQL Server最基本的锁类型有共享锁、排他锁、更新锁,而SQL Server还专门提供了意向锁,意向锁是其他几种锁类型的变体,包括意向共享锁、意向排他锁等。Oralce 和SQL Server都可以由以上基本锁类型进行组合以演变出更多的锁。
Oralce和SQL Server的锁机制对用户都是透明的,即系统能自动提供对应的等级锁来锁定资源,不需要用户专门设置。
2.3 死锁比较
死锁是指在两个以上的事务中,每个事务都因为试图加锁当前已被另一个事务加锁的数据项,从而造成的互相等待的现象。Oralce和SQL Server都能自动、有效地对死锁进行检测。所不同的是,当检测到死锁后,Oralce会选择一个执行修改数目最小的事务退出,被退出的事务会接收到一个错误信息,通知它所要访问的资源已经被另外的事务锁定,但Oralce不会自动回滚该事务,因此该事务锁定的资源仍未释放,解决方法是执行ROLLBACK或COMMIT语句或使用ALTER SYSTEM KILL SESSION语句终止该会话。而SQL Server在检测到死锁后,则会自动回滚其中一个事务并返回一个错误到连接对象,用此解决死锁并让其他事务继续完成工作。
2.4 锁争用的监测
ORACLE用动态性能视图V$LOCK和V$locked_OBJECT监测会话时锁的信息,V$LOCK包含所有当前由系统和所连接的会话保持的锁的信息,V$locked_OBJECT则提供当前被锁定的对象由什么锁模式锁定。SQL SERVER可采用调用系统存储过程SP_LOCK和SP_WHO,或直接查询系统表syslockinfo,或使用SSMS的活动监视器和SQL Profiler来浏览监测锁活动。
事务和锁是并发控制的主要机制,针对不同的数据库,用户在使用时应注意选择恰当的事务隔离级别,避免应用过长的事务,应在非高峰期间执行DDL操作和执行长时间运行的查询或事务,在实际应用中应仔细设计以防止锁争用的事务出现,并且对锁进行监控,解决死锁。
参考资料:
[1]Oracle Database 10g OCP Certification All-in-One Exam Guide John Watson著.清华大学出版社,2007,4.
[2]马晓玉.Oracle 10g数据库管理 应用与开发标准教程[M].清华大学出版社,2007,11.
[3]sql server 2005联机丛书.微软公司,sql server 2005文档.