这个是昨天上班的时候,写一个后台程序的调试程序时碰到的问题,和项目经理纠结了一天,最后搞定了。于是今天上班正好闲着,花了几乎一天的时间去网上找各种相关的资料。目前了解的内容如此:

根据使用的weblogic数据库驱动不同,可能会有两种报错:

①     Cannot call commit/rollback when using distributed transactions.

②     Cannot call Connection.commit/rollback in distributed transaction.

在JavaRanch上找到一个贴子,对解决问题非常有帮助:
http://www.coderanch.com/t/316208/EJB-JEE/java/Distributed-transaction-connnection-commit

其中的两个回复:
(1)这可能是因为你使用的数据库驱动启用了分布式事务(XA)。
检查一下weblogic控制台中的数据库驱动,你可能需要改一下,让它指向一个不用XA驱动的连接池。

(2)有两种方法可以实现事务:用JDBC,或者用JTA/JTS。第二种方法可以从ejb context中获取UserTransaction来实现:

UserTransaction ut = context.getUserTransaction();
ut.begin();
//do business logic
ut.commit();

  

两种模式之间有一个巨大的不同之处——只有第二种支持全局事务。
一些容器可能为了支持全局事务,会有一些特殊的数据库设定(比如容器将一直创建一个TX数据库(支持JTA的数据库),尽管基础连接池用的却是一个非XA的JDBC驱动)。可能因为如此,一使用JDBC事务就会出现这样的失败。

■总结:根据(1),最初设定数据库时的驱动选的不对。我选的是oracle.jdbc.xa.client.OracleXADataSource,这个支持分布式事务,必须要用UserTransaction接口对应的方法才能实现事务的提交和回滚操作,所以应该换用非XA的oracle.jdbc.OracleDriver驱动才对。但是仅仅这样,仍然还是会报错,只不过报错内容从①变成②。于是回复(2)解释了原因,虽然oracle.jdbc.OracleDriver并不是XA驱动,但是它为了支持全局事务,做了特殊的设定,容器在一直创建支持JTA的TX数据库,于是报了错。所以还应该在trasaction选项中把“支持全局事务”这一项的勾给去掉。这样就解决了。

按照以上的做法,就能解决问题了。如果身为开发者,还坚持要继续使用分布式事务的话,那就不要用JDBC的提交、回滚方法,而是要用JTA——实现一个UserTransaction的接口,然后用它的方法吧。

因为对于J2EE,本人还是newbie,好多东西都不知道,于是走了不少弯路。即便是把一切解决了,还是有诸多疑问。尤其是回复中的那些花样繁多的名词……于是又继续研究了一下,发现很是坑爹。

以下是查看的相关资料:

(a)http://static.springsource.org/spring/docs/2.5.x/reference/transaction.html

两种事务的基本概念——全局事务、本地事务:

全局事务:资源管理器管理和协调的事务,可以跨越多个数据库和进程。资源管理器一般使用XA二阶段提交协议与“企业信息系统”(EIS) 或数据库进行交互。

本地事务:在单个 EIS 或数据库的本地并且限制在单个进程内的事务。本地事务不涉及多个数据来源。

本地和全局事务都使用 javax.transaction.UserTransaction 接口划分界限,客户端必须使用此接口。本地事务不使用事务管理器,因而处理速度更快。

起初,所有事务都是本地的。如果非 XA 数据源连接是事务范围中登记的第一个资源连接,当“另一个”XA 数据源连接加入此连接时,该非 XA 数据源连接就成为全局事务。如果另一个非 XA 数据源连接试图加入,就会产生异常。

J2EE开发者有两个事务管理的选择: 全局 或 本地 事务。全局事务由应用服务器管理,使用JTA。局部事务是和资源相关的,比如一个和JDBC连接关联的事务。这个选择有深刻的含义。例如,全局事务可以用于多个事务性的资源(典型例子是关系数据库和消息队列)。使用局部事务,应用服务器不需要参与事务管理,并且不能帮助确保跨越多个资源(需要指出的是多数应用使用单一事务性的资源)的事务的正确性。

全局事务.  全局事务有一个重大的缺陷,代码需要使用JTA:一个笨重的API(部分是因为它的异常模型)。此外,JTA的UserTransaction通常需要从JNDI获得,这意味着我们为了JTA,需要 同时 使用JNDI 和 JTA。显然全部使用全局事务限制了应用代码的重用性,因为JTA通常只在应用服务器的环境中才能使用。 以前,使用全局事务的首选方式是通过EJB的 CMT(容器管理事务):CMT是 声明式事务管理 的一种形式(区别于 编程式事务管理)。EJB的CMT不需要任何和事务相关的JNDI查找,虽然使用EJB本身肯定需要使用JNDI。它消除了大多数(不是全部)硬编码的方式去控制事务。重大的缺陷是CMT绑定在JTA和应用服务器环境上,并且只有我们选择使用EJB实现业务逻辑,或者至少处于一个事务化EJB的外观(Facade)后才能使用它。EJB有如此多的诟病,尤其是存在其它声明式事务管理时,EJB不是一个吸引人的建议。

