欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-03-02 13:47:48
...

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


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不好用,那一定是因为自己太菜