Jbpm用户指南翻译:第7章 持久化

  
第7章 持久化
在很多情况下,Jbpm需要维护跨越长时间的流程的执行,在这里,“长时间”意味着跨越几个处理事务。因为流程执行就像是状态机,在一个处理事务中,我们就是把流程执行状态机从一个状态转到下一个状态,所以持久化的主要目的就是在等待状态存储流程的执行。
一个流程定义可以表现为三种不同形式:XML、Java对象、Jbpm数据库中记录。执行(运行时)信息和日志信息可以表现为两种形式:Java对象和Jbpm数据库中的记录。
图 7. 1 转换和不同形式
有关XML表示流程定义以及流程档案的更多信息,请参考“第16章Jbpm流程定义语言(JPDL)”。
关于怎样部署流程档案到数据库在“第16.1.1节部署流程档案” 中可以找到。
7.1 持久化API
7.1.1 相关配置框架
持久化API集成在了配置框架中,通过JbpmContext暴露出了一些便利方法,因此持久化API要像下面这样在JbpmContext块中使用:
JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
try {
 
 // Invoke persistence operations here
 
} finally {
 jbpmContext.close();
}
在下文中,我们假设配置中包含如下持久化服务(如示例配置文件src/config.files/jbpm.cfg.xml):
<jbpm-configuration>
 
 <jbpm-context>
    <service name='persistence' factory='org.jbpm.persistence.db.DbPersistenceServiceFactory' />
    ...
 </jbpm-context>
 ...
</jbpm-configuration>
7.1.2 JbpmContext中的便利方法
三个普通的持久化操作是:
l       部署流程
l       启动一个流程的执行
l       继续一个执行
首先部署一个流程定义。典型的,这可以从图形化流程设计器或部署流程的Ant任务直接完成,但是在这里你会看到怎样通过编程实现:
JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
try {
 ProcessDefinition processDefinition = ...;
 jbpmContext.deployProcessDefinition(processDefinition);
} finally {
 jbpmContext.close();
}
要创建一个新的流程执行,我们需要指定一个要实例化执行的流程定义,通常的作法是指定一个流程名称,并让Jbpm在数据库中查找这个流程的最新版本:
JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
try {
 String processName = ...;
 ProcessInstance processInstance = 
      jbpmContext.newProcessInstance(processName);
} finally {
 jbpmContext.close();
}
要继续一个流程执行,我们需要从数据库中取出这个流程实例、令牌或者任务实例,在这些POJO Jbpm对象上调用一些方法,然后再把对流程实例的更新保存到数据库中。
JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
try {
 long processInstanceId = ...;
 ProcessInstance processInstance = 
      jbpmContext.loadProcessInstance(processInstanceId);
 processInstance.signal();
 jbpmContext.save(processInstance);
} finally {
 jbpmContext.close();
}
注意:如果你在JbpmContext中使用xxxForUpdate方法,则jbpmContext.save不需要再显式的调用,因为在jbpmContext关闭时它会被自动调用。举例来说,假设我们要通知Jbpm一个任务实例已经完成,(注意:任务实例完成能够触发继续执行,所以相联的流程实例必须保存。)一个非常方便的方法是使用loadTaskInstanceForUpdate方法:
JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
try {
 long taskInstanceId = ...;
 TaskInstance taskInstance = 
      jbpmContext.loadTaskInstanceForUpdate(taskInstanceId);
 taskInstance.end();
} finally {
 jbpmContext.close();
}
正象是后台信息一样,下面部分解释了Jbpm是怎样管理持久化和使用Hibernate的。
JbpmConfiguration维护了一组服务工厂(ServiceFactory),服务工厂象前面内容所说的在jbpm.cfg.xml中配置,并且是lazy(懒)实例化的。当在第一次需要DbpersistenceServiceFactory时它被实例化,然后服务工厂就被在JbpmConfiguration中维护,DbpersistenceServiceFactory管理一个hibernate SessionFactory,而hibernate SessionFactory也是在第一次被请求的时候才创建的。
图 7. 2 持久化相关类
在调用jbpmConfiguration.createJbpmContext()方法期间,只有JbpmContext被创建,这时没有更多的持久化相关实例。JbpmContext管理一个DbPersistenceService,它在被第一次请求的时候实例化。DbPersistenceServece管理hibernate会话(session),hibernate会话在DbPersistenceServece中也是被Lazy(懒)创建的,因此结果是:一个hibernate会话只有在第一个请求持久化的操作被调用时才被打开,而在这之前不会。
7.1.3 高级API用法
DbPersistenceService维护了一个懒实例化的hibernate 会话,所有的数据库存取都是通过这个hibernate会话完成的。所有的查询和更新都是通过Jbpm暴露出的xxxSession类完成的,例如GraphSession、SchedulerSession、LoggingSession等等,这些session类都是提交hibernate查询并且都使用下层相同的hebernate会话。
XxxxSession类也是通过JbpmContext来获取的。
7.2 配置持久化服务
7.2.1 The hibernate session factory
默认情况下,DbpersistenceServiceFactory将使用classpath根下的资源文件hibernate.cfg.xml来创建hibernate会话工厂。注意:hibernate资源配置文件由“jbpm.hibernate.cfg.xml”属性指定,可以在jbpm.cfg.xml中定制。下面是默认配置:
<jbpm-configuration>
 ...
 <!-- configuration resource files pointing to default configuration files in jbpm-{version}.jar -->
 <string name='resource.hibernate.cfg.xml' 
          value='hibernate.cfg.xml' />
 <!-- <string name='resource.hibernate.properties' 
                  value='hibernate.properties' /> -->
 ...
