Hibernate事务处理机制 (1)

 Hibernate事务处理机制 

Hibernate事务处理机制(1)

Hibernate是对JDBC的轻量级对象封装,Hibernate本身是不具备Transaction处理功能的,Hibernate的

Transaction实际上是底层的JDBC Transaction的封装,或者是JTA Transaction的封装,下面我们详细

的分析:

Hibernate可以配置为JDBCTransaction或者是JTATransaction,这取决于你在hibernate.properties中

的配置:

#hibernate.transaction.factory_class net.sf.hibernate.transaction.JTATransactionFactory
#hibernate.transaction.factory_class net.sf.hibernate.transaction.JDBCTransactionFactory

如果你什么都不配置,默认情况下使用JDBCTransaction,如果你配置为:

hibernate.transaction.factory_class net.sf.hibernate.transaction.JTATransactionFactory

将使用JTATransaction

不管你准备让Hibernate使用JDBCTransaction,还是JTATransaction,我的忠告就是什么都不配,将让

它保持默认状态,如下:

#hibernate.transaction.factory_class net.sf.hibernate.transaction.JTATransactionFactory
#hibernate.transaction.factory_class net.sf.hibernate.transaction.JDBCTransactionFactory

在下面的分析中我会给出原因。

一、JDBC Transaction

看看使用JDBC Transaction的时候我们的代码例子:

Session session = sf.openSession();
Transaction tx = session.beginTransactioin();
...
session.flush();
tx.commit();
session.close();

这是默认的情况,当你在代码中使用Hibernate的Transaction的时候实际上就是JDBCTransaction。那么

JDBCTransaction究竟是什么东西呢?来看看源代码就清楚了:

Hibernate2.0.3源代码中的类

net.sf.hibernate.transaction.JDBCTransaction:

public void begin() throws HibernateException {

...
if (toggleAutoCommit) session.connection().setAutoCommit(false);
...
}

这是启动Transaction的方法,看到 connection().setAutoCommit(false) 了吗?是不是很熟悉?

再来看

