67.3. 进程引擎中的事务
流程引擎支持 Java 事务 API(JTA)事务。
进程引擎的当前版本不支持纯本地事务。
如果没有在应用程序内提供事务界限,流程引擎会在一个单独的事务中对进程引擎执行每个方法调用。
另外,您可以在应用程序代码中指定事务界限,例如,将多个命令合并到一个事务中。
67.3.1. 注册事务管理器
您必须在环境中注册事务管理器才能使用用户定义的事务。
以下示例代码注册事务管理器并使用 JTA 调用来指定事务边界。
注册事务管理器和使用事务
// Create the entity manager factory EntityManagerFactory emf = EntityManagerFactoryManager.get().getOrCreate("org.jbpm.persistence.jpa"); TransactionManager tm = TransactionManagerServices.getTransactionManager(); // Set up the runtime environment RuntimeEnvironment environment = RuntimeEnvironmentBuilder.Factory.get() .newDefaultBuilder() .addAsset(ResourceFactory.newClassPathResource("MyProcessDefinition.bpmn2"), ResourceType.BPMN2) .addEnvironmentEntry(EnvironmentName.TRANSACTION_MANAGER, tm) .get(); // Get the KIE session RuntimeManager manager = RuntimeManagerFactory.Factory.get().newPerRequestRuntimeManager(environment); RuntimeEngine runtime = manager.getRuntimeEngine(ProcessInstanceIdContext.get()); KieSession ksession = runtime.getKieSession(); // Start the transaction UserTransaction ut = InitialContext.doLookup("java:comp/UserTransaction"); ut.begin(); // Perform multiple commands inside one transaction ksession.insert( new Person( "John Doe" ) ); ksession.startProcess("MyProcess"); // Commit the transaction ut.commit();
您必须在 root 类路径中提供 jndi.properties
文件,以创建 JNDI InitialContextonnectionFactoryy
对象,因为与事务相关的对象(如 UserTransaction
、TransactionManager
和 TransactionSynchronizationRegistry
)在 JNDI 中注册。
如果您的项目包含 jbpm-test
模块,则默认已包含此文件。
否则,您必须使用以下内容创建 jndi.properties
文件:
jndi.properties
文件的内容
java.naming.factory.initial=org.jbpm.test.util.CloseSafeMemoryContextFactory org.osjava.sj.root=target/test-classes/config org.osjava.jndi.delimiter=/ org.osjava.sj.jndi.shared=true
此配置假设 simple-jndi:simple-jndi
工件存在于项目的类路径中。您还可以使用不同的 JNDI 实现。
默认情况下会使用 Narayana JTA 事务管理器。如果要使用不同的 JTA 事务管理器,您可以更改 persistence.xml
文件以使用所需的事务管理器。例如,如果您的应用程序在红帽 JBoss EAP 7 或更高版本上运行,您可以使用 JBoss 事务管理器。在这种情况下,更改 persistence.xml
文件中的事务管理器属性:
JBoss 事务管理器的 persistence.xml
文件中的事务管理器属性
<property name="hibernate.transaction.jta.platform" value="org.hibernate.service.jta.platform.internal.JBossAppServerJtaPlatform" />
使用 RuntimeManager
类的 Singleton 策略与 JTA 事务(UserTransaction
或 CMT)的 Singleton 创建了一个竞争条件。这个竞争条件可能会导致 IllegalStateException
异常,与 进程实例 XXX 类似的消息是断开连接
。
要避免这种竞争条件,在用户应用程序代码中调用事务时,请明确同步 KieSession
实例。
synchronized (ksession) { try { tx.begin(); // use ksession // application logic tx.commit(); } catch (Exception e) { //... } }
67.3.2. 配置容器管理事务
例如,如果您将进程引擎嵌入到由容器管理的事务(CMT)模式中执行的应用程序中,您必须完成额外的配置。如果应用程序在没有允许 CMT 应用从 JNDI 访问 UserTransaction
实例(例如,WebSphere Application)运行,则此配置尤为重要。
流程引擎中的默认事务管理器实施依赖于 UserTransaction
查询事务状态,然后使用该状态来确定是否启动事务。在阻止访问 UserTransaction
实例的环境中,此实施会失败。
要在 CMT 环境中启用正确执行,流程引擎提供一个专用的事务管理器实施: org.jbpm.persistence.jta.ContainerManagedTransactionManager
。此事务管理器要求事务处于活动状态,并且始终在调用 getStatus()
方法时返回 ACTIVE
。开始
、提交和
回滚
等操作是 no-op 方法,因为事务管理器无法在容器管理的事务模式中影响这些操作。
在执行代码的过程中,必须将引擎引发的任何例外传播到容器,以确保容器在必要时回滚事务。
要配置此事务管理器,请完成此流程中的步骤。
流程
在您的代码中,在创建或载入会话前将事务管理器和持久性上下文管理器插入到环境中:
将事务管理器和持久性上下文管理器插入到环境中
Environment env = EnvironmentFactory.newEnvironment(); env.set(EnvironmentName.ENTITY_MANAGER_FACTORY, emf); env.set(EnvironmentName.TRANSACTION_MANAGER, new ContainerManagedTransactionManager()); env.set(EnvironmentName.PERSISTENCE_CONTEXT_MANAGER, new JpaProcessPersistenceContextManager(env)); env.set(EnvironmentName.TASK_PERSISTENCE_CONTEXT_MANAGER, new JPATaskPersistenceContextManager(env));
在
persistence.xml
文件中,配置 JPA 提供程序。以下示例使用hibernate
和 WebSphere Application Server。在
persistence.xml
文件中配置 JPA 供应商<property name="hibernate.transaction.factory_class" value="org.hibernate.transaction.CMTTransactionFactory"/> <property name="hibernate.transaction.jta.platform" value="org.hibernate.service.jta.platform.internal.WebSphereJtaPlatform"/>
要分散 KIE 会话,请不要直接选择它。相反,执行
org.jbpm.persistence.jta.ContainerManagedTransactionDisposeCommand
命令。此命令可确保会话在完成当前事务时被处理。在以下示例中,ksession
是您要处理的KieSession
对象。使用
ContainerManagedTransactionDisposeCommand
命令执行 KIE 会话ksession.execute(new ContainerManagedTransactionDisposeCommand());
直接调整会话会导致事务完成异常,因为进程引擎注册事务同步来清理会话状态。
67.3.3. 事务重试
当进程引擎提交事务时,有时提交操作会失败,因为同时提交另一个事务。在这种情况下,进程引擎必须重试事务。
如果多次重试失败,则事务会永久失败。
您可以使用 JVM 系统属性来控制重试进程。
属性 | 值 | 默认 | 描述 |
---|---|---|---|
| 整数 | 5 | 此属性描述了进程引擎永久重试事务的次数。 |
| 整数 | 50 | 第一次重试前的延迟时间(以毫秒为单位)。 |
| 整数 | 4 | 每次后续重试增加延迟时间的倍数。使用默认值时,进程引擎在第一个重试前等待 50 毫秒,在第二个重试前等待 200 毫秒,即第三个重试前 800 毫秒,以此类推。 |