</jbpm-configuration>
当属性“resource.hibernate.properties”被指定,则指定的资源文件中的属性将会覆盖hibernate.cfg.xml中的配置,因此我们可以使用hibernate.properties文件、而不是更新hibernate.cfg.xml文件来方便的更新Jbpm指向自己的数据库:hibernate.cfg.xml仅仅需要拷贝过去不需要做任何更改。
DbpersistencrServiceFactory拥有三个配置属性:isTransactionEnabled、sessionFactoryJndiName和dataSourceJndiName。要指定这几个属性中的任何一个,你需要象bean一样在factory元素中定义服务工厂,如下:
 <jbpm-context>
    <service name="persistence">
      <factory>
        <bean factory="org.jbpm.persistence.db.DbPersistenceServiceFactory">
          <field name="isTransactionEnabled"><false /></field>
          <field name="sessionFactoryJndiName">
            <string value="java:/myHibSessFactJndiName" />
          </field>
          <field name="dataSourceJndiName">
            <string value="java:/myDataSourceJndiName" />
          </field>
        </bean>
      </factory>
    </service>
    ...
 </jbpm-context>
l        isTransactionEnabled :默认情况下, Jbpm 将会开始并且结束 hibernate 事务。如果禁用事务并且禁止使用 hibernate 管理事务,可以象上例一样配置 isTransactionEnabled 属性为 false 。更多信息,请参考“第 7.3 hibernate 事务”
l        sessionFactoryJndiName :默认情况下这个属性为空,意味着会话工厂不从 JNDI 获取。如果设置了,当需要使用会话工厂创建一个 hibernate 会话时,则将会从所提供的 JNDI 名称中通过 jndi 获取会话工厂。
l       dataSourceJndiName :默认情况下这个属性为空, JDBC 连接的创建会委托给 hibernate 。通过指定一个 datasource ,当打开一个新的会话时, Jbpm 将会从 datasource 中获取一个 JDBC 连接并且把这个连接提供给 hibernate 。有关用户提供 JDBC 连接,请参考“第 7.5 用户提供的素材”
7.3 Hibernate事务
默认情况下,Jbpm将委托事务到hibernate,并且使用每个事务一个会话的模式。Jbpm在hibernate会话被打开时启动一个hibernate事务,这在第一次调用jbpmContext的一个持久化操作时发生,事务会在hiberante会话关闭之前被提交,这在jbpmContext.close()中发生。
使用jbpmContext.setRollbackOnly()回滚一个事务,在这种情况下,事务会在jbpmContext.close()方法中关闭会话之前回滚。
要禁止Jbpm在hibernate API之上调用任何事务,可以设置isTransactionEnabled属性为false,就象上面的“第 7.2.2 节 The DbPersistenceServiceFactory”说明的一样。
7.4 管理事务
当在J2EE应用服务器中(如JBOSS)使用Jbpm时,大多情况下需要管理事务。如:
l        在应用服务器中配置一个 DataSource
l        配置 hibernate 使它的连接使用 DataSource
l        使用容器管理事务
l       Jbpm 中禁用事务
7.5 用户提供的素材
你也可以编程向Jbpm提供JDBC连接、hibernate会话和hibernate会话工厂。
当这些资源提供给Jbpm时,Jbpm会使用所提供的资源,而不是配置中指定的。
JbpmContext类包含了一些方便的方法来实现通过编程注入资源。例如,向Jbpm提供一个JDBC连接,可以使用如下代码:
JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
try {
 Connection connection = ...;
 jbpmContext.setConnection(connection);
 
 // invoke one or more persistence operations
 
} finally {
 jbpmContext.close();
}
JbpmContext类有如下方便的方法用来支持编程提供资源:
JbpmContext.setConnection(Connection);
JbpmContext.setSession(Session);
JbpmContext.setSessionFactory(SessionFactory);
7.6 自定义查询
Jbpm使用的所有HQL查询都集中在一个配置文件中,这个资源文件在hibernate.cfg.xml配置文件中被引用,如下:
<hibernate-configuration>
 ...
    <!-- hql queries and type defs -->
    <mapping resource="org/jbpm/db/hibernate.queries.hbm.xml" />
 ...
