学校时的分布式数据库读书笔记(6)

第四章 分布式数据库中的事务管理和恢复

1 两阶段提交(2PC)

由于两阶段提交(2PC)在系统效率和可用性两方面都存在缺碴 一方面与单节点事务相比.2PC的分

布事务太慢;另一方面一旦参与分布事务的某一个结点不适时地失败,会使其它结点无法继续处理数据,从而降低了系统的可靠性复制服务器有敛地解决了2PC存在的同题。

复制服务器(Replicalion Server)

首先,从效率上看.通过数据在多个节点的副本.使某节点对该数据的访问无需通过网络远程去获取-而且复制服务器的异步RPC技术使原来依赖于2PC技术的分布式事务能快速有效地进行;从可用性看,复

制服务器通过StoreForward技术解决了原有系统对网络及远程节. 可用性的依赖,在网络或远程节点出现故障时本地正常提交,复制服务器监听各种状态,一旦网络重新连通或远地节点恢复运行,则能将事务传递到远程节点进行同步 Replication Server在整个ClientServer网络的异构平台上同步复制数据.它赋予了高度的本地自治能力和灵活性。[10]

2 三阶段提交协议

主要思想是将事务的提交过程进行延长,增加了发起者结点的预提交状态和参与者结点的准备提交状态,因而在发生故障时参与者可以有更多的选择余地。具体的说,如果是参与者发生了故障,那么它重新启动后就向其他未发生故障的参与者发送查询消息,如果已经有结点进人PREPARE COMMIT状态那么故障结点就可以提交,因为发起者发出PREPARE TO COMMIT命令的前提是收到了所有参与者结点的READY消息。如果任一参与者都没有收到PREPARE TO COMMIT命令,就要考虑事务的发起者是否出现了故障,按照协议,所有无故障的参与者可依据某种策略(如排队法)来产生新的发起者来结束事务,新的发起者可以撤消事务以使各参与者尽快释放所占有的资源。如果原来的发起者发生故障时已经有参与者收到了准备提交命令,则新推选出的参与者可发出COMMIT命令提交事务。[11]

3 平坦事务模型

平坦事务模型是一种简单的事务模型,其事务性应用控制只有一层,事务的ACID特性能够得到保证,适用于短事务和较为简单的应用.目前代表产品主要有IBM WebsphereBEA Weblogic等.它不仅包括对分布事务处理的支持,还能够在成千上万的Internet用户并发访问规模下,支持多种类型的客户访问及高可用的服务性能.[9]

4 基于角色的分布式事务处理模型设计

传统的事务处理主要应用于数据库系统和操作系统领域。随着网络技术和分布式对象技术的飞速发展,在大型的、分布的、异构的计算环境中也广泛引入了事务处理技术。通过比较分析目前主要分布式事务处理模型的优缺点,在异构数据集成系统中设计一种基于角色的Agent分布式事务处理模型,旨在异构数据集成系统中建立高性能、高可用性的应用。

Agent是能为用户执行特定的任务,具有一定程度的智能以允许自主执行部分任务并以一种合适的方式与环境相互作用的软件程序。Agent首先是智能化的,它对环境具有响应性、自主性和主动性,同时Agent具有自适应性、社会姓。Agent有静态和移动Agent之分,移动Agent除了有静态Agent的特性之外,还有节省带宽、均衡网络负载等特性.

基于角色的Agent事务处理模型,如图

 

事务创建Agent:事务创建Agent在收到事务性应用程序的创建事务请求信息后,为新建事务分配一个唯一的事务标识号,并且为事务创建相应的事务协调Agent

事务分解Agent:事务分解Agent负责判断事务是局部事务还是全局事务。如果是一个全局事务,事务分解

Agent则把全局事务映射到多个分布站点的子事务上去,保证全局事务的正确调度执行。

事务协调Agent:事务协调Ag ent是移动Ag ent,它根据各个分布式场地参与者的表决信息来完成局部或全局事务的提交或回滚,实现事务的两阶段提交协议保证事务执行的原子性。

事务控制Agent:在异构数据集成系统中,不同模式结构的分布式数据资源允许多个用户同时访问和使用。

