hibernate.current_session_context_class 的各个取值的区别

本文探讨了Hibernate中sessionFactory.getCurrentSession()的使用方式,并对比了thread和jta两种配置的区别。介绍了这两种配置如何支持“每数据库事务对应一个session”的编程模型,并讨论了它们在不同环境下的适用性。

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

非spring 环境下, 

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

先看一段话:

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官网)

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 through 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.

使用getCurrentSession的代码举例:

		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, 否则程序会报以下错误:

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 就会报如下错误:

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>好的,我现在需要回答用户关于current_session_context_class配置中thread和SpringSessionContext区别的问题。首先,我需要回忆一下Hibernate中的Session管理机制。 记得Hibernatecurrent_session_context_class是用来配置当前会话上下文环境的,也就是如何绑定和获取Session。常见的选项有thread和managed,但在Spring环境中可能会用SpringSessionContext。不过可能用户提到的SpringSessionContext其实是Spring提供的实现。 接下来,我需要明确thread和SpringSessionContext各自的作用。thread通常对应ThreadLocalSessionContext,它基于线程本地存储来管理Session,确保同一线程内获取的是同一个Session实例,适用于非容器管理的事务,比如纯Hibernate应用。 而SpringSessionContext是Spring框架集成Hibernate时的实现,属于Spring的org.springframework.orm.hibernate5包。它会将Session的生命周期与Spring的事务管理绑定,特别是支持基于注解的事务管理(@Transactional),确保在事务范围内使用同一个Session,并且能处理跨多个DAO的操作,保持事务一致性。 两者的区别主要在于管理机制和应用场景。thread适用于简单的线程绑定,而SpringSessionContext更适合与Spring的事务管理整合,特别是在需要声明式事务和复杂事务传播行为的情况下。此外,SpringSessionContext可能还会考虑事务同步和Session的自动关闭等细节,避免资源泄漏。 需要确认一下配置方式的不同。使用thread时,配置为hibernate.current_session_context_class=thread;而使用Spring时,通常通过LocalSessionFactoryBean配置,并可能自动设置SpringSessionContext,或者显式配置为org.springframework.orm.hibernate5.SpringSessionContext。 可能还需要注意版本差异,比如Hibernate 3和5中的包路径变化,确保用户使用的是正确的类路径。另外,SpringSessionContext在事务提交或回滚后会自动关闭Session,而thread模式可能需要手动管理或配置自动关闭。 总结起来,两者的核心区别在于Session管理与事务管理的整合方式,以及适用的框架环境。用户如果使用Spring,尤其是需要声明式事务管理,应该选择SpringSessionContext;而独立Hibernate应用可能用thread模式。</think>在Hibernate与Spring整合时,`current_session_context_class`配置中`thread`和`SpringSessionContext`的区别主要体现在**Session生命周期管理方式**和**与事务管理的整合深度**上。以下是核心区别解析: --- ### 1. **`thread`模式(ThreadLocalSessionContext)** - **机制**: 基于`ThreadLocal`实现,将Session绑定到当前线程。同一线程内通过`sessionFactory.getCurrentSession()`获取的是同一个Session实例。 - **特点**: - **简单绑定**:Session与线程生命周期绑定,线程结束时需手动关闭或配置自动关闭。 - **无事务感知**:需手动管理事务(如`beginTransaction()`/`commit()`),或依赖Hibernate的`hibernate.transaction.auto_close_session`等配置。 - **适用场景**:独立Hibernate应用(无Spring管理),或需要显式控制Session的场景。 - **配置示例**: ```properties hibernate.current_session_context_class=thread ``` --- ### 2. **`SpringSessionContext`模式** - **机制**: Spring提供的`SpringSessionContext`实现,将Session生命周期与Spring事务管理深度绑定。Session的打开、关闭、刷新等操作由Spring控制。 - **特点**: - **事务感知**:与`@Transactional`注解无缝集成,事务提交/回滚后自动关闭Session。 - **跨DAO一致性**:同一事务内跨多个DAO操作共享同一Session,确保事务原子性。 - **资源自动释放**:无需手动关闭Session,Spring在事务结束时自动处理。 - **适用场景**:Spring管理的事务环境(如声明式事务`@Transactional`)。 - **配置方式**: 通过Spring的`LocalSessionFactoryBean`自动配置,或显式指定: ```properties hibernate.current_session_context_class=org.springframework.orm.hibernate5.SpringSessionContext ``` --- ### 3. **关键对比表** | **特性** | **`thread`模式** | **`SpringSessionContext`模式** | |------------------------|-----------------------------------|--------------------------------------| | **Session生命周期** | 绑定线程 | 绑定Spring事务 | | **事务管理** | 手动或Hibernate配置 | 与Spring `@Transactional`深度整合 | | **跨DAO操作一致性** | 需自行确保(同一线程内) | 自动保证(同一事务内) | | **资源释放** | 需配置`auto_close_session`或手动 | Spring自动关闭 | | **适用场景** | 纯Hibernate应用 | Spring整合环境(需声明式事务) | --- ### 4. **实际影响示例** - **`thread`模式下的风险**: 若未配置`auto_close_session`,长时间运行的线程可能导致Session未关闭,引发连接池泄漏。 - **`SpringSessionContext`的优势**: 在以下代码中,`userDao`和`orderDao`共享同一事务和Session,确保操作原子性: ```java @Transactional public void createUserAndOrder(User user, Order order) { userDao.save(user); // 使用Session A orderDao.save(order); // 使用同一Session A } ``` --- ### 总结 - **独立Hibernate应用**:使用`thread`模式,通过线程绑定简化Session管理。 - **Spring整合环境**:必须用`SpringSessionContext`,以实现声明式事务和资源自动管理。 - **事务复杂性**:若需要嵌套事务(`PROPAGATION_NESTED`)或跨数据源事务,`SpringSessionContext`是唯一选择。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值