</hibernate-configuration>
要自定义一个或更多查询,先拷贝一个原始文件并且把你自定义的版本放在classpath下的某个位置,然后在hibernate.cfg.xml中更新 “org/jbpm/db/hibernate.queries.hbm.xml”,使之指向你自己定义的版本。
7.7 数据库兼容
Jbpm可以在hibernate所支持的任何数据库上运行。
Jbpm中的示例配置文件(src/config.files)指定了使用的是hypersonicin in-memory数据库,这个数据库在开发和测试阶段是一个理想的选择,hypersonicin in-memory数据库把数据放在内存中而不是存储到磁盘。
7.7.1 改变Jbpm数据库
下面列出了当改变Jbpm使用一个不同数据库时的作法:
l        jdbc 驱动库放在 classpath
l        改变 Jbpm 所使用的 hibernate 配置
l       在新的数据库中创建表
7.7.2 Jbpm数据库表
Jbpm.db子项目包含了一系列的驱动库、说明和脚本来帮助你在你所选择的数据库上开始工作。请查阅jbpm.dm工程根目录下的readme.html文件来获取更多信息。
尽管Jbpm有能力生成所有数据库的DDL脚本,但是这些不总是最优的,因此你可能想要你的DBA查阅这些生成的DDL,来进行列类型的优化和使用索引。
在开发中,你可能对下面的hibernate配置感兴趣:如果你设置hibernate配置属性“hibernate.hbm2ddl.auto”为“create-drop”(例如在hibernate.cfg.xml中),则在应用中第一次使用时,便会在数据库中自动创建,当应用关闭时,则表会被删除。
也可以编程调用jbpmConfiguration.createSchema()和jbpmConfiguration.dropSchema()方法来实现表的创建和删除。
7.8 结合你自己的hibernate类
在你自己的项目中,你可能使用hibernate来持久化,可以使你自己的持久化类与Jbpm持久化类结合,这是可选的。这样做有两个主要的好处:
首先,会话、连接和事务管理变得容易。通过结合Jbpm和你自己的持久化在一个hibernate会话工厂,则只有一个hibernate会话、一个jdbc连接来处理你自己的和Jbpm的持久化,因此,Jbpm的更新与你自己的域模型更新在相同的事务中,这可以排除再使用一个事务管理器。
其次,这毫无争议的就把你自己的hibernate持久化对象融入了流程变量中。
可以通过创建一个核心的hibernate.cfg.xml来很容易的与Jbpm持久化类集成你自己的持久化类,你可以使用Jbpm中的src/config.files/hibernate.cfg.xml作为开始,然后在其中添加你自己的hibernate映射文件的引用。
7.9 定制Jbpm的hibernate映射文件
你可以按照如下方式来定制任何Jbpm的hibernate映射文件:
l        从源码( src/java.jbpm/… )或 Jbpm 库中拷贝 Jbpm hibernate 映射文件
l        把拷贝的文件放置到 classpath 下任何你想要放置的地方
l       hibernate.cfg.xml 配置文件中更新指向自定义的映射文件
7.10 二级缓存
流程定义加载一次之后,Jbpm使用hibernate的二级缓存来把它放在内存中,流程定义类和集合在Jbpm的hibernate映射文件中使用cache元素来配置,如下:
<cache usage="nonstrict-read-write"/>
因为流程定义不会改变(应该不会改变),所以把它们放在二级缓存中是很好的做法,请参考“第16.1.3节 改变已发布的流程定义”。
二级缓存是JBOSS Jbpm实现的一个很重要的方面,如果没有这个缓存,JBOSS Jbpm在与其它实现BPM引擎的技术进行比较时,会是一个严重的缺陷。
缓存策略设置为 nonstrict-read-write 。在运行时,缓存策略可以设置为 read-only ,在这种情况下,你需要一个单独的 hibernate 映射文件来部署流程,这也是为什么我们选择 nonstrict-read-write 的原因。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值