spring+hibernate4异常org.hibernate.HibernateExc和createCriteria is not valid without active transaction

在一个从来没有用过多线程的项目里面使用了多线程之后,引发的问题,所谓自作孽不可活~~~让我叹口气~~~


Spring提供的sessionFactory管理:

org.springframework.orm.hibernate4.LocalSessionFactoryBean

起初获取session使用的是:
sessionFactory.currentSession();
出现的问题是:org.hibernate.HibernateException: No Session found for current thread

问题很明显,多线程引起的,在该线程内部未初始化session

然后上网查了一下,建议一溜的:
<filter>
    <filter-name>openSessionInVieFilter</filter-name>
    <filter-class>org.springframework.orm.hibernate4.support.OpenSessionInViewFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>openSessionInVieFilter</filter-name>
    <url-pattern>/web/*</url-pattern>
</filter-mapping>

有的还包括下面这个:
<prop key="current_session_context_class">thread</prop>

~~~
好的,照办看看~~~
~~~
然后新鲜的问题出现了:
createCriteria is not valid without active transaction

看到这个问题,我的第一反应是,会不会是因为我用了criteria引起的?

然后想到就做,OK,尝试请求其他使用sql或hql的接口,然后结果显然一致
~~~

现在怎么办,再找度娘渡我一程,没什么新发现,无非是说在service上缺少了@Transaction注解,那就加上,然后继续踩,好的,一如既往的准确命中坑

是可忍孰不可忍,叔可忍婶不可忍


忍不了了,就粗暴点


先说为什么到最后才选择用这种办法:

看sessionFactory.currentSession()的注释大意是获取一个共享的Session

用了ThreadLocal之后,会按照线程创建Session,这可能会使得同时存在大量Session,可能存在资源回收问题

以下是ThreadLocal的注释:

 * Each thread holds an implicit reference to its copy of a thread-local
 * variable as long as the thread is alive and the <tt>ThreadLocal</tt>
 * instance is accessible; after a thread goes away, all of its copies of
 * thread-local instances are subject to garbage collection (unless other
 * references to these copies exist).

单纯从注释看,线程一旦结束,属于线程的一切都将进入回收队列……but,我们要时刻谨记,Java的进入回收队列和回收是两回事,一旦同时存在大量的线程,然后一波多线程结束又是一波多线程,这样的情况下是有可能会造成同时session过多,影响性能,数据库连接是有限的,连一个少一个,所以这一块还是需要有所考虑的

1、首先,干掉之前加的那些乱七八糟没用的东西
2、修改getSession方法
3、
从之前的:
private SessionFactory sessionFactory;

public void setSessionFactory(SessionFactory sessionFactory){
    this.sessionFactory = sessionFactory;
}

public Session getSession(){
    return sessionFactory.currentSession();
}

改为:
private LocalThread<Session> localThreadSession;

public void setSessionFactory(final SessionFactory sessionFactory){
    this.localThreadSession = new LocalThread<Session>{

        @Override
        protected Session initialValue() {
            return sessionFactory.openSession();
        }
    }
}

public Session getSession(){
    return this.localThreadSession.get();
}
点开org.springframework.orm.hibernate4.LocalSessionFactoryBean大概看了一下源码,也是类似于ThreadLocal的实现,所以其实使用getCurrentSession()完全是可以的,但是估计网上那些解决办法中,配置上少贴了,可以肯定的是我所使用的配置一定是缺了东西

总之,Spring是很强大的,如果觉得Spring不好用,那一定是因为自己太菜

猜你喜欢

转载自blog.csdn.net/u010746357/article/details/81039827