分布式部署工作流引擎如何处理数据源与事务问题

  1. 数据源和事务问题

本部分介绍用户如何用好的数据源,如何保证用户的事务和引擎事务的一致性,以及的事务分割原理。

本部分包括的内容

数据源:对数据源的使用可以分为基本用法和高级用法,对于基本用法主要通过配置工具进行配置,高级用法可以手工修改配置文件。

基本用法

通过 Governor配置数据源

单独使用BPS产品时,如果用户使用的是企业版,可以通过使用BPS Governor中的相应配置功能来配置BPS的数据源。用户可以登录BPS Governor,在”Governor->基本配置->数据源”中配置数据源。下图表示该功能在Governor中的位置。

数据源配置功能如下图。下图为在Tomcat服务器上时的配置界面,Tomcat环境下数据源类型为C3P0并且不可改变;当应用服务器类型不是Tomcat时,数据源类型为”JNDI”,配置项也会有一些不同

如果用户使用的是开发版,可以登录BPS管理监控工具,在”配置管理->数据源”中配置数据源。配置界面类似于上图所示。

高级用法

手工配置数据源

用户也可以采用手工配置数据源的方式,通过修改对应的配置文件来实现。配置文件的位置:%BPS_HOME%/apps_config/default/user-config.xml

用户可以在以下节点位置手工修改数据源application/module[name=' DataSource']/group[name='default']。配置示例如下:


    EOSDefaultDataSource
    ISOLATION_READ_COMMITTED
    DB2
    -1
  ...

BPS API的基本事务规则

BPS API分为两类。一类是只做查询操作,执行过程中没有对的修改动作,为纯查询的API;另一类API在执行过程中会插入、删除或者修改记录,为存在事务操作的API。

纯查询的API因为不对进行更新,所以不会创建新的事务,也不会加入到外部的事务当中。存在事务操作的API需要加入相应的事务处理,处理过程中遵循如下规则:

  • 如果BPS API被调用时外部已有事务,则本次BPS API调用不会创建新的事务,而是融合到外部事务当中。如果调用过程中发生异常,则设置事务为MARKED_ROLLBACK状态,并抛出异常。如下图:
  • 如果BPS API被调用时外部没有事务,则本次BPS API调用将自动创建新的事务。在API返回时,如果API调用发生异常,则事务回滚,并抛出异常;如果API没有发生异常,则事务提交。如下图:

事务的一致性

在BPS的应用过程中,可能在一个事务中既要处理业务,又要进行BPS调用,下面介绍如何实现这两种调用的一致。

BPS缺省支持的应用服务器产品有 WebSphere、WebLogic、JBoss和Tomcat,可以分成两种情况。

  • 如果应用服务器是Tomcat(单纯的WEB容器)
    在Tomcat环境下,用户应用的事务和BPS引擎的事务是分离的,每一次BPS调用都是一个独立的事务
  • 如果应用服务器是WebSphere、WebLogic、Jboss
    在这几种情况下,BPS使用应用服务器的JTA事务管理。如果用户也使用JTA的事务管理,就可以实现事务的一致性。比如下面的代码,应用的事务和BPS引擎完成工作项的事务是一起的。
    UserTransaction ut = null;
    
      try {
    
        InitialContext tempCtx = new InitialContext();
    
        ut = (UserTransaction) tempCtx
    
        .lookup("javax.transaction.UserTransaction");
    
        ut.begin();
    
        DataSource dataSource = (DataSource) tempCtx
    
        .lookup("ProductDefaultDataSource");
    
        Connection conn = dataSource.getConnection();
    
  •     /*
    
        * 进行业务操作 ...... 关闭连接
    
        */
    
        BPSServiceClient client = new BPSServiceClient();
    
        IWFWorkItemManager workitemManager = client.getWorkItemMananger();
    
        workitemManager.finishWorkItem(10001,false);
    
        ut.commit();
    
      } catch (Exception e) {
    
        e.printStackTrace();
    
        if (ut != null)
    
        try{
    
          ut.rollback();
    
          } catch (Exception e1) {
    
        }
    
      }
    
