如果在hibernate.cfg.xml中配置了
<property name="hibernate.transaction.manager_lookup_class">org.hibernate.transaction.JBossTransactionManagerLookup</property>
<property name="hibernate.transaction.factory_class">org.hibernate.transaction.CMTTransactionFactory</property>
<property
name="hibernate.current_session_context_class">jta</property>
这个配置的意思是当前对于这个SessionFactory(org.hibernate.transaction.CMTTransactionFactory的实例)来说,方法getCurrentSessiong()这个操作都应该在Container Manager Transaction中进行的,此时这个方法会将Session和Transaction进行绑定,对于应用来说则只需调用getCurrentSession就可以了,无需关心Session的Commit和Close.但是如果不是在一个Container Manager Transaction的Bean中调用SessionFactory.getCurrentSession(),则会抛出如下"org.hibernate.HibernateException: Unable to locate current JTA transaction"
,我想是因为容器没有为当前的Bean开始事务,所以这个方法无法绑定Session到当前的JTA transaction中去.
所以在配置前要想清楚是不是所有的操作都是在CMT中进行的,如果不是的话,不能够进行这样的操作.在一个应用中,往往有多个senarior,有的是通过CMT的session bean来调用,而有的则是通过Service直接调用DAO,要解决这个问题的话,可以配置多个SessiongFactory,将其Bind到容器的JNDI树中去.在调用的时候根据当前的Senaior来取不同的SessionFactory.
例如可以为所有通过的CMT管理的Bean作上述配置,对于BMT管理的配置如下:
<property name="hibernate.transaction.manager_lookup_class">org.hibernate.transaction.JBossTransactionManagerLookup</property>
<property name="hibernate.transaction.factory_class">org.hibernate.transaction.JTATransactionFactory</property>
<property
name="hibernate.current_session_context_class">jta</property>
使用的代码如下:
//BMTidiomwithgetCurrentSession()
try{
UserTransactiontx=(UserTransaction)newInitialContext()
.lookup("java:comp/UserTransaction");
tx.begin();
//DosomeworkonSessionboundtotransaction
factory.getCurrentSession().load(...);
factory.getCurrentSession().persist(...);
tx.commit();
}
catch(RuntimeExceptione){
tx.rollback();
throwe;//ordisplayerrormessage
}
其实这里与CMT不同的就是要手动开始一个Transaction,SessionFactory检查这个Transaction是否是Begin,然后绑定一个Session到这个Transaction上去.
如果是在非托管的环境的应用的话,用JDBCTransactionFactory就可以了,另外对于hibernate.current_session_context_class可以设置为Thread,通过Session.getCurrentSesion()这个方法,让每个Thread公用一个session,同样你也无须关心Sesion的打开和关闭.
//Non-managedenvironmentidiomwithgetCurrentSession()
try{
factory.getCurrentSession().beginTransaction();
//dosomework
...
factory.getCurrentSession().getTransaction().commit();
}
catch(RuntimeExceptione){
factory.getCurrentSession().getTransaction().rollback();
throwe;//ordisplayerrormessage
}
注意如果采取这种方式获得Session,即使对查询语句也需要开始事务,否则会抛异常.
org.hibernate.HibernateException: createSQLQuery is not valid without active transaction
如果对于CMT,BMT和非托管环境都要用到的,则不再适合用SessionFactory.getCurrentSession(),而需要用OpenSession,并自己负责事务的提交以及Sesion的Close.