main 启动 spring hiberante项目报org.hibernate.LazyInitializationException 异常

  最近在做一个web项目 (ssh) 在操作数据层时  为了方便 不想通过启动web服务器 通过前台点击调用。 于是就想到了 使用main方法 把它做为一个普通的application 项目进行启动调用。 但是 在对数据库进行操作的时候报 LazyInitializationException 异常 

具体异常信息:

2014-08-26 17:40:54 ERROR LazyInitializationException:19 - could not initialize proxy - no Session
org.hibernate.LazyInitializationException: could not initialize proxy - no Session
at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:57)
at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:111)
at org.hibernate.proxy.pojo.cglib.CGLIBLazyInitializer.invoke(CGLIBLazyInitializer.java:150)
at com.resource.happok.common.domain.Comment$$EnhancerByCGLIB$$1a705b58.getUser(<generated>)
at com.resource.happok.common.util.Test.main(Test.java:35)
Exception in thread "main" org.hibernate.LazyInitializationException: could not initialize proxy - no Session
at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:57)
at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:111)
at org.hibernate.proxy.pojo.cglib.CGLIBLazyInitializer.invoke(CGLIBLazyInitializer.java:150)
at com.resource.happok.common.domain.Comment$$EnhancerByCGLIB$$1a705b58.getUser(<generated>)
at com.resource.happok.common.util.Test.main(Test.java:35)


异常原因: Indicates access to unfetched data outside of a session context.

hibernate 在sesssion访问之外访问了数据。(也就是seeeion已关闭了)

这个是hibernate的延迟加载异常,

Hibernate 允许对关联对象、属性进行延迟加载,但是必须保证延迟加载的操作限于同一个 Hibernate Session 范围之内进行。如果 Service 层返回一个启用了延迟加载功能的领域对象给 Web 层,当 Web 层访问到那些需要延迟加载的数据时,由于加载领域对象的 Hibernate Session 已经关闭,这些导致延迟加载数据的访问异常

为了不产生该异常,有如下解决方法:

1、在相应的映射文件里禁止该类的延迟加载:设置lazy=false
2、在session关闭之前取出需要的属性
3、使用openSessionInView

法一: 为了一个测试修改项目的源码不靠谱,而且取消了延迟加载会增加不必要的开销。

法二: session关闭之前取出数据  也是要修改项目源码  将load()改成get();  太麻烦 和方法一一样。

法三: 使用openSessionInView 

在web.xml  文件加入如下配置信息

<filter>
<filter-name>openSessionInView</filter-name>
<filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>openSessionInView</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

但这是在web项目中的解决方法 我该怎么使用这种方法在application项目中解决该问题呢? 

不妨我们先看看openSessionInView.java 这个类是干什么的 主要实现了什么功能。

下面是openSessionInView 的doFilterInternal方法

protected void doFilterInternal(
HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {


SessionFactory sessionFactory = lookupSessionFactory(request);
boolean participate = false;


if (isSingleSession()) {
// single session mode
if (TransactionSynchronizationManager.hasResource(sessionFactory)) {
// Do not modify the Session: just set the participate flag.
participate = true;
}
else {
logger.debug("Opening single Hibernate Session in OpenSessionInViewFilter");
Session session = getSession(sessionFactory);
TransactionSynchronizationManager.bindResource(sessionFactory, new SessionHolder(session));

}
}
else {
// deferred close mode
if (SessionFactoryUtils.isDeferredCloseActive(sessionFactory)) {
// Do not modify deferred close: just set the participate flag.
participate = true;
}
else {
SessionFactoryUtils.initDeferredClose(sessionFactory);
}
}


try {
filterChain.doFilter(request, response);
}


finally {
if (!participate) {
if (isSingleSession()) {
// single session mode
SessionHolder sessionHolder =
(SessionHolder) TransactionSynchronizationManager.unbindResource(sessionFactory);
logger.debug("Closing single Hibernate Session in OpenSessionInViewFilter");
closeSession(sessionHolder.getSession(), sessionFactory);
}
else {
// deferred close mode
SessionFactoryUtils.processDeferredClose(sessionFactory);
}
}
}
}


这个方法 主要是把一个Hibernate Session和一次完整的请求过程对应的线程相绑定。

找到了原因 接下来就好办了 我们可以自己写一个类似的方法 在每次执行数据库操作的时候调用。

方法如下:

public static void before () {

//手动编码打开session
 Session session = sessionFactory.openSession();
 //将session保存在SessionHolder ,并由TransactionSynchronizationManager进行管理
 //保存
 SessionHolder sessionHolder = new SessionHolder(session);
 //管理,绑定到本地线程
 TransactionSynchronizationManager.bindResource(sessionFactory,sessionHolder);
}

既能开启了session 并且绑定到了本地线程 那么就得有个解除解除绑定和关闭session的操作

方法如下

public static void after() {

SessionHolder  sessionHolder = (SessionHolder)TransactionSynchronizationManager.getResource(sessionFactory);
Session   session = sessionHolder.getSession();
//清除
session.flush();
//从本地线程中取消绑定
TransactionSynchronizationManager.unbindResource(sessionFactory);
//关闭连接
SessionFactoryUtils.closeSession(session);
}

这个在main方法中 进行数据库操作前执行before() 操作完成之后 执行after()方法 这样就不会报错了~ 问题解决


我的具体代码 

package com.resource.happok.common.util;


import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.orm.hibernate3.SessionFactoryUtils;
import org.springframework.orm.hibernate3.SessionHolder;
import org.springframework.transaction.support.TransactionSynchronizationManager;


import com.resource.happok.common.domain.Comment;
import com.resource.happok.school.service.impl.CommentServiceImpl;


public class Test {


/**
* @param args
*/
private static SessionFactory sessionFactory;
public static void main(String[] args)throws Exception {

String[] array = {"springContext/applicationContext-*.xml"};

ApplicationContext atcx=new ClassPathXmlApplicationContext(array);
sessionFactory = (SessionFactory) atcx.getBean("sessionFactory");
System.out.println("sessionFactory>>" + sessionFactory);

before();
CommentServiceImpl commentServiceImpl = (CommentServiceImpl)atcx.getBean("commentServiceImpl");
Comment comment = commentServiceImpl.findById(new Long(1));
System.out.println(comment.getUser().getUserName());
System.out.println(comment.getUser().getImage());


after();
}

/**
* 将session和线程绑定  在执行数据库操作之前调用
*/
public static void before () {

//手动编码打开session
 Session session = sessionFactory.openSession();
 //将session保存在SessionHolder ,并由TransactionSynchronizationManager进行管理
 //保存
 SessionHolder sessionHolder = new SessionHolder(session);
 //管理,绑定到本地线程
 TransactionSynchronizationManager.bindResource(sessionFactory,sessionHolder);
}

/**
* 将session和线程解除绑定 关闭session  在执行数据库操作之后调用
*/
public static void after() {

SessionHolder  sessionHolder = (SessionHolder)TransactionSynchronizationManager.getResource(sessionFactory);
Session   session = sessionHolder.getSession();
//清除
session.flush();
//从本地线程中取消绑定
TransactionSynchronizationManager.unbindResource(sessionFactory);
//关闭连接
SessionFactoryUtils.closeSession(session);
}
}


参考文章

1. http://www.itzhai.com/org-hibernate-lazyinitializationexception-solution-using-opensessioninviewfilter.html

2. http://www.360doc.com/content/13/0531/15/2703996_289489930.shtml

3. http://xiaoxuejie.iteye.com/blog/789092

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值