因此在同一时刻可能存在多个并行运行的事务,如何保证个对象被并行事务计算和访问时的数据一致性,这就需要用到事务控制Agent。事务控制Agent主要负责协调并行运行的事务,保证事务执行的可串行性,从而保证数据资源的一致性。

事务日志Agent:事务日志Agent记录事务执行过程中发生的所有事件,为事务恢复提供依据。事务日志Agent把事务开始、事务提交、事务结束和事务回滚等每一个操作都登记为一条日志记录,存放在日志文件中。日志登记次序严格按照并行事务操作执行的时间次序,同时遵循先写日志文件,再执行操作的规则。

事务恢复Agent:事务恢复Agent主要是为了在事务异常情况下采取一定的事务恢复策略来保证事务的原子

性。根据事务执行在空间、时间上出现故障的不同,事务恢复Agent将采取不同的恢复策略,如果故障出现在两阶段协议提交之前,则通过两阶段提交协议就可以保证事务以回滚而结束,各场地利用日志Agent的日志信息执行恢复操作。如果故障出现在两阶段协议提交之后和事务提交之前,情况较复杂,一般采用向前恢复的机制,即恢复出错部件,重新执行事务操作,将它推进到下一个一致状态。[12]

5 基于日志的数据恢复及其在Oracle中的实现

假设某运行中的数据库系统在Tl时刻做了一次完整的备份,由于某种原因在T2时刻(T2>T1)出现了故障,导致数据库损坏,如图l所示。一般意义上的数据恢复只能做到不完全恢复,即重建数据库,利用T1时刻的数据备份将数据库恢复到T1时刻的状态,T1T2时间段的数据则丢失。

如果TIT2时间段的事务日志存在,则我们可实现数据的完全恢复(Complete Recovery) 即将数据库恢复到故障前的状态 因为T1T2时间段的事务日志是按照时间顺序详细记录了这一时间段的事务处理信息,之所以数据库中的数据由Tl状态过渡到T2时刻的状态,正是由于这些事务处理操作的结果。如果我们在T1状态的基础上,重新依次运行这些事务,就可以将数据库由TI状态逐步推演到T2时刻的状态,实现数据库的数据恢复.并且这种“推演”可以根据需要在T1T2之间某个时间点停留,即将数据库恢复到过去的某个特定的时间点。图1对整个过程做了演示。需要注意的是,日志中记录的事务处理信息是与当时的

数据库状态相关联的,离开了特定的数据状态,数据操作也就失去了意义。因此事务日志的重演是有前提的:①数据库首先必须处于某一时刻点的完整状态(通常由数据库备份来实) 只有处于这个状态,在这一时间点之后的事务才有重新运行的基础;②重新运行的事务处理必须严格按照原来的时间顺序进行只有这样,才能实现逐步推演,因为实际的数据库操作其后一步操作总是依赖于前一步操作的结果 正因为如此,数据库的事务日志必须连续地保存,如果某个时间段的事务日志损坏或丢失。则此时间段之后的日志也就失去了存在的意义

Oracle数据库恢复范例分析

外部存储结构及其运行方式

首先扼要介绍Oracle数据库的体系结构。一个OracLe数据库在物理上由Data FilesRedo Log FilesControl Files 3部分组成.它们在逻辑上形成一个有机的整体DataFile是由表空间所对应的文件,用于实际存储数据库中的数据;Redo Log File是用于记录事务处理信息的日志文件;Control File存储整个数据库的结构信息,它控制整个数据库的运行。数据库在启动时需要创建Oracle Instance(指数据库使用的内存结构),包括SGABackground Processes两部分。根据Parameter File中的配置参数,可以将数据库设置在归档方式(Archive Log Mode)下运行,这样每当出现Log Switch操作时,Background Processes中的进程ARCH会将刚写满的Redo Log File备份转移,形成归档目志(Archive Log Files,即联机日志的脱机拷贝)。由于受物理文件大小的限制,联机日志只能记录有限时间段的事务处理信息。而联机日志和归档日志的联舍可以连续完整地记录数据库在运行过程中的事务处理信息。

数据库恢复图解

