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

本文探讨了Hibernate环境下Session管理的不同策略,包括ThreadLocalSessionContext和JTASessionContext,并详细介绍了它们的工作原理及适用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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声明式事务就不起作用了, 只能使用编程式事务了。

<think>嗯,用户问的是Hibernate中的hibernate.allow_update_outside_transaction配置是否会影响currentSession。首先,我需要回忆一下Hibernate的事务管理机制。HibernateSession通常和事务绑定,尤其是在使用currentSession时,通常是通过事务上下文来管理的。 然后,这个配置项hibernate.allow_update_outside_transaction的作用是允许在没有活动事务的情况下执行更新操作。默认情况下,Hibernate会阻止这种情况,避免数据不一致。所以当启用这个配置时,即使没有事务,也能进行更新,但可能会带来风险,比如自动提交模式的问题。 接下来要考虑currentSession的实现。currentSession通常由Hibernate根据上下文环境管理,比如在JTA事务中,Session会绑定到当前事务。如果允许无事务更新,是否会导致currentSession在没有事务时仍然存在?或者是否会影响Session的自动关闭和清理? 可能的结论是,这个配置主要影响的是在没有事务时是否允许执行更新操作,而不会直接影响currentSession的管理方式。但需要注意,启用此配置后,即使使用currentSession,在没有事务的情况下执行更新可能会导致数据库连接处于自动提交模式,这可能引发问题,比如多次提交影响性能或产生不一致状态。 需要验证一下Hibernate的文档,确认currentSession的行为是否受此配置影响。根据Hibernate的文档,currentSession的生命周期通常事务相关联,特别是在事务结束后会自动关闭Session,除非配置了其他方式。而hibernate.allow_update_outside_transaction更多是控制数据修改操作的事务要求,不直接影响Session的绑定机制。 因此,总结起来,这个配置不会直接影响currentSession的管理,但允许在无事务时进行更新操作,使用时需谨慎处理事务边界,避免潜在问题。</think>Hibernate的`hibernate.allow_update_outside_transaction`配置项`currentSession`的关系可通过以下要点理解: --- ### 1. **配置项的作用** - **默认行为**:Hibernate 默认要求数据修改操作(如`save/update/delete`)必须在事务内执行。若无活跃事务,会抛出`TransactionRequiredException`。 - **启用配置**:`hibernate.allow_update_outside_transaction=true`允许在无事务环境下执行更新操作。 - **风险**:可能导致数据库连接的`auto-commit`模式被隐式启用(取决于连接池配置),引发多次提交、性能下降或数据不一致。 --- ### 2. **对`currentSession()`的影响** - **Session绑定机制**:`currentSession()`的绑定通常由事务上下文驱动(如JTA或Hibernate的`hibernate.current_session_context_class`配置)。 - **无事务场景**: - **未启用配置**:尝试无事务更新会直接报错。 - **启用配置**:允许无事务更新,但不会改变`currentSession()`的绑定逻辑。Session仍由事务上下文管理,若未开启事务,Session可能处于未绑定状态(取决于具体实现)。 - **生命周期**:启用此配置后,需手动管理Session的关闭,否则可能导致连接泄漏(例如,在无事务时未关闭Session)。 --- ### 3. **典型场景分析** #### 场景1:在事务外更新 ```java // 配置已启用 hibernate.allow_update_outside_transaction=true Session session = sessionFactory.getCurrentSession(); User user = session.get(User.class, 1L); user.setName("NewName"); // 允许执行,但可能隐式触发auto-commit ``` #### 场景2:混合事务非事务操作 ```java // 事务内操作 Transaction tx = session.beginTransaction(); User user = session.get(User.class, 1L); user.setName("InTransaction"); tx.commit(); // 事务外操作(依赖配置允许) user.setEmail("test@example.com"); // 无事务更新,可能auto-commit ``` --- ### 4. **最佳实践** - **避免启用此配置**:强制事务边界可确保数据一致性。 - **明确事务管理**: ```java try (Session session = sessionFactory.openSession()) { Transaction tx = session.beginTransaction(); // 执行更新操作 tx.commit(); } ``` - **监控连接池**:若必须启用此配置,确保连接池配置为关闭`auto-commit`(如C3P0的`autoCommitOnClose=false`)。 --- ### 总结 - `hibernate.allow_update_outside_transaction` **不直接影响**`currentSession()`的绑定机制,但允许在无事务时通过Session执行更新。 - **主要风险**在于隐式提交和连接状态管理,需结合事务策略和连接池配置谨慎使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值