JTA的事务处理规则
如果BPS引擎和应用使用同一个数据源,则可以使用非XA的事务控制。如果应用的数据源和BPS引擎使用的数据源不相同(JNDI地址不相同),则需要使用XA的数据源,才能保证事务的一致性。
JTA事务
JTA是Java Transaction API(Application Programming Interface)的缩写。
什么是JTA Transaction?它有怎样的特点呢?JTA Transaction是指由J2EE Transaction manager去管理的事务。其最大的特点是调用UserTransaction接口的begin,commit和rollback方法来完成事务范围的界定,事务的提交和回滚。JTA Transaction可以实现同一事务对应不同的,但是它仍然无法实现事务的嵌套。
JTA是只是一组java接口用于描述,J2ee框架中事务管理器与应用程序,资源管理器,以及应用服务器之间的事务通讯。
它主要包括高层接口即面向应用程序的接口;XAResource接口即面向资源的接口;以及事务管理器的接口。值得注意的是JTA只提供了接口,没有具体的实现。
所以,JTA可以处理任何提供符合XA接口的资源。包括:,JMS,商业对象等等
“Java 事务 API”(JTA)启用两阶段提交功能。当配置 WebSphere Application Server等应用服务器以访问数据库时,可选择具有 JTA 能力的驱动程序。如果需要两阶段提交功能,则必须使用启用 JTA 的驱动程序。
只要您在事务中调用了多个数据库连接,就需要 JTA。只要您在事务中调用了多个数据库服务器,就需要两阶段提交。这些连接可以是相同的物理数据库服务器或多个数据库服务器。例如:
  • 实体企业 Bean Entity1 在应用程序服务器 AppServer1 中部署。
  • 实体企业 Bean Entity2 在应用程序服务器 AppServer1 中部署。
  • 会话企业 Bean Session1 在应用程序服务器 AppServer1 中部署。

如果 Session1 对同一事务内的 Entity1 和 Entity2 调用了方法而这两个企业 Bean 正在使用不同的物理数据库连接,则必须对 Entity1 和 Entity2 使用的数据源启用 JTA。当从相同的数据源对象获取那些连接时,这也是成立的。这需要具有 JTA 能力的驱动程序以提交事务。
当事务涉及到多个进程时,JTA 也是必需的。例如,一个事务可能会涉及在多个应用程序服务器中部署的企业 Bean。

  • 实体企业 Bean Entity1 在应用程序服务器 AppServer1 中部署。
  • 实体企业 Bean Entity2 在应用程序服务器 AppServer2 中部署。
  • 会话企业 Bean Session1 在应用程序服务器 AppServer1 中部署。

如果 Session1 对同一事务(此事务构成一个分布式事务)内的 Entity1 和 Entity2 调用了方法,则必须对 Entity1 和 Entity2 使用的数据源启用 JTA。
JTA 启用的连接与非 JTA 启用的连接执行性能不同。基于此原因,如果您的应用程序不需要 JTA,则最好使用非 JTA 启用的驱动程序。
有关 JTA 规范的更多信息,参见下列站点:https://java.sun.com/products/jta

XA事务
简单的说XA事务是遵从XA事务规范的事务。非XA事务是指不遵从XA事务规范的事务。