无论何种原因故障导致Oracle数据库不能正常启动(即不能进八Open状态,此时即需要执行数据库恢复典型的数据库恢复过程需要如下3个阶段:① Restore:选择某个历史备份作为恢复的起点,即首先将数据恢复至备份时刻的状态 ②Roll Forward:利用归档曰志和联机日志依次重做自备份时刻以来的事务;③Roll Back:在故障时刻前附近的些事务,有些还未来得及提交(Commit),但由于系统内部的Checkpoint事件的触发导致已经写入联机日志,这部分事务需要利用数据映像(Before Image)进行必要的回滚。如果这3个阶段的操作都能够顺利进行,则可以将数据库毫无损失地恢复到损坏前一时刻的状态.即所谓的完全数据库恢复(Complete Recovery),如果这个恢复过程在第23阶段由于某种原因中途结束,则数据库只能恢复到过去的某个时闻点.即不完全恢复(Incomplete Recovery)。图2给出了Oracle数据库恢复的典型示例:

设系统在T7时刻出现故障导致Ocac]e数据库停止运行,数据库分别在T1T3T63次历史备份,由图2可知.Archive Log中包含了T2T5时闻段的事务日志,Online Redo Log中包含了T4T7时间段的事务日志。下面说明恢复过程。最直接的恢复方法是选择T6时刻的备份作为恢复的起点,首先利用备份将数据文件RestoreT6时刻,在此基础上只需利用联机重做日志.依次重新运行T6T7时间段所包古的所有事务.即可将数据库恢复到故障时刻,实现Complete Recovery.妇果选择T3时刻的备份作为恢复的起点,则需要同时使用两类日志,首先利用归挡日志重做T3T4(TS)时间段的事务.接着利用联系日志重做T4(T5)T7时间段的事务,也可将数据库恢复到故障时刻,同样实现Complete Recovery如果数据库在T2T7时间段没有备份可以利用,则只能够选择较远的T1时刻的备份作为恢复的起点.此时由于缺T1T2时间段的事务日志,数据库只能够恢复到TI时刻,导致TIT7(故障时剡)时间段的最新数据丢失,即只能实现Incomplete Recovery.同样在选样T3时刻备份作起点的恢复方法中,如果联机重做日志丢失.则数据库只能最大限度地恢复T5时刻,此时同样实现的是Incomplete Recovery。需要特别指出的是,尽管在上述恢复过程中没有提到控制文件,但它的作用不可或缺,系统恢复进程正是根据Control File中包含的最新的Log Sequence Number确定需要重做的事务。由此需要注意.在平利用历史备份对数据库进行Restore阶段,不能对控制文件进行Restore操作,否则会导致数据库的不完全恢复;其次,为确保控制文件的可用性,控制文件最好联机保存多个副本,并分布于不同的物理磁盘上。

6 完全数据恢复的黄金法则

6.1 隔离数据和事务日志的物理存储

数据和事务日志是数据库两个不可分割的部分。实际应用中,在部署一个数据库系统的物理存储时,有必要将数据和事务日志分开,条件许可的情况下,尽可能地将两者置于相互独立的物理磁盘中。这种存储方案可以大大提高数据的可用性:在数据库故障的案例中,存储介质失效是占有相当大的比重,两个相互独立的物理磁盘同时出现介质故障的可能性要小得多。如果数据盘出现损坏,而日志盘正常,导致数据丢失而日志存在,这种情况可以通过历史备份和连续存在的事务日志使数据库得到完全恢复。

6.2 保持事务日志适当冗余(Redundancy)

在前面介质失效的例子中,如果出现另一种情况,即日志盘损坏而数据盘正常,导致日志丢失而“数据”存在,这种情况下存在的“数据”通常也是不可存取的,因为无法定位日志,数据库是不能正常启动的。解决的办法是重建日志并做日志与数据的同步处理或利用备份进行恢复。实践中两种方法都不可避免地要出现部分最新数据的丢失。比较前后介质失效的两种情况我们可以看出,事务日志在数据恢复过程中显得比数据本身更为重要。因此在条件许可的情况下,应首先将事务日志做数据冗余处理,如进行软硬件镜象、采用RAID存储、借助第三方软件实现双机热备等措施,以确保事务日志的安全性。因为数据丢失可以利用历史备份和事务日志来恢复数据,而联机日志丢失则必然要导致数据的不完全恢复。

6.3 监控事务日志的完整性

