对于JBoss中容器管理的事务的疑惑

我在SessionBean中写了一方法,该方法实现了对于同一个数据源,两步数据库的操作,都是直接调用的SQL语句。第一个SQL语句负责对一个已经存在的表进行插入记录的操作,它下面紧接的SQL对一个不存在的表做更新操作。SessionBean是容器管理的事务,并且该SessionBean中所有方法都是Required。本以为捕获到SQLException后(表或视图不存在),EJB Container会对事务做回滚操作。可实际上,EJB Container并没有这么做,我查了下数据库,发现记录已经插入进去了!

我后来把由容器管理的事务改为Bean管理的事务,于是在代码里加了
UserTransaction ut = null;
try {
ut = sessionContext.getUserTransaction();
ut.begin();
....
ut.commit();

}catch(SQLException es) {
es.printStackTrace();
try{
ut.rollback();
}catch(SystemException se) {

}
}
.....

用这样Bean管理的事务的时候,就没有问题,事务可以回滚,不会有记录被插入。

更有意思的是,我还是用容器管理的事务类型,我尝试在SQLException的catch中抛出更底层一点的异常 throw new RuntimeException();事务居然能正常回滚!

这个问题困绕了我两天,不知大家可否遇到,有兴趣的话试试,期盼各位的结果!
开发环境JBoss3.0.8 + JBuilder9.0 + JBossOpenTool(本人试过JBoss3.2.3,JBoss3.2.5结果都一样)

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

Re: 对于JBoss中容器管理的事务的疑惑 发表时间: Aug 21, 2004 7:06 PM
回复
发表人: banq    发表文章: 4532 / 来  自: 上海 / 注册时间: 2002-08
看你使用什么数据库,oracle必需使用oracle-xa-ds.xml配置数据源。

我曾经亲自动手在MySQl 4.0上试验OK。


Re: 对于JBoss中容器管理的事务的疑惑 发表时间: Aug 21, 2004 7:57 PM
回复
发表人: daquan198163    发表文章: 136 / 注册时间: 2003-08
提倡用容器管理的事务。
但是你在捕获SQL异常后,应该写一句:
sessionContext.setRollBackOnly(),
因为容器只有在捕获EJBException时才会回滚。

见《EJB设计模式》相关章节


Re: 对于JBoss中容器管理的事务的疑惑 发表时间: Aug 21, 2004 8:07 PM
回复
发表人: mk    发表文章: 12 / 注册时间: 2004-08
如果是Oracle的话一定要用Oracle-xa-ds.xml吗?不是吧,那为什么用Bean管理的事务就可以呢?难道用普通的Oracle-ds.xml就不能回滚了?

楼上那位仁兄,能不能告诉我那句话在《EJB设计模式》第多少页,先3Q了!


Re: 对于JBoss中容器管理的事务的疑惑 发表时间: Aug 21, 2004 8:32 PM
回复
发表人: mk    发表文章: 12 / 注册时间: 2004-08
谢谢楼上的那位兄弟,我在《EJB设计模式》里找到了。(第228页)

它上面说的application exceptions和developer written exceptions应该不包括RuntimeException,所以在抛那个异常的时候能正常回滚。

像它这样做,自由度就提高了些,不是所有的异常都进行回滚。这点确实很重要啊,否则真的出现了数据的不一致性就麻烦了!


Re: 对于JBoss中容器管理的事务的疑惑 发表时间: Aug 21, 2004 9:06 PM
回复
发表人: daquan198163    发表文章: 136 / 注册时间: 2003-08
你看的是那本翻译的吗,在166页,一共才205页呀,哈哈


Re: 对于JBoss中容器管理的事务的疑惑 发表时间: Sep 7, 2004 4:26 PM
回复
发表人: cats_tiger    发表文章: 147 / 注册时间: 2003-05
> 谢谢楼上的那位兄弟,我在《EJB设计模式》里找到了。(第2
> 8页)

_0_我的一共就205页


Re: 对于JBoss中容器管理的事务的疑惑 发表时间: Aug 22, 2004 12:55 PM
回复
发表人: mk    发表文章: 12 / 注册时间: 2004-08
我这是英文版的啊! 一908KB的PDF文档啊!


Re: 对于JBoss中容器管理的事务的疑惑 发表时间: Aug 22, 2004 12:57 PM
回复
发表人: mk    发表文章: 12 / 注册时间: 2004-08
ejbdesignpatterns.pdf

我忘了在哪下的了,一共289页。


