您的位置:首页 > 编程语言 > Java开发

hibernate.current_session_context_class 的各个取值的区别以及与Spring整合的问题

2016-07-25 09:30 525 查看
在非spring 环境下, 

hibernate.current_session_context_class主要就是thread和jta 两个取值。

先看一段话:

[html] view
plain copy

 





What does sessionFactory.getCurrentSession() do? First, you can call it  

as many times and anywhere you  

like, once you get hold of your SessionFactory (easy thanks to  

HibernateUtil). The getCurrentSession()  

method always returns the "current" unit of work. Remember that we  

switched the configuration option for this  

mechanism to "thread" in hibernate.cfg.xml? Hence, the scope of the  

current unit of work is the current Java  

thread that executes our application. However, this is not the full  

truth. A Session begins when it is first  

needed, when the first call to getCurrentSession() is made. It is then  

bound by Hibernate to the current  

thread. When the transaction ends, either committed or rolled back,  

Hibernate also unbinds the Session from  

the thread and closes it for you. If you call getCurrentSession() again,  

you get a new Session and can start a  

new unit of work. This thread-bound programming model is the most  

popular way of using Hibernate.  

再看下面一段(来自Hibernate官网)

[html] view
plain copy

The easiest way to handle Sessions and transactions is Hibernate's automatic "current" Session management.   

For a discussion of contextual sessions see 第 2.3 节 “上下文相关的会话(Contextual Session)”.   

Using the "jta" session context, if there is no Hibernate Session associated with the current   

JTA transaction, one will be started and associated with that JTA transaction the first time you call sessionFactory.getCurrentSession().  

The Sessions retrieved via getCurrentSession() in the "jta" context are set   

to automatically flush before the transaction completes, close after the transaction completes,   

and aggressively release JDBC connections after each statement.  

This allows the Sessions to be managed by the life cycle of the JTA transaction to which it is associated,   

keeping user code clean of such management concerns.   

Your code can either use JTA programmatically thr
11449
ough UserTransaction,   

or (recommended for portable code) use the Hibernate Transaction API to set transaction boundaries.  

If you run in an EJB container, declarative transaction demarcation with CMT is preferred.  

[html] view
plain copy

使用getCurrentSession的代码举例:  

[java] view
plain copy

SessionFactory sf = new Configuration().configure()  

        .buildSessionFactory();  

Session s = null;  

Transaction t = null;  

try {  

    // 准备数据  

    UserModel um = new UserModel();  

    um.setUuid(9);  

    um.setUserId("id1");  

    um.setName("name1");  

    um.setAge(1);         

    s = sf.getCurrentSession();  

    t = s.beginTransaction();             

    s.save(um);  

    t.commit();  

} catch (Exception err) {  

    err.printStackTrace();  

    t.rollback();             

} finally {  

  

}  

1. 这两个值的相同点

     对于sessionFactory.getCurrentSession()操作而言, 这两种实现都提供了“每数据库事务对应一个session”的编程模型,也称作每次请求一个session。Hibernate
session的起始和终结由数据库事务的生存来控制。也就是说, 对于thread而言, 当执行getCurrentSession时, session创建并绑定到当前线程,当事务提交时, session就关闭了, 无须手动关闭session (openSession方法需要手动关闭session);  jta与此类似,当执行getCurrentSession时, session创建并绑定到当前JTA context, 当事务提交时, session就关闭了, 无须手动关闭session 。

2. 不同点

org.hibernate.context.JTASessionContext - 当前session根据JTA上下文来跟踪和界定(即保存在JTA上下文中)。这和以前的仅支持JTA的方法是完全一样的。

org.hibernate.context.ThreadLocalSessionContext - 当前session通过当前执行的线程来跟踪和界定(即保存在当前线程上下文的threadlocal变量中)。

在JDBC的独立应用程序中(非容器集成环境下),取值只能是thread, 否则程序会报以下错误:

[java] view
plain copy

 





org.hibernate.HibernateException: No TransactionManagerLookup specified  

   at org.hibernate.context.JTASessionContext.currentSession(JTASessionContext.java:81)  

   at org.hibernate.impl.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:687)  

   at com.cvv.service.UserManager.exists(UserManager.java:16)  

在J2EE容器的环境下, 可以使用thread, 也可以使用jta, 因为容器环境中一般会配置 TransactionManagerLookup。并且,如果没有配置 hibernate.current_session_context_class,但是有org.hibernate.transaction.TransactionManagerLookup的配置的情况下,Hibernate会采用org.hibernate.context.JTASessionContext,即jta。容器环境优先考虑jta方式。

在Spring环境中,

除了thread和jta两个值以外, Spring 增加了 org.springframework.orm.hibernate4.SpringSessionContext 这个值。

1. 当你使用Spring 声明式事务的时候 (@Transactional, tx标签 ...),  @Transactional声明式事务管理 会创建一个 绑定了事务的session并把 该session放到SpringSessionContext 这个上下文中, 所以在使用声明式事务并且使用 getCurrentSession()这个方法的时候,只有从 SpringSessionContext
 上下文中才能取到当前的session, 这就要求将 hibernate.current_session_context_class 这个值设置为org.springframework.orm.hibernate4.SpringSessionContext, 在spring 配置文件中, 在使用LocalSessionFactoryBean时会自动的设置这个值,
不需要你去设置, 所以在spring 配置中  hibernate.current_session_context_class 默认就是SpringSessionContext;

2. 如果你将 hibernate.current_session_context_class 设置成了 thread,并不是不可以, 而是代码需要做些修改:

因为使用Spring 声明式事务的时候, 绑定了事务的session被放置在了spring context中,而当前hibernate.current_session_context_class值为 thread, 也就是说getCurrentSession不会从spring context中去寻找current session, 而是会到org.hibernate.context.ThreadLocalSessionContext
这个上下文中去寻找current session, 没有就自动创建一个;这个时候, current session是在 org.hibernate.context.ThreadLocalSessionContext 上下文中创建的, 没有绑定通过Spring 声明式事务@Transactional 创建的 transaction, 因此, spring 就会报如下错误:

[java] view
plain copy

org.hibernate.HibernateException: save is not valid without active transaction org.hibernate.context.ThreadLocalSessionContext$TransactionProtectionWrapper.invoke(ThreadLocalSessionContext.java:341)at com.sun.proxy.$Proxy12.save(Unknown Source)at cn.javass.h4.hello.UserDao.save(UserDao.java:18)  

因为Hibernate的数据库操作是一定要在一个事务中进行的(参考Hibernate教程), 所以报了以上错误, 解决的办法很简单, 就是在调用getCurrentSessioin()后, 手动添加 session.beginTransaction() 和 transaction.commit() 语句将数据库操作包装进事务中。这种情况下, spring声明式事务就不起作用了, 只能使用编程式事务了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: