我们的应用程序有两个 Oracle 实例(两台物理机)和一个架构。 我们正在使用 weblogic 应用服务器。应用程序使用启用了 XA 事务的数据源。
我有一个 bean 管理的 EJB,我所做的 -
- 更新表中的一些数据然后提交
- 提交 Oracle 作业
- 再次更新表中的一些数据然后提交
这里我收到错误 - java.sql.SQLException: 无法在全局事务中使用本地事务提交。
奇怪的是,这个错误并不是每次执行都会出现,而是在 7-8 次执行中出现 1 次。
现在我的问题是
- 如果我使用启用 XA 的事务,Bean 管理的事务有何意义?
- 为什么每次执行时都没有遇到?
谢谢。
下面是代码-
DataObject.updateDataAndReturnCount(" UPDATE EOD_Trn_BatchProcess SET iJobNo = ?, szParameters = ? WHERE iProcessSeqNo = ? ", conn, new String[]{null, strParameters, (String)mapParameters.get("__PROCESS_SEQ_NO")});
conn.commit();
String strStatement = "{? = call submitProcAsJob(?, ?)}";
//String strStatement = "begin ? := submitProcAsJob(?, ?); end;";
CallableStatement pStmt = conn.prepareCall(strStatement);
pStmt.registerOutParameter(1, OracleTypes.NUMBER);
pStmt.setObject(2, strJobName);
pStmt.setObject(3, strInstanceNo);
pStmt.execute();
vString strJobNo = pStmt.getString(1);
vpStmt.close();
DataObject.updateData(" UPDATE EOD_Trn_BatchProcess SET iJobNo = ?, szParameters = ? WHERE iProcessSeqNo = ? ", conn, new String[]{strJobNo, strParameters, (String)mapParameters.get("__PROCESS_SEQ_NO")});
conn.commit();
这里需要第一次提交,因为我想保存调用期间使用的参数,即使作业提交失败。(或前面的任何事情。)
最佳答案
异常的原因是全局事务下不能手动调用commit()/rollback,只能将其标记为回滚。您有以下三种选择:
抛出异常,取决于ejb-jar.xml/weblogic-ejb-jar.xml,默认是对于任何RuntimeException,事务被标记为回滚;
在发生 CheckedException 时或在需要时调用 EJBContext.setRollbackOnly() 方法;
如果同一事务下的所有资源都没有发生上述情况,那么事务管理器迟早会提交该事务。
事务管理器负责为你commit()/rollback()事务,这样它就有机会与 不同的资源(例如两个oralce db)。您可以通过google关键字“两阶段事务”或“全局事务”查看详细信息,这是我发现的: Global Transaction
至于你的问题
如果我使用启用 XA 的事务,Bean 管理的事务有何意义?
如果 ejb-jar.xml 中的事务属性启用事务传播,则 Bean 管理的事务是“全局事务”。全局事务需要数据源启用XA,即jdbc驱动程序本身是XA类驱动程序,例如oracle.jdbc.xa.client.OracleXADataSource,或者启用XA的瘦驱动程序oracle.jdbc.OracleDriver(模拟两阶段事务,但不是真正的事务)
为什么每次执行都没有遇到?
我不知道为什么,我猜驱动程序有某种机制来检查规则是否被破坏。或者事务属性配置为支持,所以如果调用者有事务上下文,那么你的ejb就在全局事务下,否则不是。
希望我的回答对您有所帮助,祝您好运!
关于java.sql.SQLException : could not use local transaction commit in a global transaction,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15501655/