数据库的事务日志是随时间一维无限增长的,实际投运的数据库需要保持对事务日志的监控,主要是两个方面:① 维护事务日志的时间连续性和完整性,以确保在数据库在出现故障的情况下数据能够实现完全恢复。这里说的连续性和完整性是指自上一次数据库完整备份以来至数据库运行的当前时刻这一时间段的事务日志。对Oracle来说,必须将数据库设置在归档方式(Archive Log Mode)下运行;② 监视事务日志的存储空间,如果对它不做任何处理,事务日志会持续增长,旦存储空间用尽,数据库进程将被挂起,此时的数据库将会停止响应对数据的任何操作。

7 事务管理器的事务恢复处理

OMG组织的OTS(对象事务服务)中规定了一套事务失败恢复的模型。该模型是基于假定回滚的策略恢复失败的事务。假定回滚是事务二阶段提交协议的一种效率优化策略,事务发起者在决定提交之前和资源在准备好之前都不用写任何13志。这样在失败发生后重新启动时,所有未记录13志的事务都认为已经做过回滚操作。

事务的失败模型

事务服务在应用、系统或通信失败时,要提供事务的原子性结果。下面描述失败发生时各应用实体的行为。

(1)事务创建者

局部失败:在事务创建者发出提交命令之前的失败将引起事务回滚。在事务创建者发出提交命令之后而在事务结果报告之前的失败,依赖于时机导致提交或回滚。这种情况下事务的完成情况与事务创建者的失败无关。

外部失败:任何在事务创建者发出提交命令之前的外部失败,都将引起事务的回滚。在事务创建者发出提交命令之后而在事务结果报告之前的失败,意味客户端可能不会通知事务的结果,这依赖于失败的特征和提交命令是否使用reportheuristics选项。客户端可以通过Coordinatorgetstatus方法得到事务的结果。但这也不是可靠的方法,因为可能得到事务不存在的结果。

(2)事务服务器

局部失败:事务服务器失败后,事务服务如果实现可选的检查方法,将引起事务的回滚。如果没有实现可选的检查方法,事务是否回滚取决于事务的提交命令是否发出。当未检查的客户端在收到所有服务器的应答之前发出提交命令时就是这种情况。

外部失败:任何在事务服务器执行过程发生的外部失败都将引起事务的回滚。事务对象的方法执行时发生

失败,将不会影响方法的执行。方法将会正常结束,返回结果到客户端。最后事务回滚异常返回到发出提交命令的客户端。

(3)恢复服务器

可恢复服务器在失败发生时的行为决定于Coordinator与可恢复服务器的资源对象之间的二阶段提交协议。

事务失败后的继续完成

通常,完成方法是在失败发生点继续完成事务。这意味着Coordinator常常有责任向注册的资源发送提交命令。某些失败情况下也需要资源初始化恢复程序。资源代表与某一事务关联的可恢复数据的集合。当失败恢复时,已经准备好的资源使用Recovery Coordinator对象的replycompletion方法确定事务的结果和完成事务。根据Coordinator在日志记录决定提交前的失败可能是单方面的回滚事务。如果所有资源都准备好,需要初始化的恢复过程如下:若根Coordinator的结果是提交,则发出提交命令继续完成协议;若根Coordinator的结果是回滚,则发出回滚命令继续完成协议。

事务的恢复处理

事务恢复,就是能够在容错的方式下继续完成事务。通过日志的记录信息,在恢复过程中使用这些有用的信息恢复事务。

事务恢复的二个阶段是:④ 正常操作时,在事务处理过程中存储必要的信息到日志顺序文件,后台进程对已完成的顺序文件做归档操作。②恢复过程中,通过归档文件和日志文件的信息恢复事务。

事务的正常阶段

(1)事务的状态及保存点OTS中,事务的惟一标识是事务标识。事务标识由三个字段的数据结构表示:全局事务标识,用GtxID表示;分支事务标识,用BqualID表示;事务的格式标识,用FORMATID表示。由以上三个字段组成的事务标识可以惟一标识任何范围内分布式计算环境中的一个事务。

事务在其整个生命周期中存在以下的状态:活动事务(ACTIVE),正在准备的事务(PREPARING),准备好的