在谈到XA规范之前,必须首先了解分布式事务处理(Distributed Transaction Processing,DTP)的概念。Transaction,即事务,又称之为交易,指一个程序或程序段,在一个或多个资源如数据库或文件上为完成某些功能的执行过程的集合。
分布式事务处理是指一个事务可能涉及多个数据库操作,分布式事务处理的关键是必须有一种方法可以知道事务在任何地方所做的所有动作,提交或回滚事务的决定必须产生统一的结果(全部提交或全部回滚)。
X/Open组织(即现在的Open Group)定义了分布式事务处理模型。X/Open DTP模型(1994)包括应用程序(AP)、事务管理器(TM)、资源管理器(RM)、通信资源管理器(CRM)四部分。一般,常见的事务管理器(TM)是交易中间件,常见的资源管理器(RM)是数据库,常见的通信资源管理器(CRM)是消息中间件。为表述方便起见,在本文中直接以其常见表现形式进行描述。
通常把一个数据库内部的事务处理,如对多个表的操作,作为本地事务看待。数据库的事务处理对象是本地事务,而分布式事务处理的对象是全局事务。
所谓全局事务,是指分布式事务处理环境中,多个数据库可能需要共同完成一个工作,这个工作即是一个全局事务,例如,一个事务中可能更新几个不同的数据库。对数据库的操作发生在系统的各处但必须全部被提交或回滚。此时一个数据库对自己内部所做操作的提交不仅依赖本身操作是否成功,还要依赖与全局事务相关的其它数据库的操作是否成功,如果任一数据库的任一操作失败,则参与此事务的所有数据库所做的所有操作都必须回滚。
一般情况下,某一数据库无法知道其它数据库在做什么,因此,在一个DTP环境中,交易中间件是必需的,由它通知和协调相关数据库的提交或回滚。而一个数据库只将其自己所做的操作(可恢复)影射到全局事务中。
XA就是X/Open DTP定义的交易中间件与数据库之间的接口规范(即接口函数),交易中间件用它来通知数据库事务的开始、结束以及提交、回滚等。XA接口函数由数据库厂商提供

XA与两阶段提交协议

  通常情况下,交易中间件与数据库通过XA 接口规范,使用两阶段提交来完成一个全局事务,XA规范的基础是两阶段提交协议。
在第一阶段,交易中间件请求所有相关数据库准备提交(预提交)各自的事务分支,以确认是否所有相关数据库都可以提交各自的事务分支。当某一数据库收到预提交后,如果可以提交属于自己的事务分支,则将自己在该事务分支中所做的操作固定记录下来,并给交易中间件一个同意提交的应答,此时数据库将不能再在该事务分支中加入任何操作,但此时数据库并没有真正提交该事务,数据库对共享资源的操作还未释放(处于上锁状态)。如果由于某种原因数据库无法提交属于自己的事务分支,它将回滚自己的所有操作,释放对共享资源上的锁,并返回给交易中间件失败应答。
在第二阶段,交易中间件审查所有数据库返回的预提交结果,如所有数据库都可以提交,交易中间件将要求所有数据库做正式提交,这样该全局事务被提交。而如果有任一数据库预提交返回失败,交易中间件将要求所有其它数据库回滚其操作,这样该全局事务被回滚。
以一个全局事务为例,AP首先通知交易中间件开始一个全局事务,交易中间件通过XA接口函数通知数据库开始事务,然后AP可以对数据库管理的资源进行操作,数据库系统记录事务对本地资源的所有操作。操作完成后交易中间件通过XA接口函数通知数据库操作完成。交易中间件负责记录AP操作过哪些数据库(事务分支)。AP根据情况通知交易中间件提交该全局事务,交易中间件会通过XA接口函数要求各个数据库做预提交,所有数据库返回成功后要求各个数据库做正式提交,此时一笔全局事务结束。
XA规范对应用来说,最大好处在于事务的完整性由交易中间件和数据库通过XA接口控制,AP只需要关注与数据库的应用逻辑的处理,而无需过多关心事务的完整性,应用设计开发会简化很多。
具体来说,如果没有交易中间件,应用系统需要在程序内部直接通知数据库开始、结束和提交事务,当出现异常情况时必须由专门的程序对数据库进行反向操作才能完成回滚。如果是有很多事务分支的全局事务,回滚时情况将变得异常复杂。而使用XA接口,则全局事务的提交是由交易中间件控制,应用程序只需通知交易中间件提交或回滚事务,就可以控制整个事务(可能涉及多个异地的数据库)的全部提交或回滚,应用程序完全不用考虑冲正逻辑。

