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

spring 环境下, 

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

先看一段话:

[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. What does sessionFactory.getCurrentSession() do? First, you can call it  
  2. as many times and anywhere you  
  3. like, once you get hold of your SessionFactory (easy thanks to  
  4. HibernateUtil). The getCurrentSession()  
  5. method always returns the "current" unit of work. Remember that we  
  6. switched the configuration option for this  
  7. mechanism to "thread" in hibernate.cfg.xml? Hence, the scope of the  
  8. current unit of work is the current Java  
  9. thread that executes our application. However, this is not the full  
  10. truth. A Session begins when it is first  
  11. needed, when the first call to getCurrentSession() is made. It is then  
  12. bound by Hibernate to the current  
  13. thread. When the transaction ends, either committed or rolled back,  
  14. Hibernate also unbinds the Session from  
  15. the thread and closes it for you. If you call getCurrentSession() again,  
  16. you get a new Session and can start a  
  17. new unit of work. This thread-bound programming model is the most  
  18. popular way of using Hibernate.  


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

[html]  view plain  copy
  1. The easiest way to handle Sessions and transactions is Hibernate's automatic "current" Session management.   
  2. For a discussion of contextual sessions see 第 2.3 节 “上下文相关的会话(Contextual Session)”.   
  3. Using the "jta" session context, if there is no Hibernate Session associated with the current   
  4. JTA transaction, one will be started and associated with that JTA transaction the first time you call sessionFactory.getCurrentSession().  
  5. The Sessions retrieved via getCurrentSession() in the "jta" context are set   
  6. to automatically flush before the transaction completes, close after the transaction completes,   
  7. and aggressively release JDBC connections after each statement.  
  8. This allows the Sessions to be managed by the life cycle of the JTA transaction to which it is associated,   
  9. keeping user code clean of such management concerns.   
  10. Your code can either use JTA programmatically through UserTransaction,   
  11. or (recommended for portable code) use the Hibernate Transaction API to set transaction boundaries.  
  12. If you run in an EJB container, declarative transaction demarcation with CMT is preferred.  

[html]  view plain  copy
  1. 使用getCurrentSession的代码举例:  

[java]  view plain  copy
  1. SessionFactory sf = new Configuration().configure()  
  2.         .buildSessionFactory();  
  3. Session s = null;  
  4. Transaction t = null;  
  5. try {  
  6.     // 准备数据  
  7.     UserModel um = new UserModel();  
  8.     um.setUuid(9);  
  9.     um.setUserId("id1");  
  10.     um.setName("name1");  
  11.     um.setAge(1);         
  12.     s = sf.getCurrentSession();  
  13.     t = s.beginTransaction();             
  14.     s.save(um);  
  15.     t.commit();  
  16. catch (Exception err) {  
  17.     err.printStackTrace();  
  18.     t.rollback();             
  19. finally {  
  20.   
  21. }  

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
  在CODE上查看代码片 派生到我的代码片
  1. org.hibernate.HibernateException: No TransactionManagerLookup specified  
  2.    at org.hibernate.context.JTASessionContext.currentSession(JTASessionContext.java:81)  
  3.    at org.hibernate.impl.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:687)  
  4.    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
  1. 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声明式事务就不起作用了, 只能使用编程式事务了。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值