事务(PREPARED),正在提交的事务(COMMITING),已完成提交的事务(COMMITED),正在回滚的事务(ROLLBACKING),已完成回滚的事务(ROLLEDBACK),标记为回滚的事务(ROLLBACKMARKED),出现启发式异常的事务(UNKNOWN)

根据OTS规范的事务失败假定回滚策略, 所有在事务失败时没有决定提交或回滚的事务,在恢复处理过程中都可以忽略。因此,为了简化事务失败恢复的操作,提高交易中间件的事务处理能力,选取事务处理过程中的以下几个关键点做为事务的保存点。在事务的生命周期中遇到事务的保存点,就必须在事务的日志文件中记录下事务的相关信息,在以后的恢复过程中使用。事务的保存点如下:① PREPARED:二阶段提交事务的准备阶段正常完成后,事务管理器向各个资源发出提交命令之前;COMMITED: 事务提交正常完成之后; ③ ROLLBACKED:事务回滚正常完成之后;ROLLBACKING事务决定回滚;⑤UNKNOWN:事务出现HEURISTIC常。在事务的保存点除了记录事务的状态信息以外,还需要记录事务的标识信息。可以用三个值分别记录事务的全局事务标识、分支事务标识及格式标识。

(2)日志文件的设计

日志文件以行数据作为结构单元。一行数据包括以下几列:第一列值表示全局事务标识(GtxlD);第二列值表示分支事务标识(BquallD);第三列值表示格式标识(FORMATID);第四列值表示事务保存点的状态(STATUS);第五列值是行结束符。日志文件是同一目录下一序列顺序文件的集合(logalogblogclogz)。每个文件的行数可以配置为一个定值ROWMAX,写满了一个日志文件后,便可以开始写下一个顺序文件。事务的处理进程在事务的保存点根据事务的信息添加一行记录。每个日志文件长度达到ROWMAX行后,做个标记(setReadOnly),创建一个新的日志顺序文件,并刷新事务进程的写缓冲区,开始在新的日志文件中记录。后台单独有一个线程对已写满的日志文件做归档操作。归档就是筛选出日志文件中未完成事务的记录。归档文件和日志文件的结构是相同的,所有的日志文件归档后保存到一个归档文件中。日志文件归档完成后就删除该日志文件或做归档完成标记。

(3)其他优化

为了提高写日志的效率、减少系统资源的开销,事务的状态值可以用一个字节表示,事务的标识可以用定长个数的字节表示。日志文件的同步写操作在成千上万的事务并发处理过程中,可能成为事务处理器的瓶颈。因此有必要同时开辟若干个写缓冲区和若干个日志文件供不同的事务并发写日志。

事务的恢复阶段

(1) 恢复方式

事务的恢复有二种可行的方式:①事务管理器恢复并发送结果到资源。资源不用主动参与恢复过程,只是正常的提交或回滚命令被触发。② 资源没有发现事务结果传递过来,就发请求到事务管理器。事务管理器恢复Rec0veryC00rdinat0r对象,资源通过该对象的replaycompletion()方法请求获得事务

结果,如果不能获得结果信息,则回滚事务,否则按获得的结果完成事务。

为了事务的完整性,OTS在恢复时,既要恢复Recovery Coordinator对象,又要根据日忐中事务的状态向注册的资源发送commit()rollback()命令。

(2) 事务恢复

事务恢复根据以下规则进行:所有活动的事务都必须恢复,所有已经准备提交的事务都提交,所有已经准备回滚的事务都同滚,所有状态未知的事务都回滚。事务发生失败后,在交易中间件重启时要做恢复操作。首先读取失败时日志目录下所有未来得及归档的日志文件,再读取归档文件中的内容。根据读取的这些文件内容筛选出失败发生时未完成的事务,由交易中间件恢复所有这些未完成的事务,保

证了事务的完整性和一致性。[14]

8 DelphiSQL Server 事务处理编程技术

下面是我以前的一个C/S项目代码。其中用到了事务处理。项目使用的是SQL Server数据库服务器,Delphi开发,使用的是BDE数据库引擎驱动,三层架构。

 

客户端的代码(一个过程):

 

procedure TRightFunction.RzCheckTree1StateChanging(Sender: TObject;

  Node: TTreeNode; NewState: TRzCheckState; var AllowChange: Boolean);

