Spring 3 和 Hibernate4 整合时遇到的 No Session found for current thread !

案例

Spring 配置文件,将 sessionFactory 注入到了 DAO 实现类:

<bean id="dao" class="CatDAOImpl">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>

DAO 实现类:

public class CatDAOImpl implements ICatDAO {
	
	private SessionFactory sessionFactory;
   //并设置其setter和getter方法。
}

调用类:

public void createCat(Cat c) {
	// TODO Auto-generated method stub
	Session session=sessionFactory.getCurrentSession();
	session.persist(c);
}

报错:   nested exception is org.hibernate.HibernateException: No Session found for current thread


原理分析:


CurrentSessionContext 

SessionFactory的getCurrentSession并不能保证在没有当前Session的情况下会自动创建一个新的,这取决于CurrentSessionContext 的实现,SessionFactory 将调用 CurrentSessionContext 的 currentSession() 方法来获得 Session。在 Spring 中,如果我们在没有配置 TransactionManager 并且没有事先调用 SessionFactory.openSession() 的情况直接调用getCurrentSession(),那么程序将抛出“No Session found for current thread”异常。如果配置了 TranactionManager 并且通过 @Transactional 或者声明的方式配置的事务边界,那么 Spring 会在开始事务之前通过 AOP 的方式为当前线程创建Session,此时调用 getCurrentSession() 将得到正确结果。


current_session_context_class
然而,产生以上异常的原因在于 Spring 提供了自己的 CurrentSessionContext 实现,如果我们不打算使用 Spring,而是自己直接从 hibernate.cfg.xml 创建 SessionFactory,并且为在 hibernate.cfg.xml 中设置 current_session_context_class 为thread,也即使用了 ThreadLocalSessionContext ,那么我们在调用 getCurrentSession() 时,如果当前线程没有Session存在,则会创建一个绑定到当前线程。


Hibernate 在默认情况下会使用 JTASessionContext ,Spring 提供了自己 SpringSessionContext,因此我们不用配置current_session_context_class,当 Hibernate 与 Spring 集成时,如果我们配置了 TransactionManager,那么我们就不应该调用 SessionFactory 的openSession() 来获得 Sessioin,因为这样获得的 Session 并没有被事务管理。


在没有Spring的情况下使用 Hibernate,如果没有在 hibernate.cfg.xml 中配置 current_session_context_class,又没有 JTA 的话,那么程序将抛出"No CurrentSessionContext configured!"异常。此时的解决办法是在 hibernate.cfg.xml中将current_session_context_class 配置成 thread。



解决方案分两种情况:

1.如果没有配置TranactionManager事务,那么调用getCurrentSession()之前,先调用SessionFactory.openSession();


2.如果配置了 TranactionManager 事务,无论是 @Transactional 注解或者声明的方式配置的事务边界,那么Spring 都会在开始事务之前通过 AOP 的方式为当前线程创建 Session,此时调用 getCurrentSession() 是没有问题的。但是如果依然出现了该问题,那么十之八九是事务没有起到作用。


  • 如果是@Transactional事务那么spring的配置文件中需要加上
<bean id="txManager"
        class="org.springframework.orm.hibernate4.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>
  <!-- 使用annotation声明 -->
    <tx:annotation-driven />
   <tx:advice id="txAdvice" transaction-manager="txManager">
        <tx:attributes>
            <tx:method name="get*" read-only="true" propagation="REQUIRED" />
            <tx:method name="add*" propagation="REQUIRED" />
            <tx:method name="update*" propagation="REQUIRED" />
            <tx:method name="save*" propagation="REQUIRED" />
            <tx:method name="*" propagation="REQUIRED" />
        </tx:attributes>
    </tx:advice>

同时,在获得 Session 的 DAO 实现类的方法上,要添加 @Transactional("txManager") 标注:

@Transactional("txManager")
@Override
public void createCat(Cat c) {
	// TODO Auto-generated method stub
	Session session=sessionFactory.getCurrentSession();
	session.persist(c);
}



  • 如果已经加上该注释依旧没起作用,那就可能是扫描包的地方有点问题,如果是 spring + springMVC 框架,因为 springMVC 容器是 spring 的子容器,也就是说 spring 容器的创建是优先于 springMVC,那么如果springMVC 对包的扫描没有过滤掉对 service 的扫描,就会存在 springMVC 创建的不含有事务的 service 覆盖掉主容器 spring 创建的含有事务的 service,因此,我们的事务就相当于没有起到作用,解决方案就是springMVC 子容器扫描包时过滤掉对 service 的扫描,代码如下:
在spring-mvc.xml文件中加上:
<context:component-scan base-package="com.chenyee.lxf" >  
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service" /> 


转载自:

http://blog.csdn.net/YQFCXY/article/details/51930085

http://www.yihaomen.com/article/java/466.htm

http://www.xuebuyuan.com/762337.html

猜你喜欢

转载自blog.csdn.net/qq_30715329/article/details/79517904