欢迎参与Java 事务讨论

*****************************
**JTA与JDBC中事务处理的区别**
*****************************
JTA(Java Transaction API) , 如begin(), commit()
JDBC中也有事务处理的API, 如begin(), commit()

两者都是控制事务的API, 不知它们有什么区别? 是不是底层实现相同?

****************************************
**另外,也谈谈我对CMP与Hibernate的理解**
****************************************
显然,CMP在处理复杂的查询时弱于Hibernate. CMP也没有动态查询。
但是,CMP在事务处理方面强于Hibernate, 原因是CMP与EJB容器结合,其CMT直接在Declarative transaction申明事务的类型,其它的事情交给EJB容器,代码量少,也容易维护。

*********************************************************
**在EJB中用hibernate代替CMP的可行性到底有多少?(好与坏)**
*********************************************************

顶一顶. 不相信大家对此不感兴趣。

先说一说hibernate:
在此之前大家对hibernate进行了很多讨论。由于我没有真正在项目中使用过hibernate,所以不敢乱说。但看了一些资料和使用hibernate的Sample后,我感觉使用hibernate并非会有根本性的好处(当然cmp也不是必须使用的)。
先列出2种后台层次结构:
1.一个使用hibernate的sample
sessionBean --> (domain object) -->DAO -->hibernate
2.我在上一个项目中使用的结构
sessionBean --> (domain object) -->DAO
比较上面2种结构,区别在于:
方式1在DAO中使用了hibernate进行persistence工作,实现对关系型数据库的操作;而我方式2中,是在DAO中使用jdbc直接操作关系数据库。

我的结论是:
1.方式1能做的事情,在方式2中都能做;而方式2能做的事情方式1不一定能胜任。例如在DAO优化方面,方式2要比方式1更灵活;

2.方式1在代码量方面不比方式2少。--实际上方式1需要维护的是o/r mapping 文件,而方式2可以通过代码生成工具方便地生成绝大部分代码

3.o/r mapping的概念,更应该是一个面向对象设计的原则。在实现的时候,直接在DAO使用JDBC操作数据库也是一种o/r 转换的做法。因此还是没有理由一定要使用hibernate。

说的片面之处,请各位指正.

>>**JTA与JDBC中事务处理的区别**

去找本教科书看

>>CMP在事务处理方面强于Hibernate, 原因是CMP与EJB容器结合,其CMT直接在Declarative transaction申明事务的类型,其它的事情交给EJB容器,代码量少,也容易维护

澄清一个事实:Hibernate本身没有事务处理功能!

如果在Session Bean里面调用Hibernate,一样可以使用CMT。

CMP的代码量比Hibernate只多不少,可维护性更加是一场恶梦!不要凭空去想,实际做做项目你就知道了。

>>**在EJB中用hibernate代替CMP的可行性到底有多少?(好与坏)**

如果你觉得你可以用Session Bean + DAO + JDBC可以取代Session Bean + CMP,那么你就可以一样用Session Bean + DAO + Hibernate取代 Session Bean + CMP。

Hibernate只不过是JDBC的一个非常好用,非常简单的lightweight的对象封装框架而已,没有必要老是拿来和CMP做对比。凡是用JDBC的地方,你都可以用Hibernate,仅此而已。

>>**在EJB中用hibernate代替CMP的可行性到底有多少?(好与坏)**


Hibernate的优点有很多,我相信前面的帖子已经讨论的够充分了。简单,易用,强大,灵活而且速度够快。

Hibernate的缺点从功能上来说,不适合处理批量update和delete(这也是ORM共同的缺点)。HQL只有select,没有update和delete。本来在HQL里面增加update和delete只不过是举手之劳而已。但是一旦在HQL里面增加update和delete,必须同步更新在JVM里面的persistent object,否则会造成persisent object的状态不一致的问题。这边厢数据库里面的记录已经被删除了,那边厢persistent object还在JVM里面好好的运行呢!

所以Gavin King建议批量update和delete使用JDBC,这也符合他的软件哲学,把95%的事情做到最好,剩下5%的瓶颈交给JDBC,“非不能也,是不为也”。

不过,实际上在一个面向用户交互的软件中,极少会遇到批量更新和批量删除的情况,即便遇到,批量处理的记录数也不会很多,一般用Hibernate处理也足够了。只有一些数据库后台维护程序会比较频繁的使用批量更新和批量删除,但对于这样的情况,直接使用数据库的C API更加符合要求。

另一个我曾经认为是Hibernate的缺点是不支持动态映射数据库表,不支持映射非表的其他数据库对象,当然这也是JDO,CMP同样的面临的问题。但我最近几天发现Hibernate完全可以做到。

在Hibernate中,persistent object通过XML Mapping文件映射到数据库表上,这样就不能动态映射不同的表,比如有时候会遇到根据不同的情况选择是从当前表还是从历史表中进行查询。不过persistent object通过XML Mapping文件也可以选择不映射数据库表,而是映射到一个Java class上,这样就可以自己编写一个ClassPersister,处理如何把persistent object和数据库进行数据映射。更进一步,通过该方法,也可以解决在Hibernate中调用Store procedure的问题。

