首页 > 代码库 > Hibernate 中 load() 方法导致的 noSession 异常
Hibernate 中 load() 方法导致的 noSession 异常
之所以要写这个,是因为最近碰到了一个延迟加载的 load() 导致出现 noSession 的异常。
解决这个问题需要用到一个本地线程的对象,也就是 ThreadLocal 类,之前写过关于这个对象,可以看这个博客【本地线程 ThreadLocal 类】
我在数据层中封装了一个 load() 方法,根据用户 Id 获取用户对象:
public UserModel get(Long uuid) { return this.getHibernateTemplate().load(UserModel.class, uuid); //return this.getHibernateTemplate().get(UserModel.class, uuid); }
当在业务层调用了这个方法后,获得一个 userModel 对象,当展示用户信息时,就会报出 noSession 问题,
public String get(){ //报出了 org.hibernate.LazyInitializationException: could not initialize proxy - no Session异常 UserModel temp = userEbi.get(1L); System.out.println(temp.getName()); System.out.println(temp.getAge()); return "haha"; }
报出的异常如下:
这是因为数据层提供的 load() 方法具有延迟加载的特性,也就是获得对象只有 OID ,其他的信息都没有,只有当需要的时候才会去查询(这叫二次查询,延迟加载其他数据),如果二次查询之前,这个只具有 OID 的对象传递到了业务层(如果在事务关闭session之前立马进行二次查询,就不会出问题),此时对象仍是一个延迟加载对象(只具有 OID),如果传递到了表现层(action内),此时该对象依然是延迟加载对象(但此时早在业务层,事务就已经将session关闭了,一旦要进行二次查询就会报异常,因为session对象已经被刷新了,也就是连接断开了,session中存储的数据早已丢失)。
但是在表现层使用二次查询是比较正常的,也就是要做到当前session不关闭,直到一次请求完成才关闭。这时用到的一个技术就是 openSessionInView
这需要在 web.xml 中配置一个过滤器,用于将每个请求对象 request 和 session 对象绑定在一起(这里的session是与数据库交互的session,并不是浏览器的session会话),至于session的关闭,在一次请求结束时 session 会被自动关闭,这时注解的事务的任务就是开启事务,刷新事务;关闭事物的功能交给了 OpenSessionInViewFilter 这个类了,因为这个过滤器配置在一个,请求对象 request 最先接触到它,请求结束时的最后一个过滤器也是它(这就是过滤器链了,往返要都过滤一次)。代码在下面:(一定要将 OpenSessionInViewFilter 配置在所有过滤器的前面)
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <!-- applicationContext对象加载仅加载一次,服务器启动时加载,使用web中的监听器机制 --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param> <!-- OpenSessionInView解决noSession问题,一定要配置在核心过滤器的前面 --> <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> <!-- struts核心过滤器 --> <filter> <filter-name>struts2</filter-name> <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class> </filter> <filter-mapping> <filter-name>struts2</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app>
Hibernate 中 load() 方法导致的 noSession 异常