本地事务. 本地事务容易使用,但也有明显的缺点:它们不能用于多个事务性资源。例如,使用JDBC连接事务管理的代码不能用于全局的JTA事务中。另一个缺点是局部事务趋向于入侵式的编程模型。

(b)XA连接区别于非XA连接。

XA连接区别于非XA连接。要记住的是XA连接是一个JTA事务中的参与者。这就意味着XA连接不支持JDBC的自动提交特性。也就是说应用程序不必在XA连接上调用java.sql.Connection.commit()或java.sql.Connection.rollback()。 相反,应用程序应该使用UserTransaction.begin()、UserTransaction.commit()和UserTransaction.rollback()。

(c)http://hi.baidu.com/logson/blog/item/d32db308e750258ad0581b69.html

从程序角度考虑,事务可以分为两大类:一种是本地事务,一种是全局事务(也叫分布式事务)。

本地事务:是针对某个独立的事务资源(如JDBC)操作的事务。

全局事务:是协同或横跨多个资源(如JDBC连接、数据库等)操作的事务(上下文),多个资源协作是由事务管理器来完成的

JDBC与JTA:

JDBC是Java database connectivity 的缩写,意思是Java数据库连接。一般本地事务是与一个数据库连接相关的,因此Java中常称本地事务为JDBC事务。JDBC本身提供了简单的本地事务控制,可以满足针对一个JDBC连接事务的需求。

JTA是Java Transaction API的缩写,意思是Java事务API,这是一种组复杂事务控制接口,这组接口作为J2EE规范暴露给容器开发商,一般都由J2EE容器来实现。Spring很牛,也实现了这组API,使得任何应用使用JTA事务变得更容易。

(d)http://hi.baidu.com/eredlab/blog/item/d78c2538e45894e6b311c764.html

全局事务亦即常说的分布式事务:

全局事务需要应用服务器的支持,使用JTA。全局事务可以用于多个事务性的资源。(典型的为跨越多个数据库或者消息队列)。

本地事务:

应用服务器不需要参与事务管理。只针对单一事务资源。不能跨越多个事务资源。

XA:

XA是指X/Open组织在分布式规范中定义的交易中间件与数据库之间的接口规范(即接口函数),交易中间件用它来通知数据库事务的开始、结束以及提交、回滚等。 XA 接口函数由数据库厂商提供。

(e)connect.commit和UserTransaction.commit的区别:
http://www.coderanch.com/t/307456/JDBC/java/Difference-between-connection-commit-usertransaction
前者由数据库执行,后者由用户执行。
他们是不同的东西。想象一下,一个事务中包含了好几个数据库连接。提交用户的事务将会把这些都给一同commit上去。但是提交其中一个连接时却只commit一个。

■ 结论:全局事务常被称为分布式事务,而常说的JDBC事务即是本地事务。XA是组织在分布式中的接口规范,所以带XA字样的数据库驱动一般启用的都是分布式事务。而JTA是JAVA事务API的缩写(顺带一提,JTS是JAVA事务服务的缩写),一般说的JTA事务也是指分布式事务。所以前边说的看起来好像是有好几种事务似的,但是其实他们都是一回事,归结起来就只有两种而已,一种是分布式的,一种是非分布式的,发生的错误归结起来就是一句话:别在任何支持分布式事务的东西里用非分布式的commit和rollback方法,不好用……完毕。真是各种坑爹,一物多名真是初学者杀手啊。

现在再回顾一下之前的回复(2)中说的内容。分布式事务必须通过JTS来获取UserTransaction的接口才能得以实现。所以之前在分布式中调用JDBC事务的方法,才会出现异常。而后来换的那个虽然不是XA的驱动,但是他为了支持全局事务(就是分布式事务),一直在创建一个支持JTA的TX数据库,所以还是报了错。想正常地使用JDBC事务,必须保证用的不是XA驱动,同时全局事务支持必须关掉,二者缺一不可,和分布式一点儿边也不能沾。

详细的,这还有一篇文章介绍这方面的基础知识的:
http://www.ibm.com/developerworks/cn/java/j-dao/

http://www.programgo.com/article/81382059720/

