最近,用各种算是流行的方法写了些Hibernate的例子(基于测试)。上次打算写两篇文章。① Hibernate 常用工具的配置和使用。② Hibernate 比较简单的,基于单表操作的例子。写了80%吧。越想越感觉意义不大。现在网上很多这方面的文章。我自己也没有理由,自私的所谓备份。占用Blogjava的硬盘空间。就成了后来的 “冰 冻 闲 聊”
上个星期五,因为公司停电。所以休息了三天。一年前,这个数字可能会感觉太短。但是现在却是突然觉得连续三天不上班。不知道该干什么好。
难道是对这种“月光”族的生活上瘾拉?… 这样的话题,等以后想明白了再说吧!~
接着说这个周末吧!因为无聊,翻翻,去年用过的一些散乱的笔记。越看越搞笑,字迹潦草,还好基本上是一些技术痕迹。找不到从前那些“少年不知愁滋味”的感觉。
因为我一直不是很喜欢看书。现在的书,写得好的不多,但是价钱蛮贵的。所以,有时候就会把一些疑惑的问题写在一张纸上。然后去网上先收集一些资料,再阅读总结。
这里,我发现了一条有趣的问题。2004年12月3日 Hibernate使用JDBC和JTA管理事务有什么区别?傻傻的问题。不如今天就聊聊这个话题吧!可能,现在也会有人对这个问题感觉疑惑的。
打开hibernate.cfg.xml看看具体的JDBCTransaction 和 JTATransaction 配置:
11)
2<property name="hibernate.transaction.factory_class">
3org.hibernate.transaction.JDBCTransactionFactory
4</property>
5
62)
7<property name="hibernate.transaction.factory_class">
8org.hibernate.transaction.JTATransactionFactory
9</property>
10
可能你还会问:“除了这两种还有其他的选择吗?到底选择那一种好呢?在一个应用中能混合使用吗?”等等问题
分析和解答:
第一个问题
可以选择其他的事务管理方式。不过都是JTA的不同实现版本。这个目录下面有罗列出来hibernate-3.0\src\org\hibernate\transaction。比如:
1<property name="hibernate.transaction.manager_lookup_class">
2org.hibernate.transaction.WeblogicTransactionManagerLookup
3</property>
4
第二个问题
概念事务:事务就是能以整体的原子操作形式完成的一系列操作。
是不是感觉有些饶口?简单的说,事务 就是一个逻辑工作单元。其中包括一系列的操作。至于事务为什么会产生?有什么基本特性?等等。。这些问题今天不就详细的罗列了。网络上有写得很好的文章。
Hibernate 是JDBC的轻量级封装。他本身并不具备事物管理的能力。事务的管理和调度将委托给JDBC或者JTA去做。
先说,他默认的事务处理机制[ JDBC Transaction ],这的确是最简单的处理方式,因为Hibernate只是对JDBC事物做了一层简单
的封装。JDBC事务由Connection管理。事务周期局限于Connection的生命周期之内。在Hibernate中这种事务周期也就局限于一个Session之内。做个比较吧!
Connection conn = … ; <--- session = sf.openSession();// 初始化数据库连接,
和setAutoCommit= false;
conn.setAutoCommit(false); <--- tx = session.beginTransactioin(); 会再次确认setAutoCommit是否是false
调用业务方法 <--- 调用业务方法
conn.commit(); <--- tx.commit(); (对应左边的两句) 这里很关键,关掉自动commit。自己就必须做commit。否则数据是不会被持久到数据库
conn.setAutoCommit(true);
conn.close(); <--- session.close();
简单吧!如果你对JDBC有了解,看到这里可能会坏笑,NND就这么简单,我也会封装…有兴趣的话可以直接去看看具体的源代码。
看看第二种[JTA Transaction]有什么神奇的地方吧!
JTA 提供了跨Session的事务管理能力。JTA的事务是要容器支持的,即JTS,用来分布式的要求比较多一些,比如像银行这种大系统,处理多个事务源的这些的。
JTA事务管理则是由JTA容器实现。事务的生命周期完全由容器来维护。容器中可以有很多Connection。按照执行的顺序,因该是串联的一条JDBC Connection事务链。所以JTA的事务周期可以跨多个JDBC Connection的生命周期。在Hibernate中这种事务周期也就可以跨越多个Session。
所以。JTA事务的Connection不能对事务管理进行干涉。意思就是,假如使用了JTA就不应该再重复调用Hibernate的Transaction功能。这里涉及到一种事务模型(嵌套式事务模型)的问题。这里也不详细的介绍具体的几种事务模型了。在EJB2.0规范里面也不支持这种事务处理模型。
例如 :
1class A 有一个方法 savePerson()
2class B 有一个方法 saveAddress()
3// Call A.savePerson() and B.saveAddress() Used JTATransaction
4class C 有一个方法 saveAll()
5UserTransaction tx = (UserTransaction)(new InitialContext.lookup(“…”))
6A.savePerson();
7B.saveAddress();
8tx.commit();
9
那么下面这段代码
1Transaction tx = session.beginTransaction();
2tx.commit();
3
就不能在class A 和 class B 中出现。
原因:session.beginTransaction()也同样执行了InitialContext.lookup方法来获UserTransaction的实例,tx.commit()也同样调用了UserTransaction.commit().这样做就会形成嵌套式的事务。在Hibernate里面是不被允许的。会导致运行期错误。
谈到这里,不难看出,他们都有着自己鲜明的特点和基本的联系。回到开头的问题,在实际项目中该选用谁好呢?
这就需要分情况而定了。
1) 如果项目有用到Sessionbean.可能你会疑问?这时候由谁来管理事务呢?
答案:用SessionBean来管理。使用JTA会很方便。因为你完全没有必要去理会Transaction。直接在SessionBean的部署描述符里面声明事务就行了。
2) 自己实现一个Service类,来统一调用持久层的方法。这样也能做到前后台的松耦合。但是这时候你对session和Transaction的处理就需要小心了。如果系统考虑分布式就使用JTA否则就JDBC足夷。但还是有必要考虑系统的升级,变迁什么的。对session和Transaction的处理,最好不要放在DAO里面做。单独实现一个模板类来统一做。具体的原因和做法,以后有时间再写出来。
第三个问题
由于SessionFactory是线程安全的,他的创建过程非常复杂,代价极其昂贵。一个应用中最好只有一个SessionFactory。事务管理类型的选择是在SessionFactory的属性里面配置的。这里只能选择一种事务管理方式。
当然,你可以说还有特殊的情况,假如,这个应用需要连接到两台数据库服务器,就必须为他创建另一个SessionFactory。那么就可以选用另一种事务管理方式。表面上看这种情况是可以的。居于两种事务的性能考虑。混和用的意义不是很大。假设这样用+面对考虑不周全的DAO,也违背了设计原则,想想,这样的话,因为数据库的变动,还得回去修改DAO的代码吗?(可能会产生嵌套问题)
所以关于这个问题的结论就是:
在一个SessionFactory中只能选用一种事务管理
面对多个SessionFactory的时候,可以混合用,但是不推荐
2005-11-28 CTU OFFICE GOINGMM