Re: 对于JBoss中容器管理的事务的疑惑 发表时间: Aug 25, 2004 11:32 AM
回复
发表人: daquan198163    发表文章: 136 / 注册时间: 2003-08
12个最重要的J2EE最佳实践

…………

8. 使用容器管理的事务。

学习一下 J2EE 中的两阶段提交事务,并且使用这种方式,而不是开放您自己的事务管理。容器在事务优化方面几乎总是比较好的。

使用容器管理的事务(CMT)提供了两个关键的优势(如果没有容器支持这几乎是不可能的):可组合的工作单元和健壮的事务行为。

如果您的应用程序代码显式地使用了开始和结束事务(也许使用 javax.jts.UserTransaction 或者甚至是本地资源事务),而将来的要求需要组合模块(也许会是代码重构的一部分),这种情况下往往需要改变事务代码。例如,如果模块 A 开始了一个数据库事务,更新数据库,随后提交事务,并且有模块 B 做出同样的处理,请考虑一下当您在模块 C 中尝试使用上述两个模块,会出现什么情况呢?现在,模块 C 正在执行一个逻辑动作,而这个动作实际上将调用两个独立的事务。如果模块 B 在执行中失败了,而模块 A 的事务仍然能被提交。这是我们所不希望出现的行为。如果,相反地,模块 A 和模块 B 都使用 CMT 的话,模块 C 也可以开始一个 CMT(通常通过配置描述符),并且在模块 A 和模块 B 中的事务将是同一个事务的隐含部分,这样就不再需要复杂的重写代码的工作了。

如果您的应用程序在同一个操作中需要访问多种资源,您就要使用两阶段提交事务。例如,如果从 JMS 队列中删除一个消息,并且随后更新基于这条消息的纪录,这时,要保证这两个操作都会执行或都不会执行就变得尤为重要。如果一条消息已经从队列中被删除,而系统没有更新与此消息相关的数据库中的纪录,那么这种系统是不稳定的。一些严重的客户及商业纠纷源自不一致的状态。

我们时常看到一些客户应用程序试图实现他们自己的解决方案。也许会通过应用程序的代码在数据库更新失败的时候 “撤销”对队列的操作。我们不提倡这样做。这种实现要比您最初的想象要复杂得多,并且还有许多其他的情况(想象一下如果应用程序在执行此操作的过程中突然崩溃的情况)。作为替代的方式,应该使用两阶段提交事务。如果您使用 CMT,并且在一个单一的 CMT 中访问两阶段提交的资源(例如 JMS 和大多数数据库),WebSphere 将会处理所有的复杂工作。它将确保整个事务被执行或者都不被执行,包括系统崩溃、数据库崩溃或其他的情况。其实现在事务日志中保存着事务状态。当应用程序访问多种资源的时候,我们怎么强调使用 CMT 事务的必要性都不为过。


Re: 对于JBoss中容器管理的事务的疑惑 发表时间: Aug 25, 2004 11:28 PM
回复
发表人: banq    发表文章: 4532 / 来  自: 上海 / 注册时间: 2002-08
>sessionContext.setRollBackOnly(),

在EJB方法中不需要写任何语句,只要有Exception抛出,就可以事务回滚。


Re: 对于JBoss中容器管理的事务的疑惑 发表时间: Aug 26, 2004 9:12 AM
回复
发表人: daquan198163    发表文章: 136 / 注册时间: 2003-08
>只要有Exception抛出,就可以事务回滚

banq ,好像跟弗洛伊德说得不太一样呀


Re: 对于JBoss中容器管理的事务的疑惑 发表时间: Aug 30, 2004 9:32 AM
回复
发表人: holykeeper    发表文章: 25 / 注册时间: 2004-06
应该是抛出系统级的异常才可以回滚,包javax.ejb的异常类中,除了NoSuchEntityException和EJBException属于系统级异常外,其他的异常全部是应用级异常。
照搂主的说法还有
RuntimeException也属于系统级的。

但一个异常究竟属于哪个级别,从哪里查阿?


Re: 对于JBoss中容器管理的事务的疑惑 发表时间: Aug 30, 2004 9:51 AM
回复
发表人: daquan198163    发表文章: 136 / 注册时间: 2003-08
确切的说是运行时异常,即RuntimeException及其子类,也就是那些即使抛出也不需要声明throws 的