说实话,从功能上就ORM这一点来说,我还没有发现Hibernate的缺点,大概是因为我对Hibernate研究还不够深入吧。

Hibernate好处很多,这也是为什么大家对此如此关注的原因。

sessionBean --> DAO(JDBC+SQL) 业务逻辑与数据库偶合太密。不利于扩展及维护。这个我以前做项目深有体会,特别是SQL量大的时候。并且ORM在数据库端是透明的,以前做项目用一种数据库SQL Server,后来又让支持另一种数据库Oracle,光写传参数和写if 语名判断不说,连有些SQL语句也要变,现在想起来还记忆有新。

所以我们才会用ORM这种映射。


“1.方式1能做的事情,在方式2中都能做;而方式2能做的事情方式1不一定能胜任。例如在DAO优化方面,方式2要比方式1更灵活;

Hibernate在SQL优化方面已经帮我们做了很多,自已优化需要对JDBC了解较深入,学习周期长。

“方式1在代码量方面不比方式2少。--实际上方式1需要维护的是o/r mapping 文件,而方式2可以通过代码生成工具方便地生成绝大部分代码

ORM 文件可以通过XDoclet去做,很方便,即使是Ojbect的属性有变化,只需用Xdoclet重新生成一次就行。但我现在还不知道如果数据库端若有变化,如何将变化自动或半自动的反映到Object这边,我对Hibernate还在了解中。


hi, robbin,以下我的总结不知是否正确,还望指点。

JDBC和JTA是BMT中的两种事务类型。
JDBC 事务受数据库的事务管理器控制。JTA 允许事务在不受数据库的事务管理器控制的情况下划分事务, EJB中利用JTS实施事务管理器,在代码中调用JTA方法,由JTA调用JTS提供的服务。所以JTA受JTS控制,JTS支持JTA. 如果事务要跨不同的数据库,就需要一个JTA事务。在BMT的SessionBean 中,也可以将 JDBC 和 JTA 事务混合在一起。但是这样做容易引起混乱,不利于维护代码。

我对hibernate还在了解中,可能看问题太片面。我想说的是,CMT比BMT代码量少。如果hibernate也可以用在CMT中,那SessionBean+hibernate确实是一个不错的组合。

"但是一旦在HQL里面增加update和delete,必须同步更新在JVM里面的persistent object,否则会造成persisent object的状态不一致的问题。这边厢数据库里面的记录已经被删除了,那边厢persistent object还在JVM里面好好的运行呢!"

的确,如果在同步的话,性能必定要打折扣。看样Gavin King也很圆滑呀。


"在Hibernate中,persistent object通过XML Mapping文件映射到数据库表上,这样就不能动态映射不同的表,比如有时候会遇到根据不同的情况选择是从当前表还是从历史表中进行查询。不过persistent object通过XML Mapping文件也可以选择不映射数据库表,而是映射到一个Java class上,这样就可以自己编写一个ClassPersister,处理如何把persistent object和数据库进行数据映射。更进一步,通过该方法,也可以解决在Hibernate中调用Store procedure的问题。"

你的意思是不是这个被映射的Java class,做为一个control的功能,然后由它来指向不同的数据库表。
如果是的话,那Hibernate功能实在强大。有没有相关的URL? 我也想研究一下。

>>sessionBean --> DAO(JDBC+SQL) 业务逻辑与数据库偶合太密。不利于扩展及维护。

用ORM的原因主要不是因为降低耦合。使用JDBC并不会造成和数据库过分的耦合,除非你总是用数据库扩展的SQL,而不是ANSI SQL92。当然ORM和数据库的耦合度更低。

自己使用JDBC来实现ORM绝不是blues说的那么容易的,要处理大量很棘手的问题,否则ORM就没有存在的必要了。简单的来说,一个复合持久对象你用JDBC实现ORM就非常麻烦,主要的困难不在于多表查询,在于你怎么实现动态的lazy loading?我相信blues没有用JDBC做过复杂的ORM工作,否则就不会这样想当然了。我在没有听说过ORM之前就是自己手工写JDBC代码来实现ORM的,一旦持久对象之间存在复杂的组合和聚合关系,很难按照OO设计做下去了。我曾经为此头疼过很久,一直没有好的解决办法,直到接触JDO和Hibernate,才算找到答案。


>>但我现在还不知道如果数据库端若有变化,如何将变化自动或半自动的反映到Object这边

http://hibernate.bluemars.net/52.html

ReverseEngTool可以这样做,但还不够好。可以手工修改XML Mapping File,然后用CodeGenerator自动生成代码。


>>在BMT的SessionBean 中,也可以将 JDBC 和 JTA 事务混合在一起。但是这样做容易引起混乱,不利于维护代码

不能混合使用,事务不能嵌套,会报错的。本质上来说,JDBC事务是由数据库管理的,JTA事务是由App Server容器的事务管理器来管理的。JTA可以实现跨数据库连接,跨域的事务控制。

在多个数据库参与事务的情况下,JTA管理方式颇有不同,需要启动2PC。第一阶段通知参与事务的各资源准备提交,如果有资源没有准备好,全体放弃;第二阶段真正提交,并且记录日志。另外JTA除了可以管理数据库资源外,也可以管理其他资源,比如JMS。


>>你的意思是不是这个被映射的Java class,做为一个control的功能,然后由它来指向不同的数据库表。

对。Hibernate里面提供了一个接口ClassPersister,其抽象了persistent class和数据库对象的映射操作。同时Hibernate也提供了两个
ClassPersister接口的具体实现类:

EntityPersister:根据Mapping 文件中定义的对象属性和表字段映射关系,处理"table-per-class-hierarchy" mapping
NormalizedEntityPersister:根据Mapping 文件中定义的对象属性和表字段映射关系,处理"table-per-subclass" mapping

默认情况下,Hibernate就是调用EntityPersister和NormalizedEntityPersister 来处理对象和表映射的。但如果EntityPersister和NormalizedEntityPersister都不能满足你的要求的话,就可以自己写一个ClassPersister的实现类,处理更复杂多变的动态映射关系。

最后在XML Mapping文件里面指定使用你自己写的ClassPersister实现类,而不使用默认的EntityPersister。由此也可以看出Hibernate本身具有很强的可扩展性,如果Hibernate功能不能满足你的需要,还可以自己扩充Hibernate的功能。相关介绍和例子见Hibernate文档第4.1.3节:

http://hibernate.bluemars.net/hib_docs/reference/html/or-mapping.htmlor-mapping-s1-3

多谢robbin的 Reference URL,我会仔细看看的。

ORM的优势我总结为:
将对象映像到关系数据库,多分出一个持久层,减少耦合.对关系数据库结构的简单改动并不影响你的面向对象代码的。而且应用程序开发者不需要了解关系数据库结构,事实上,他们甚至不需要知道对象是保存在关系数据库中。

"我在没有听说过ORM之前就是自己手工写JDBC代码来实现ORM的,一旦持久对象之间存在复杂的组合和聚合关系,很难按照OO设计做下去了"
厉害,凡是自已写ORM的人都不简单。佩服!
的确,对象之间的关系太难处理。一对一,一对多,多对多还可以通过外键和association 表解决,但对于组合和聚合这种M-M,O-M 关系来说,考虑增删改就太复杂了。这也就是老外说的 impedance mismatch. 关系数据库是基于关系数学,无法充分体现OO的关系。


"不能混合使用,事务不能嵌套,会报错的"
我可没说这两个要嵌套使用,难道JDBC和JTA不能是并行的关系,各管各的?

"在多个数据库参与事务的情况下,JTA管理方式颇有不同,需要启动2PC。第一阶段通知参与事务的各资源准备提交,如果有资源没有准备好,全体放弃;第二阶段真正提交,并且记录日志"

在第一阶段还有一个叫交易日志,不知与第二阶级参与者和协调者提交或中止记录写入的日志有什么区别?感觉是一样的。

另外,感觉2PC容易形成瓶颈.


"除非你总是用数据库扩展的SQL,而不是ANSI SQL92"
时间长了,我也记不得了,只记得那时SQL Server 与Oracle的左联,右联SQL语句写法不同,那时改得真的都发毛了。

Robbin,如果使用JDBC来进行update/delete操作,会不会在Hibernate的cache里得到反映?如果可以,我很想知道Hibernate是怎么知道何时需要更新cache的

> sessionBean --> (domain object) -->DAO -->hibernate

为什么要这么麻烦,

hibernate API
直接 service ---------------> POJO
不就可以了?

用了O-R Mapping工具,DAO是不需要存在的

> Robbin,如果使用JDBC来进行update/delete操作,会不会在H
> bernate的cache里得到反映?如果可以,我很想知道Hibernat
> 是怎么知道何时需要更新cache的

你的问题问得很好!答案是不可以。

上面我提到如果Hibernate可以在HQL里面批量update/delete,那么必须进行POJO的同步,这里面隐含一个前提,就是在同一个数据库连接里面处理。如果不是在同一个数据库连接里面处理的话,其实就不是Java程序能够控制的了,需要根据数据库设定的隔离级别来确定到底会产生什么样的结果。

"上面我提到如果Hibernate可以在HQL里面批量update/delete,那么必须进行POJO的同步,这里面隐含一个前提,就是在同一个数据库连接里面处理。如果不是在同一个数据库连接里面处理的话,其实就不是Java程序能够控制的了,需要根据数据库设定的隔离级别来确定到底会产生什么样的结果。"

不知我的理解是否正确。
你的意思是不是,如果在同一个数据库连接里面处理的话,通过设置JDBC transaction 隔离级别为Serializable mode?
如果是跨多个数据库的话,所有的数据库设置为最高隔离级别,这样才能保证批量update/delete完整性和一致性.