J2EE分布式事务中的提交、回滚方法调用异常。的更多相关文章

  1. SpringBoot统一异常处理后TX-LCN分布式事务无法捕获异常进行回滚

    通常我们使用SpringBoot都会进行统一异常处理,例如写一个BaseController,在BaseController里进行统一异常处理,然后其他的Controller都继承BaseContro ...

  2. Jfinal中手动提交/回滚 事物

    在Jfinal中有个Tx类为事物声明类 在方法或controller上面加@Before({Tx.class})即可,可是这样并不能满足有的业务场景 下面是今天写的手动提交的事物处理方法,希望对大家有 ...

  3. 分布式事务中的2PC和3PC

    分布式事务 分布式事务是指会涉及到操作多个数据库的事务.其实就是将对同一库事务的概念扩大到了对多个库的事务. 分布式事务中需要注意的是分布式系统中存在的一致性问题: CAP原则:在一个分布式系统中,C ...

  4. sourceTree"重置提交"和"提交回滚"的区别

    相信用过sourceTree的伙伴们都认识这两,但是不一定用过这两个功能,甚至是不能很好的把握它两的区别,根据自己最近亲身测试,总算是能小小的总结一下了 首先这儿假如,历史版本已经出现了1.2.3.4 ...

  5. 阻止iOS中页面弹性回滚,只允许div.phone_body的区块有弹性

    使用说明:只要替换选择器:var selector = '.phone_body'; /** * 阻止iOS中页面弹性回滚,只允许div.scroller的区块有弹性 */ (function () ...

  6. SVN 提交回滚

    取消对代码的修改分为两种情况:   第一种情况:改动没有被提交(commit). 这种情况下,使用svn revert就能取消之前的修改. svn revert用法如下: # svn revert [ ...

  7. 重学 Java 设计模式:实战备忘录模式「模拟互联网系统上线过程中,配置文件回滚场景」

    作者:小傅哥 博客:https://bugstack.cn - 原创系列专题文章 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 实现不了是研发的借口? 实现不了,有时候是功能复杂度较高难以实 ...

  8. git远程库代码版本回滚方法

    最近使用git时, 造成了远程库代码需要回滚到之前版本的情况,为了解决这个问题查看了很多资料. 问题产生原因: 提交了错误的版本到远程库. 以下是解决的方法, 供大家参考: 1.对本地代码库进行回滚 ...

  9. JDBC03 利用JDBC实现事务提交与回滚【调用Connection中的方法实现事务管理】

    目录 1 Connection中的重用方法 2 JDBC事务管理经典案例 1 Connection类中常用的方法回顾 1.1 Statement createStatement() throws SQ ...

随机推荐

  1. 禁止VMware用户在系统里删除网卡的操作的方法

    点击选项-常规-配置参数,如下图所示:   8)点击“添加行”,在新的栏目中,左栏输入:devices.hotplug,右边栏输入:false

  2. 16、SQL基础整理(触发器.方便备份)

    触发器(方便备份) 本质上还是一个存储过程,只不过不是通过exec来调用执行,而是通过增删改数据库的操作来执行(可以操作视图) 全部禁用触发器 alter table teacher disable ...

  3. LCA(RMQ)

    ; xh=; ..lx*] of longint; lt,dfn,fr,dep:..lx] of longint; f:..lx*,..xh] of longint; vis:..lx] of boo ...

  4. 第一个Sprint冲刺第九天

    讨论成员:邵家文.李新.朱浩龙.陈俊金 工作:修改公式,修改bug

  5. iOS开发环境C语言基础 数组 函数

    1 求数组元素的最大值 1.1 问题 创建程序,实现查询数组中最大值的功能,需求为:创建一个长度为10的数组,数组内放置10个0~99之间(包含0,包含99)的随机数作为数组内容,要求查询出数组中的最 ...

  6. 七、CCScene

    CCScene一般情况是游戏里面的根节点,称之为"场景",运行游戏时需要通过CCDirector启动第一个场景.当然,游戏稍微复杂一点的话,可能会包含很多个场景,这就涉及到场景的切 ...

  7. shell MAC 地址 校验

    /*************************************************************************************** * shell MAC ...

  8. yii 隐藏index.php

    首先,开启apache的rewrite模块 去掉rewrite前的#,如下所示 LoadModule rewrite_module modules/mod_rewrite.so 接着,在yii的ind ...

  9. 扩展KVM镜像的虚拟磁盘大小

    当我们需要扩展模板镜像的虚拟磁盘大小时,比如原来的虚拟磁盘大小为20G,现在我们想将其扩展到30G,那么我们可以根据如下步骤来操作. 整个流程可以分为三个阶段: 1.扩展KVM镜像磁盘文件大小到30G ...

  10. VIM键盘快捷键映射

    http://www.jianshu.com/p/216811be226b