Re: 对于JBoss中容器管理的事务的疑惑 发表时间: Aug 30, 2004 9:56 AM
回复
发表人: wwlhp@jdon    发表文章: 66 / 注册时间: 2003-04
总结一下,
1> 如果bean抛出RuntimeException,容器会自动回滚事务,并且在外面包装一个RemoteException抛出。
2> 如果bean抛出其他的异常,容器不会做任何处理。


Re: 对于JBoss中容器管理的事务的疑惑 发表时间: Sep 7, 2004 11:02 AM
回复
发表人: zdbj2ee    发表文章: 16 / 注册时间: 2003-08
JBOSS这个东西,EJB容器管理事务有问题,我在jboss和oracle8.17使用XADataSource也就是oracle-xa-ds.xml配置,在ejb中得到数据库连接正常
但在容器提交tx事务时,出错,说什么xid错误.我把这段代码放在weblogic中一点问题都没有。JBOSS让人无法理解。我现在已改用weblogic了,没办法。


Re: 对于JBoss中容器管理的事务的疑惑 发表时间: Sep 8, 2004 4:06 PM
回复
发表人: mk    发表文章: 12 / 注册时间: 2004-08
出了什么错,帖出来嘛!我说不定能找得到!

我前段时间刚在JBOSS配置过XA DataSource。中间是很多环节都容易出错。主要原因不是Application Server的问题,而是像Oracle这样支持分布式数据库的问题。按网上Oralce的安装攻略,安装好的Oracle,其实根本还不支持分布式事务,需要另外做一些初始化的工作。


Re: 对于JBoss中容器管理的事务的疑惑 发表时间: Sep 24, 2004 1:14 PM
回复
发表人: liuluo    发表文章: 1 / 注册时间: 2004-04
> >sessionContext.setRollBackOnly(),
>
> 在EJB方法中不需要写任何语句,只要有Exception抛出,就可

banq还真顽固,不懂装懂呵呵


Re: 对于JBoss中容器管理的事务的疑惑 发表时间: Jan 26, 2005 10:10 PM
回复
发表人: 阿木欢    发表文章: 3 / 注册时间: 2005-01
> >sessionContext.setRollBackOnly(),
>
> 在EJB方法中不需要写任何语句,只要有Exception抛出,就可
> 允挛窕毓觥?
请参考EJB的规范,并不是只要有Exception抛出就可以回滚,而是RuntimeException


Re: 对于JBoss中容器管理的事务的疑惑 发表时间: Sep 8, 2004 4:20 PM
回复
发表人: mk    发表文章: 12 / 注册时间: 2004-08
鉴于有的道友看不到《EJB设计模式》的原话,我在这里还是把它列出来。


引用《EJB设计模式》里的原话,第228页

[b]Always Call setRollbackOnly when
Application Exceptions Occur[/b]

An important but unemphasized fact is that application exceptions(developer
written exceptions) thrown from an EJB to client don't trigger automatic
rollbacks of the running transaction,in contrast to EJBExceptions,which auto-
matically trigger the current transaction to roll back.Serious data consistency
problems can arise if a use case fails without the transaction rolling back.
Therefore,always remember to first catch application exceptions and call
ctx.setRollbackOnly() (where ctx is of type javax.ejb.SessionContext
for session beans)before rethrowing or wrapping application exceptions to the
client.

我同意有位道友的观点,遇到运行时异常(RuntimeException)及其子类,容器管理的Bean才回滚。
在文中提到的EJBException是RuntimeException的子类。而SQLException,NamingException的父类是Exception。个人感觉就《EJB设计模式》中所说的application exception概念有的笼统,按习惯性的思维SQLException应该不会包括在里面。

哎,可是事实胜于雄辩。


Re: 对于JBoss中容器管理的事务的疑惑 发表时间: Sep 10, 2004 12:17 PM
回复
发表人: daquan198163    发表文章: 136 / 注册时间: 2003-08
嗯,有了这些理论基础,我们就可以方便的搭建这样的系统了:
struts+BusinessDelegate(业务代理)+SLSB(封装业务逻辑)+DAO(数据访问逻辑)

我们都知道,struts实现了MVC中的V和C,对M没有实现,我们需要写一些业务代理(普通java对象)来实现M,所谓的业务代理只不过是隐藏了对SLSB的查找逻辑和一些异常的包装;SLSB封装了业务逻辑,它通过JNDI获取数据源,然后取得连接,然后用数据库连接构造若干DAO并调用起方法,对事物进行管理(例如当DAO抛出SQLException时调用ctx.setRollbackOnly() ,这样保证了数据的完整性)

你可能感兴趣的:(设计模式,exception,数据库,jboss,ejb,application)