基本概念

BPS API的操作类方法默认都是采用”有则加入,无则创建“的方式(类似于EJB的Required事务策略)加入到外部事务当中的,但有时也有例外。

在一些特定情况下,事务需要以活动为单位,活动执行过后事务即提交;而不是等到API方法执行完毕(外部没有事务),或者依赖于外部的事务提交(外部有事务),这种情况对整个API调用过程来说将会产生”事务分割”。在BPS API中,因为主要以”活动”为单位进行事务分割,所以只有能推动流程流转的API才可能支持事务分割,目前只有以下方法可能支持事务分割:

  • 启动流程实例
  • 完成工作项
  • 完成活动实例

事务分割的的含义:流程调度类型API的执行过程被切分成以”流程启动”或者”活动”为单位的多个分离的事务,也就是在”流程启动”或者”活动执行”完成以后即提交事务,并开始一个新的事务;后面的错误不会回滚以前已经完成的内容

事务分割生效的控制在两处。第一个是在调用对应API的参数”是否分割事务”的参数;第二个是活动定义中的”分割事务”配置。只有这两个条件都满足,才能在该活动对应的活动实例完成时分割事务,否则不会分割事务。活动定义上的分割事务配置如下图:

事务分割与BPS API的调度过程

下面以finishWorkItem方法为例,来说明事务分割的场景。假定某流程中有三个活动:”填单”(人工活动)、”自动审核”(自动活动)、”人工审核”(人工活动),拓扑顺序如下图。在应用中调用API完成”填单”活动对应的工作项,将会推动流程向前运行,流程执行的基本操作分别为:API开始调用–>完成填单活动–>执行自动审核活动–>启动人工审核活动–>返回。下面分别描述finishWorkItem的参数”是否启动事务分割”为true和false的情况下的执行过程。

  • 传入false:即调用finishWorkItem(工作项ID,false)
    在这种情况下,调用API方法时传入的”是否启用事务分割”值为false,则按照正常的API执行规则进行调用。不会挂起事务,也不会判断各个活动上配置的”事务分割”配置。
    具体完成工作项的过程如下图,该图针对外部有事物的情况,如果外部没有事务,需要在API进入后和退出前分别增加”启动事务”和”提交事务”即可。
  • 传入true:即调用finishWorkItem(工作项ID,true)
    如果调用API时外部传入的”是否启用事务分割”值为true,则在处理API过程中有以下规则:
    • 进入API方法时,挂起外部事务,并创建一个新事务;
    • 对于流程推进过程中的每一个活动,在结束以后,如果该活动设置了”分割事务”,则执行提交事务,并创建新的事务。
      具体完成工作项的过程如下图,这里只描述外部有事务的情况;如果外部没有事务,则去掉挂起或恢复外部事务的步骤即可。

事务分割API过程中发生的异常

在支持事务分割的API执行过程中,如果发生了异常(出现Exception),则会对当前事务进行回滚(Rollback)处理,并中止API的继续执行。具体会回滚到上次启动事务的地方,不会对API外部的事务造成影响(外部的事务仍然能够继续进行和正常提交)。

声明: 除非转自他站(如有侵权,请联系处理)外,本文采用 BY-NC-SA 协议进行授权 | 智乐兔
转载请注明:转自《分布式部署工作流引擎如何处理数据源与事务问题
本文地址:https://www.zhiletu.com/archives-7022.html
关注公众号:智乐兔

赞赏

wechat pay微信赞赏alipay pay支付宝赞赏

上一篇
下一篇

相关文章

在线留言

你必须 登录后 才能留言!

在线客服
在线客服 X

售前: 点击这里给我发消息
售后: 点击这里给我发消息

智乐兔官微