public void commit() throws HibernateException {
...
try {
if ( session.getFlushMode()!=FlushMode.NEVER ) session.flush();
try {
session.connection().commit();
committed = true;
}
...
toggleAutoCommit();
}

这是提交方法,看到connection().commit() 了吗?下面就不用我多说了,这个类代码非常简单易懂,

通过阅读使我们明白Hibernate的Transaction都在干了些什么?我现在把用Hibernate写的例子翻译成

JDBC,大家就一目了然了:

Connection conn = ...; <--- session = sf.openSession();

conn.setAutoCommit(false); <--- tx = session.beginTransactioin();

... <--- ...

conn.commit(); <--- tx.commit(); (对应左边的两句)
conn.setAutoCommit(true);

conn.close(); <--- session.close();

看明白了吧,Hibernate的JDBCTransaction根本就是conn.commit而已,根本毫无神秘可言,只不过在

Hibernate中,Session打开的时候,就会自动conn.setAutoCommit(false),不像一般的JDBC,默认都是

true,所以你最后不写commit也没有关系,由于Hibernate已经把AutoCommit给关掉了,所以用

Hibernate的时候,你在程序中不写Transaction的话,数据库根本就没有反应。
(未完待续)


Hibernate事务处理机制(2)
责任编辑:admin   更新日期:2005-8-6
 
Hibernate事务处理机制(2)

二、JTATransaction

如果你在EJB中使用Hibernate,或者准备用JTA来管理跨Session的长事务,那么就需要使用

JTATransaction,先看一个例子:

javax.transaction.UserTransaction tx = new InitialContext().lookup

("javax.transaction.UserTransaction");

Session s1 = sf.openSession();
...
s1.flush();
s1.close();

...

Session s2 = sf.openSession();
...
s2.flush();
s2.close();

tx.commit();

这是标准的使用JTA的代码片断,Transaction是跨Session的,它的生命周期比Session要长。如果你在

EJB中使用Hibernate,那么是最简单不过的了,你什么Transaction代码统统都不要写了,直接在EJB的

部署描述符上配置某某方法是否使用事务就可以了。

现在我们来分析一下JTATransaction的源代码, net.sf.hibernate.transaction.JTATransaction:

public void begin(InitialContext context, ...
...
ut = (UserTransaction) context.lookup(utName);
...

看清楚了吗? 和我上面写的代码 tx = new Initial Context?().lookup

("javax.transaction.UserTransaction"); 是不是完全一样?

public void commit() ...
...
if (newTransaction) ut.commit();
...

JTATransaction的控制稍微复杂,不过仍然可以很清楚的看出来Hibernate是如何封装JTA的Transaction

代码的。

但是你现在是否看到了什么问题? 仔细想一下,Hibernate Transaction是从Session中获得的,tx =

session.beginTransaction(),最后要先提交tx,然后再session.close,这完全符合JDBC的

Transaction的操作顺序,但是这个顺序是和JTA的Transactioin操作顺序彻底矛盾的!!! JTA是先启

动Transaction,然后启动Session,关闭Session,最后提交Transaction,因此当你使用JTA的

Transaction的时候,那么就千万不要使用Hibernate的Transaction,而是应该像我上面的JTA的代码片

断那样使用才行。

总结:
1、在JDBC上使用Hibernate

必须写上Hibernate Transaction代码,否则数据库没有反应。此时Hibernate的Transaction就是

Connection.commit而已

2、在JTA上使用Hibernate

写JTA的Transaction代码,不要写Hibernate的Transaction代码,否则程序会报错

3、在EJB上使用Hibernate

什么Transactioin代码都不要写,在EJB的部署描述符里面配置

|---CMT(Container Managed Transaction)
|
|---BMT(Bean Managed Transaction)
|
|----JDBC Transaction
|
|----JTA Transaction


--------------------------------------------------------------------------------

提问:

javax.transaction.UserTransaction tx = new InitialContext().lookup

("javax.transaction.UserTransaction");

Session s1 = sf.openSession();
...
s1.flush();
s1.close();

...

Session s2 = sf.openSession();
...
s2.flush();
s2.close();

tx.commit();

s1不关闭,使用s2进行操作的代码中使用s1可不可以(我觉得这样更加节约资源,不需要反复的连接、

关闭)

但sf.opengSession()时,并没有setAutoCommit(false),我想问的是,如果不编写任何事务代码,如:
Session s = sf.openSession();
......
s.close();
数据库会不会有反应(此时应该是默认AutoCommit为true)。

不会有反应。在sf.openSession() 创建Session实例的时候,就已经调用了conn.setAutoCommit(false)

了。

另外,我想问一下:


1. s.flush()是不是必须的

2. s.close()是不是一定要关闭


--------------------------------------------------------------------------------

回答:

s.flush不是必须的,s.close()会调用一次s.flush()

s.close()正常情况下应该关闭,除非你是用ThreadLocal管理Session。

s1不关闭,使用s2进行操作的代码中使用s1可不可以(我觉得这样更加节约资源,不需要反复的连接、

关闭)

在这个例子中看不出来JTA的作用。
假设
Class A {
find() {
Session s1 = sf.openSession();
...
s1.flush();
s1.close();
}
}

Class B {
find() {
Session s2 = sf.openSession();
...
s2.flush();
s2.close();
}
}

Main {

tx = ...;
A.find();
B.find();
tx.commit();
} (全文完)
 

 

如何学习Hibernate
责任编辑:admin   更新日期:2005-8-6
 
如何学习Hibernate

Hibernate入门容易,掌握精通我也不敢自夸。我第一遍看Hibernate文档的时候也觉得很吃力,但不是

因为Hibernate难掌握而感到吃力,是因为Hibernate文档处处都是持久层设计的经验和最佳实践。

Hibernate文档准确的来说,绝大部分内容都在讲对象的持久层设计,而不是简单的Hibernate使用,使

用问题查Java doc就够了。所以学习Hibernate,主要是在学习持久层的设计模式,如果你把Hibernate

文档都看完了,还整天只会提那些 Hibernate的配置问题,Hibernate的类调用问题,我觉得这样的人还

没有真正的入门,算是白学了。

我对Hibernate 的那些配置也不是特别纯熟,每次写hbm,都要对照文档一点点的检查;类调用参数也不

太记得,写代码也要Java doc随时备查。但是我在学习Hibernate的时候即集中所有精力来理解

Hibernate的运行原理,集中精力来掌握持久层设计应该把握的原则和技巧,这些才对我是最重用的东西

。毫不夸张的说,学习完Hibernate,我对JDBC的编程也提高了一大截,更不要说对于J2EE架构的持久层

的框架设计,基本上是了然于胸了,即使将来换了API,不用Hibernate的,改用JDO,Castor什么的,这

些经验一样照用。

学习Hibernate主要不是在学习Hibernat怎么配置,用工具怎么生成hbm文件,如果你把重点放在这里,

基本上等于白学了Hibernate。Hibernate的精华在于无与伦比的灵巧的对象持久层设计,这些持久层设

计经验不会因为你不用Hibernate而丧失掉,我自己学习Hibernate,已经明显感觉到对持久层设计能力

已经长了很多经验值了,这些经验甚至不光可以用在Java上,用在.net上也是一样。所以Hibernate配置

的学习,我只是简单看看,用的时候知道到那里去查就行了,一堆复杂的生成工具我根本就看都不去看

,这样算下来,掌握Hibernate的配置,可以用Hibernate来替代JDBC写程序,不过花上3天时间就足够了

。我想3天时间对你来说不算很奢侈的学习代价吧。

为什么我这么强调学习Hibernate的对象持久层设计理念呢?那就看你的理想是想一辈子做一个程序员呢

?还是想向更高的方向发展呢?从纯做技术的角度来说,职业发展的最高点是“系统架构师”,Bill

Gates不是还叫做微软的首席系统架构师吗?System Architect职位需要的是你的学习和领悟能力,如果

你不能把学习Hibernate得到的设计经验运用到其它地方,那么你是失败的,也没有资格做 System

Architect。
不管JDO也好,Hibernate也好,TopLink也好,CocoBase也好,还是 Castor,还是什么Torque,OJB,软

件的使用和配置方法可以各异,但本质上都是ORM,都是对JDBC的对象持久层封装,所以万变不离其宗,

如果你完整的学习和掌握Hibernate花了1个月的时间,那么你再学习OJB的时间不应该超过1个星期,因

为你已经把对象持久层设计都了然于胸了,你需要的只是熟悉一下OJB的API和配置罢了,至于怎么运用

OJB进行持久层的开发你早就已经熟悉了。

所以当你掌握了两种以上的ORM,你应该能够不拘于使用的ORM软件的限制,设计出适合于你的项目的持

久层来,这才是System Architect的水准。用金庸小说来打个比方来说吧,张无忌学太极剑,只记剑意

,不记剑招,这才是真正的高手,而低手就只会去学习剑招,而不去领会剑招背后蕴含的剑意,所以一

辈子都是低手,永远不能真正学会太极剑。所以周颠看到张三丰第二次演示太极剑,招式完全不同就以

为是另一套东西,其实本质上都一样。学习Hibernate也不要舍本逐末的去学各种五花八门的工具,重点

掌握它的对象持久层设计理念。

 


Struts中不同的Action和ActionForm组合
责任编辑:admin   更新日期:2005-8-6
 
Struts中不同的Action和ActionForm组合

在TSS.com上看到一篇好文,有关Struts使用中各种不同的Action和ActionForm组合的利弊。我先消化一

下,整理好,供大家参考。原文标题:Struts action mappings: Divide Et Impera,作者:Michael

Juravlev。在TSS上的URL:http://www.theserverside.com/articles/article.tss?

l=StrutsActionMapping

说明:阅读本文需要一定的Struts基础。
注:文中小写的action不一定代表具体的Struts Action类,有时也指作为一个整体的action mapping。


[1] 完整的action

<action path="/aFullAction"
type="somePackage.someActionClass">
name="someForm"
input="someJSP.jsp"
<forward name="successful" path="someJSP.jsp"/>
<forward name="failed" path="someOtherJSP.jsp"/>
</action>

首先,Struts的ActionServlet接收到一个请求,然后根据struts-config.xml的配置定位到相应的

mapping(映射);接下来如果form的范围是request或者在定义的范围中找不到这个form,创建一个新

的form实例;取得form实例以后,调用其reset()方法,然后将表单中的参数放入form,如果validate属

性不为false,调用validate()方法;如果validate()返回非空的ActionErrors,将会被转到input属性

指定的URI,如果返回空的ActionErrors,那么执行Action的execute()方法,根据返回的ActionForward

确定目标URI。

这样做的效果是:execute()仅当validate()成功以后才执行;input属性指定的是一个URI。


[2] 仅有Form的action

<action path="/aFormOnlyAction"
type="org.apache.struts.actions.ForwardAction"
name="someForm"
input="someJSP.jsp"
parameter="someOtherJSP.jsp"
/>

首先,Struts会在定义的scope搜寻someForm,如果找到则重用,如果找不到则新建一个实例;取得form

实例以后,调用其reset()方法,然后将表单中的参数放入form,如果validate属性不为false,调用

validate()方法;如果validate()返回非空的ActionErrors,将会被转到input属性指定的URI,如果返

回空的ActionErrors,那么转到parameter属性指定的目标URI。

这样做的效果是:没有action类可以存放我们的业务逻辑,所以所有需要写入的逻辑都只能写到form的

reset()或者validate()方法中。validate()的作用是验证和访问业务层。因为这里的action映射不包括

forward(也没有意义),所以不能重定向,只能用默认的那个forward。这种仅有form的action可以用

来处理数据获取并forward到另一个JSP来显示。


[3] 仅有Action的action

<action path="/anActionOnlyAction"
type="somePackage.someActionClass">
input="someJSP.jsp"
<forward name="successful" path="someJSP.jsp"/>
<forward name="failed" path="someOtherJSP.jsp"/>
</action>

首先,ActionServlet接收到请求后,取得action类实例,调用execute()方法;然后根据返回的

ActionForward在配置中找forward,forward到指定的URI或action。

这样做的效果是:没有form实例被传入execute()方法,于是execute()必须自己从请求中获取参数。

Action可以被forward或者重定向。这种action不能处理通过HTML FORM提交的请求,只能处理链接式的

请求。


[4] 仅有JSP的action

<action path="/aJSPOnlyAction"
type="org.apache.struts.actions.ForwardAction"
parameter="someOtherJSP.jsp"
/>

首先,ActionServlet接到请求后调用ForwardAction的execute()方法,execute()根据配置的parameter

属性值来forward到那个URI。

这样做的效果是:没有任何form被实例化,比较现实的情形可能是form在request更高级别的范围中定义

;或者这个action被用作在应用程序编译好后充当系统参数,只需要更改这个配置文件而不需要重新编

译系统。


[5] 两个action对应一个form

<action path="/anAction"
type="somePackage.someActionClass">
name="someForm"
input="someJSP.jsp"
<forward name="successful" path="/anotherAction.do"/>
</action>
<action path="/anotherAction"
type="somePackage.someOtherActionClass">
name="someForm"
input="someOtherJSP.jsp"
<forward name="successful" path="someResultJSP.jsp"/>
</action>

就每个单独的action来讲,处理上并没有和完整的action有什么实质的区别。这个组合模式可以被用来

传递命令对象(form)。需要注意的是在后一个action中同样会调用form的reset()和validate()方法,

因此我们必须确保form中的信息不被重写。

处理的方式大致分为两种:a) 在request中放入一个指示器表明前一个action有意向后一个action传递

form,从而在后一个action可以保留那个form中的值,这一方式只能在使用forward时使用。b) 当使用

