关于EJB把真正的逻辑 "委托" 给受Spring管理的POJO 后失去transaction 力度的说法是错误的,我都做了测试,可能你对事务的理解有些片面,你有责任改正,你的有些观点有些偏激,不要误人子弟。

我做了测试,你的所谓ejb command pattter的粗粒度事务问题的说法是不成立的,而且说句实话,你的那个框架从思想及使用的方便性等都没法跟appfuse比,希望你不是出于商业目的而发表一些误人子弟的言论。

to rambostar
你把测试代码和方案贴在这里吧,我也再来测试一下,粗粒度问题早在Petstore出来时就提到这个问题,见帖子:
http://www.jdon.com/jive/thread.jsp?forum=61&thread=15476

EJB的方法实现如果是委托一个普通JavaBeans的方法实现,那么这个普通JavaBeans的方法实现中将没有事务回滚,除非你在javabeans的方法中自己提供事务,这是基础常识啊。

说真的,这个基础常识我还真的不懂(我看过的e文书都没有提到过这一点)。鉴于自己机器和服务器太差,我到现在还懒的自己去测试一下。但从理论上,为什么ejb要留出这么个细粒度问题?是技术实现有困难(这一点我很怀疑),还是出于设计上的考虑?

这实际属于嵌套事务,如果没有这种粗粒度问题,就不必有嵌套事务这个概念。

你这么一说我才想起来,jta等二步提交方式的事务管理只支持flattern 事物,不支持嵌套事务。可怜我做了这么久居然没发现这个问题。。

不过bang 你要早这样说,我也不用为“粗粒度”这个概念困惑这么久了。tmd,这确实是个基础概念。不过这只是对于jta着种分布试的二步提交的事务方式而言。对于jdbc这种本地事务应该是支持嵌套事务吧?如果是这样,楼上那位老兄估计是利用jdbc事务做出的测试结果吧?

一个EJB方法内不允许有多个事务,那当然也包括嵌套事务,这个我是知道的,我做的测试也非常简单,weblogic8+mysql,无状态session ejb,事务属性为required,connection是从weblogic8连接池中获取的,整个测试没有写任何与事务相关的代码。

1:EJB--->非EJB类--->EJB (petstore的ejb command模式+session facade模式),这个是肯定OK的;

2:EJB--->非EJB类(无update操作)--->2个非EJB类(有update操作),在这种情况下,如果非EJB类的connection是从ejb中获取的,那也肯定没有事务问题;

3:EJB--->非EJB类(无update操作)--->2个非EJB类(有update操作),autocommit = false,非EJB类中有关闭connetion操作,测试结果也是可以回滚的,没有任何问题;

另外,jpetstore中也有ejb command的代码,它也没有粗粒度事务问题,所以单纯的讲一个东西有粗粒度事务问题,而不看它的上下文环境及前提条件是不行的。

补充说明:在上面的测试3中,2个非EJB类中都有关闭connection的操作,JDBC事务的autocommit缺省也为false,我以上3个测试都没有问题。

总之,要根据需求来确定你的项目到底需要什么样的事务控制,而且对于上面的测试2,可以提高性能,避免数据库锁。

weblogic有cluster相关的接口。
> 2.Sping 就把 性能的扩展性任务推给了 web
> container,那么我们就要求有一个好的Web容器提供Cluster?> 持,但是遗憾的是,目前J2EE标准中并没有和涉及Web容器的?> 何Cluster定义或接口,所以造成有的Web容器提供Cluster,?> tomcat有一些,jetty比较好,大部分商业化产品如Weblogic?> 没有,它们把Cluster集中在EJB层了。

To Benq:
刚刚看到你的文章,我觉得你在EJB的事务处理机制上有误解:
引用:
 下面以代码描述什么是粗粒度事务机制:

  ejb方法:
  public void updateUser(){
    service.updateUser();
  }

  service是一个POJO,具体方法可能是更新两个表:
  public void updateUser(){
    updateTabel1();//更新table1
    updateTable2(); //更新table2
  }
当updateTable2()抛出异常,updateTable1()是不回滚的。这样,table1中就有一条错误的多余的记录,而table2则没有这条记录。

  那么,怎么做才能使两个表记录一致,采取事务机制,只有下面这样书写才能实现真正事务:
在EJB方法中写两个方法,因为EJB方法体缺省是一个事务。
  public void updateUser(){
    updateTabel1();//更新table1
    updateTable2(); //更新table2
  }

我不明白为什么一定要在EJB中调用DAO中的方法。实际上在你举出的没有“事务一致性”的例子中,只需要在POJO里面得到处理的异常或者是一个标识是否成功的标志就可以在EJB中回滚事务,我想大家也都很清楚用什么方法:sessionContext.setRollbackOnly();
上面的代码稍做改动:
ejb方法:
  public void updateUser(){
ReturnValue ret = service.updateUser();
if(ret.errorCode != Constant.SUCCESS){
sessionContext.setRollBackOnly();
}
  }
POJO方法:
public ReturnValue updateUser(){
ReturnValue ret = new ReturnValue()
try{
dao.updateTable1();
dao.updateTable2();
}catch(BusinessException e){
ret.errorCode = e.getErrorCode;
}
return ret;
}
一样可以保证事务的完整性,当然,这种事务的保证必须依赖JTA。所以任何事情都要根据不同的情况来分析,不能盲目的就下定论。

> weblogic有cluster相关的接口。
> > 2.Sping 就把 性能的扩展性任务推给了 web
> >
> container,那么我们就要求有一个好的Web容器提供Cluster?
> 持,但是遗憾的是,目前J2EE标准中并没有和涉及Web容器的
> >
> 何Cluster定义或接口,所以造成有的Web容器提供Cluster,?
> tomcat有一些,jetty比较好,大部分商业化产品如Weblogic
> > 没有,它们把Cluster集中在EJB层了。

不明白你为什么要这么去考虑性能的问题,web层的性能可以通过loadbalance去保证,这是硬件级别的,但是你如何去保证你业务层的性能并且保证事务的完整性??难道还是loadBanlance,有一点我觉得你理解不对,J2EE关注的是Service服务,并不是表现层。

大家好,第一次在这个论坛上发贴,请多关照。

发这个贴子,主要是因为不敢苟同这篇文章里关于所谓的“粗粒度事务机制“的描述。 说句实话,在到这个论坛之前,从来没听过“粗粒度事务机制“ 这种说法。(后来google了一下,除了这个论坛,别的地方也没有用到这个词,不会是文章作者的原创吧......)

这两天正好接了一个J2EE项目,准备把logic全放到POJO里面,用SESSION BEAN做个壳。 这个项目跟算钱有关,对TRANSACTION要求非常严格。然后突然看到这篇文章说到了“粗粒度事务机制" 的问题,自然出了一身冷汗。如果POJO和EJB的TRANSACTION 配合有问题,失败了还不能ROLLBACK,小弟我的这点工资可不够陪人家损失的..... 所以这两天一直在钻研这个问题,最后终于理顺了条理,下面跟大家报告一下,希望能有所帮助。

问题的本质在于,从EJB 到 POJO 的调用, TRANSACTION 有没有 PROPAGATE 到POJO?
(当然,EJB已经在TRANSACTION CONTEXT里面。) 结论是,TRANSACTION 可以 PROPAGATE 到 POJO 里面去。

例子:ejb方法:
  public void updateUser(){
    service.updateUser();
getSessionContext().setRollbackOnly(); ------- ROLLBACK TWO UPDATES
  }

  service是一个POJO,具体方法可能是更新两个表:
  public void updateUser(){
    updateTabel1();//更新table1
    updateTable2(); //更新table2
  }

在这个例子里面,updateUser() 执行完毕时, 两个table 的 update 动作都会回滚(虽然他们是在POJO 里面做的,但是他们仍然属于GLOBAL TRANSACTION). 为什么会这样? 因为EJB 里的transaction 是基于JTA, 在JTA 的定义里:The TX Context is tied to the current thread. 注意,是thread, 而不管你是什么bean. 所以, 只要我们的POJO不做thread的操作, EJB 就可以调用随便多少个POJO, 而TRANSACTION 会自动的 PROPAGATE 到POJO里面去。(要注意的一点是:在POJO里面, JDBC的connection 必须支持xa 接口。)

