问题描述
实体类代码如下:public class Organization {private int id;private String name;private String sn;private String description;private Organization parent;private Set children;get和set省略}业务实现类://删除机构public void delete(int orgId) {Organization org =(Organization)this.getHibernateTemplate().load(Organization.class, orgId);System.out.println(org.getChildren().size());}getchildren和getparent都无法读取,null调用size导致空指针异常但能顺利的读取description等属性配置如下<?xml version="1.0"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><hibernate-mapping><class name="com.yourcompany.modle.Organization"><id name="id"><generator class="native" /></id><property name="name" /><property name="sn"/><property name="description"/><many-to-one name="parent" column="pid"/><set name="children" inverse="true" lazy="extra"><key column="pid"/><one-to-many class="com.yourcompany.modle.Organization"/></set></class></hibernate-mapping>
解决方案
引用这位兄弟,他的引用都指出来了,这个事物是否关闭有什么关系啊。。。这个引用是CGLib增强后的代理对象,根本就不是原来的对象。当代码调用org.getChildren().size()的时候会判断是否已经加载,如果lazy="false"的话就没问题,load的时候肯定是已经加载了。如果lazy="true"(默认)的话,代理对象发现没有加载过,触发sql语句加载children,但是发现session已经关闭了。哦,我明白了,这个时候因为没有Spring事务的保护,其实已经是Detached的对象了,因为laze="true",所以children是空的。提醒楼主,默认状态下getHibernateTemplate()中的方法都是会自动关闭session的,如果楼主要学习的话,请直接调用session的方法,而不要太依赖getHibernateTemplate(),如果是要正二八经的开发,请使用Spring的事务配置,给这段代码所在的方法加上事务。
解决方案二:
<set name="children" inverse="true" lazy="extra">改成<set name="children" inverse="true" lazy="false">试试因为你没有这个事务管理,而getHibernateTemplate().load方法执行完以后,session就自动关掉了。这位兄弟,他的引用都指出来了,这个事物是否关闭有什么关系啊。。。
解决方案三:
用了spring么?用了的话。你在业务实现类这一级的方法上加事务,在一个事务中,一般配置下,spring会用org.springframework.orm.hibernate3.HibernateTransactionManager,以保证在一个事务中的session一直是开着的。因为你没有这个事务管理,而getHibernateTemplate().load方法执行完以后,session就自动关掉了。