redirect而不是forward时,可以把指示器放在session或更高的级别,在命令链的最后一环将这个指示

器清除。


[6] 两个action对应两个form

<action path="/anAction"
type="somePackage.someActionClass">
name="someForm"
input="someJSP.jsp"
<forward name="successful" path="/anotherAction.do" redirect="true"/>
</action>
<action path="/anotherAction"
type="somePackage.someOtherActionClass">"
name="someOtherForm"
input="someOtherJSP.jsp"
<forward name="successful" path="someResultJSP.jsp"/>
</action>

这个组合方式跟前一种在流程上没有太大区别,只是我们现在对于两个action分别提供了form,于是代

码看上去更加清晰。于是我们可以分别处理WEB应用程序的输入和输出。值得注意的是,后一个action同

样会尝试往form中写入那些参数,不过我们可以这样处理:a) 在后一个form中使用另一套属性名;b)

只提供getter而不提供setter。

大致的处理是这样:
前一个action接收输入、验证、然后将数据写入业务层或持久层,重定向到后一个action,后一个

action手动的从业务层/持久层取出数据,写入form(通过其他方式),交给前台JSP显示。

这样做的好处是不必保留输入form中的值,因此可以使用redirect而不是forward。这样就降低了两个

action之间的耦合度,同时也避免了不必要的重复提交。
 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值