还有一些其他比较复杂的情况,比如POJO是remote的怎么办?这篇文章有很好的介绍:http://www-106.ibm.com/developerworks/java/library/j-jtp0410/?open&l=907,t=gr


在原文里,关于上面的例子,是这样说的:

当updateTable2()抛出异常,updateTable1()是不回滚的。这样,table1中就有一条错误的多余的记录,而table2则没有这条记录。

那么,怎么做才能使两个表记录一致,采取事务机制,只有下面这样书写才能实现真正事务:
在EJB方法中写两个方法,因为EJB方法体缺省是一个事务。
  public void updateUser(){
    updateTabel1();//更新table1
    updateTable2(); //更新table2
  }

这些话说了等于没说,看上去好像高深莫测,浑然天成,其实是nonsense。

首先,"updateTable2() 抛出异常,,updateTable1()是不回滚的." 是什么异常?是SQLException?那么 updateTable1() 当然不会回滚了。不是所有的异常都会导致 EJB Transaction 的回滚, 只有runtime exception 才会导致(我记得有另外一篇贴子说的就是这个事情,其实看看J2EE spec 不就什么都清楚了)。

其次, 如果抛出的是SQLException , 那么在第二中调用中,用EJB method一样不会回滚, 原因同上。如果是 run time exception, 那么,不管在那种调用中, 都会回滚。

综上所述, ”粗粒度事务机制“ 其实根本不存在, 庸人自扰而已。

欢迎大家讨论。


同意idxp的观点,刚看到banq的例子的时候就觉得奇怪,在EJB方法里更新就能回滚,通过另一个对象的方法更新就不能回滚,从常识上来讲也讲不通啊,凭什么要求我一定要把所有的数据库操作都写到一个方法里呢?
不过看大家都没提什么异议,还围绕这个问题讨论半天,都没敢出声,怕自己理解错误,总算看到一个想法一致的,声援一下。
不过没有idxp分析的细致,没有去考虑线程的问题

转贴:我为什么没有使用Spring

在这里,Spring指的是Spring开发框架,一种依赖注入容器的实现。首先,我声明我没有一点冒犯Rod的意思(你是个优秀的人)。但是坦白地说,我不能狂热的追随您的开发框架。更为严重的是,我注意到,我所考虑的这些可能对于Spring框架的使用率来说是危险的,并且有可能降低对Spring框架的使用率。我读到一个关于Spring的很重要的文章或书籍,看起来好像除了我,所有的人都喜欢Spring。但是我有什么损失吗?可能采用Spring是J2EE一个类似“膝跳反射”的事情(这种事情可以不经过大脑)。“J2EE不是好东东,Spring的人说他们的产品更好一些,所以Spring一定是好的”但是事情并不是那样的。


第二点,我仅仅讨论Spring,而不讨论依赖注入。我喜欢依赖注入,并且每天都使用它。它是一个摆脱service locators的好方法。

我记不得有多少次有开发者对我说,“我的上一个项目使用了Spring,这个框架真好”。但是没有人能清楚明白的说出他们究竟喜欢Spring的哪一点,Spring到底帮助了他什么。所以我敢说,他们喜欢setter注入,这使得他们的代码更加灵活和可测;但并不一定必需Spring。我猜有些人并没有彻底理解依赖注入,所以他们依赖Spring来帮助(或者强迫?)他们使用依赖注入。然而,这种好处并没有在量上大于Spring在你的代码上带来的负面影响,这些负面相应在下面的清单上。

Spring的狂热者公开的指责J2EE,但是从他们的指责中,我可以说,Spring实际上既不是轻量级也不简单。Javadocs未必是必要的,但是这一切都要怪罪于一个用户API吗?最起码J2EE清晰的将API和它们的实现分离开来。Spring的鼓吹者吹捧Spring不会“动”你的代码,例如,你不必去实现任何的Spring指定的接口(生命周期接口除外等等)。新闻特写,“XML配置文件是我们自己的代码,通过它,我们能组织起很多的代码,这些代码都是Spring给定的”