begin

if Loaded then

begin

Screen.Cursor:=crHourGlass;

tData:=Node.Data;

FunctionId:=tData^;

      (GlobalRemoteServer as TSocketConnection).AppServer.StartTransaction;

       try

          if (NewState=csChecked) or (NewState=csPartiallyChecked) then

          begin

             RightFunctionDataSet.Close;

             RightFunctionDataSet.CommandText:='select * from RightFunction where 权限序号='+IntToStr(RightId)+' and 功能序号='+IntToStr(FunctionId);

             RightFunctionDataSet.Open;

             if RightFunctionDataSet.RecordCount=0 then

             begin

                RightFunctionDataSet.Close;

                RightFunctionDataSet.CommandText:='insert into RightFunction(权限序号,功能序号) values('+IntToStr(RightId)+','+IntToStr(FunctionId)+')';

                RightFunctionDataSet.Execute;

             end;

          end;

          if NewState=csUnChecked then

          begin

             RightFunctionDataSet.Close;

             RightFunctionDataSet.CommandText:='delete from RightFunction where 权限序号='+IntToStr(RightId)+' and 功能序号='+IntToStr(FunctionId);

             RightFunctionDataSet.Execute;

         end;

         (GlobalRemoteServer as TSocketConnection).AppServer.CommTransaction;

         LogDateTime:=(GlobalRemoteServer as TSocketConnection).AppServer.GetDateTime;

         (GlobalRemoteServer as TSocketConnection).AppServer.WriteLog(LogDateTime,UserInfo.UserName,'用户分配系统权限功能成功','',1);

        except

        (GlobalRemoteServer as TSocketConnection).AppServer.RollBackTransaction;

        LogDateTime:=(GlobalRemoteServer as TSocketConnection).AppServer.GetDateTime;

        (GlobalRemoteServer as TSocketConnection).AppServer.WriteLog(LogDateTime,UserInfo.UserName,'用户分配系统权限功能时,数据库发生错误','',0);

        Application.MessageBox('数据库发生错误,本操作无效!','提示!',mb_IconError+mb_OK);

        end;

Screen.Cursor:=crDefault;

end;

end;

 

服务器端代码:

procedure TServer.CommTransaction;

begin

DataBase1.Commit; //提交

end;

 

procedure TServer.RollBackTransaction;

begin

DataBase1.Rollback; //回滚

end;

 

procedure TServer.StartTransaction;

begin

if not DataBase1.InTransaction then

DataBase1.StartTransaction; //启动事务

end;

  通过上面的代码,客户端调用服务的程序执行,服务器将结果送回客户端。由于项目不规范,请不要模仿上面的写法。只是用来说明问题。

9 JAVA编程实例

  一般情况下,J2EE应用服务器支持JDBC事务、JTAJava Transaction API)事务(一般由容器来进行管理)。通常,最好不要在程序中同时使用上述三种事务类型,比如在JTA事务中嵌套JDBC事务。第二方面,事务要在尽可能短的时间内完成,不要在不同方法中实现事务的使用(事务的嵌套要求更加良好的设计)。

    下面的代码也是我以前项目的实例。文中去掉了日文注释。是B/S架构,MYSQL数据库,TOMCAT容器。Java开发的网站后台程序。

    /**

     *

     *

     * @param inputData  Object

     * @param outputData Object

     *

     *

     * @return    nResult

     *

     *  UILogicBean.LOGIC_ERROR

     *

     **/

    public int insertDB(Object inputData, Object outputData) throws Exception

    {

        int nResult         = UILogicBean.LOGIC_ERROR;

       

        StatementEx objStmt = null;

        ResultSetEx rs      = null;

       

        //sql

        String[] strInputValues = null;

        try

        {

        //

            objStmt = this.m_objConn.createStatementEx();

           

            HashMap hmInputdata = (HashMap)inputData;

           

            //HarsMap

            String strCorpName = hmInputdata.get(LBInsertMRC.strCorpName).toString();

            String strUserName = hmInputdata.get(LBInsertMRC.strUserName).toString();

            String strPwd = hmInputdata.get(LBInsertMRC.strPwd).toString();

            String strRight = hmInputdata.get(LBInsertMRC.strRight).toString();

            String strUpdateId = hmInputdata.get(LBInsertMRC.strUpdateId).toString();

            strUpdateId = "1";

           

            strInputValues = new String[] {strCorpName,strUserName,strPwd,strRight,strUpdateId};

           

            //

            nResult = objStmt.executeUpdateByKey("SQL_LBInsertMRC_003", strInputValues);

 

        }

        catch (SQLException e)

        {

            //print log

            log.error(e.toString());

            throw new DBException();

        }

        catch (Exception ex)

        {

            //print log

            log.error(ex.toString());

            throw new SystemException();

        }

        finally

        {

            if (objStmt != null)

            {

                objStmt.close();

                objStmt = null;

                }

        }

 

        return nResult;

}