为什么我一定要把我所有的依赖使用XML文件来表达?我是需要把我所有的对象都用Spring来处理,还是仅仅一些没有考虑成熟的?上面我所说的这些问题,Spring文档没有给出一些可靠的答案,而且所有的Spring书籍也没有给出。我假定我们使用Spring是为了产生所有的对象。那么这样还是我们喜欢的Java编程吗?我希望在编译期和随后的装载期能够确定这些对象,而不是在运行我的代码的时候才能够确定。Spring能做到支持这些吗?

很明显,我希望装载一些像JDBC驱动这样的动态实现的依赖(即不要求编译期的检测);但是在我的系统中,这样的依赖只是一小部分;而剩下的部分,我们代码的绝大部分却不是。我是在使用一种强类型的语言。如果我希望像Spring那样,我会使用Ruby。难道Spring的配置文件不像是我们在猜测着将Java代码写入XML文件里吗?难道那些使用Spring的开发者使用起Java来不那么舒服?我确信增加了一个XML层并不能使得代码变得哪怕是一点点简单。

现在回过头来谈谈关于对Spring API的依赖的问题。我不得不调用容器来产生我的第一个对象(假定剩下的Spring管理对象是注入的),不是吗?我需要一些方法在编译期间来测试我所请求的对象是正确的类型;我不想靠抛出违例的方法。究竟,我真的需要一个容器吗?在Spring里,你通过使用一个唯一的ID来获取对象。我假定大部多数的开发者在他们Java代码里使用一个String类型的常量来定义他们的ID。Spring并不能帮助我使得我的Java代码里的ID值和我的XML文件里的ID值保持一致。当一个对象已经够用了的时候,为什么要使用两个对象?是否我们真的把所有的信息组织到一起放到了容器里?是Java的包和类不够用了吗?

还有一个困扰我的问题是,在我的XML配置文件里,我不得不引用Spring实现的类,我不想管这些东西。在Spring的计划里,我听说更加简单的、域范围的XML将在2.0版本中被使用,但是我到现在还没有看到。为什么这些不能早一点被采用呢?

什么继承上的东西啊?关于超常类名置换的变换。但这些都不是我的风格。

Spring在哪里支持了JDK1.5的泛型?我知道你有很多客户运行在JDK1.4甚至JDK1.3的版本上,但是这和JDK1.5没有分歧啊。泛型打开了通向像这种框架的各种各样的可能性的大门。这些是我最喜欢的JDK1.5的新特性,拥抱这些新特性吧!

你曾经看过每次你产生一个对象Spring要做多少事情吗?我需要在运行期内有少量的instanceof,而大多数是在装载期的Class.isAssignableFrom()。不是因为内部的实现给最终用户带来了很多的麻烦,而是因为把它作为了一个测试框架剩下部分质量的试金石。一个好的对于bean的创建渠道的重构将会很容易的被遵循和产生更加高质量的代码,并且不需要求助于更多的继承就能被重用。

Auto-wiring也有同样的问题。每一个人真的在使用它吗?或者是为未来的重要功能的一个铺垫?
  Spring是怎么处理领域范围的?我听说在2.0版本中,Spring最终会支持HTTP request和session的。我很惊讶难道现在这些没有被支持吗,那么Spring的用户在整个期间里都做了些什么。难道是新的版本将使我能够定义自己的领域范围?例如,它将实现我想要一个“conversation”领域范围,就像Seam将要支持的那样。

我们将不涉及MVC或者AOP框架。幸运或者不幸的是在某一时候,我将不使用一个依赖注入容器。难道不认为PicoContainer已经远离了简单二字。它也和Spring有同样的问题,我认为Aslak和Jon已经转移到了Ruby的领地。还有其他的开发框架没有这样的问题吗?

幸运地,简单的采用依赖注入设计模式能让你完成Spring的90%的工作,特别是当你在并不急于使用它的时候。这是我推荐的方法。我的确没有看到让我自己马上使用Spring的理由。没有它我工作的很好。如果你在使用它,那么请你把眼睛睁大一些,使用怀疑的、鉴赏的目光。如果仅仅因为某人有流行的开源框架,他们有很好的市场,并且他们被一些大的公司支持(IBM在很多年前就推荐我使用Struts)。但这并不意味着他们知道什么工具对你最好,尽管他们比你知道什么是更好的。