JDBC事务

JDBC中怎样将多个SQL语句组合成一个事务呢?在JDBC中,打开一个连接对象Connection时,缺省是auto-commit模式,每个SQL语句都被当作一个事务,即每次执行一个语句,都会自动的得到事务确认。为了能将多个SQL语句组合成一个事务,要将auto-commit模式屏蔽掉。在auto-commit模式屏蔽掉之后,如果不调用commit()方法,SQL语句不会得到事务确认。在最近一次commit()方法调用之后的所有SQL会在方法commit()调用时得到确认。例如下面的代码:
/**
*
测试Jboss中的JDBC事务
* <p>@author</p>
* @date 2006
*/
jjava.sql.Connection conn = null;
try{
javax.sql.DataSource ds = (javax.sql.DataSource) context.lookup("java:/OracleDS");
conn = ds.getConnection();
conn.setAutoCommit(false);
java.sql.Statement statement = conn.createStatement();
/**
*
*
数据库操作
*
*/
conn.commit();
} catch (Exception e) {
if(conn!=null)
try{conn.rollback();}catch(Exception e1){out.println("catch:
事务回滚失败!<br />");}
out.println("catch:" + e.getClass() + ";" + e.getMessage()+"<br />");
}finally{
if(conn!=null)
try{conn.close();}catch(Exception e1){out.println("finally:
关闭数据库连接失败!
<br />");}
}

Java 事务 API(JTA) 及其同门兄弟 Java 事务服务(Java Transaction Service JTS) J2EE 平台提供了分布式事务服务。一个分布式的事务涉及一个事务管理器和一个或者多个资源管理器。一个资源管理器是任何类型的持久性的数据存储。事务管理器负责协调所有事务参与者之间的通信。
  与本地事务相比,XA 协议的系统开销相当大,因而应当慎重考虑是否确实需要分布式事务。只有支持 XA 协议的资源才能参与分布式事务。如果事务须登记一个以上的资源,则需要实现和配置所涉及的资源(适配器、JMS JDBC 连接池)以支持 XA

**
*
测试JBossJTA事务
* <p>@author</p>
* @date 2006
*/
javax.transaction.UserTransaction tx = null;
java.sql.Connection conn = null;
try{
tx = (javax.transaction.UserTransaction) context.lookup("java:comp/UserTransaction");
javax.sql.DataSource ds = (javax.sql.DataSource) context.lookup("java:/XAOracleDS");

tx.begin();
conn = ds.getConnection();
//conn.setAutoCommit(false);
java.sql.Statement statement = conn.createStatement();
String sql = "insert into testtable (cell1,cell2,cell3,cell4) values('"+System.currentTimeMillis()+"','','','')";
int insert = statement.executeUpdate(sql);
//conn.commit();
out.println("
插入了" + insert + "行记录!<br />");
if(true)throw new Exception("
故意抛出的异常!");
int num = statement.executeUpdate("delete testtable");
out.println("
删除了" + num + "行记录!<br />");
tx.commit();
} catch (Exception e) {
if(tx!=null)
try{tx.rollback();}catch(Exception e1){out.println("catch:
事务回滚失败!<br />");}
out.println("catch:" + e.getClass() + ";" + e.getMessage()+"<br />");
}finally{
if(conn!=null)
try{conn.close();}catch(Exception e1){out.println("finally:
关闭数据库连接失败!<br />");}
}

}

10 小结

   本章的两阶段和三阶段协议是分布式最重要的部分之一。是处理很多问题的基础。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值