关系数据库实际上只支持多对一或一对一的单向关联。我们每次在hbm和持久化类中都对外键做双向设置实际是多余的,如:

Cardparameter.java

  1. /**注册卡信息**/ 
  2.     private Cardinfo cardinfo; 

Cardparameter.hbm.xml

  1. <many-to-one name="cardinfo" class="com.telezone.domain.Cardinfo" fetch="select"> 
  2.             <column name="CARDID" precision="22" scale="0" not-null="true" /> 
  3.         </many-to-one> 
  4.  

Cardinfo.hbm.xml

  1. <set name="cardparameters" inverse="true" cascade="delete"> 
  2.             <key> 
  3.                 <column name="CARDID" precision="22" scale="0" 
  4.                     not-null="true" /> 
  5.             </key> 
  6.             <one-to-many class="com.telezone.domain.Cardparameter" /> 
  7.         </set> 

Cardinfo.java

  1. /**卡参数即卡状态信息集合**/ 
  2.     private Set<Cardparameter> cardparameters = new HashSet<Cardparameter>(0); 

而我们项目中,并没有通过cardinfo取过它对应的所有cardparameter,都是根据cardid写sql去数据库查找的……而且每次加载一个对象,会加载很多set对象到内存中,也很浪费吧。

比如cardinfo中很多set集合属性:

  1. /**区域定位信息集合**/ 
  2.     private Set<Arealocatedata> arealocatedatas = new HashSet<Arealocatedata>(0); 
  3.     /**短信集合**/ 
  4.     private Set<Smsinfo> smsinfos = new HashSet<Smsinfo>(0); 
  5.     /**报警设置信息集合**/ 
  6.     private Set<Alarmsetinfo> alarmsetinfos = new HashSet<Alarmsetinfo>(0); 
  7.     /**卡余额信息集合**/ 
  8.     private Set<Cardbalance> cardbalances = new HashSet<Cardbalance>(0); 
  9.     /**套餐余量信息集合**/ 
  10.     private Set<Premaininfo> premaininfos = new HashSet<Premaininfo>(0); 
  11.     /**卡对象信息集合**/ 
  12.     private Set<Cardownerinfo> cardownerinfos = new HashSet<Cardownerinfo>(0); 
  13.     /**报警信息集合**/ 
  14.     private Set<Alarmrecord> alarmrecords = new HashSet<Alarmrecord>(0); 
  15.     /**朋友信息集合**/ 
  16.     private Set<Friendinfo> friendinfos = new HashSet<Friendinfo>(0); 
  17.     /**卡参数即卡状态信息集合**/ 
  18.     private Set<Cardparameter> cardparameters = new HashSet<Cardparameter>(0); 
  19.     /**卡交易信息集合**/ 
  20.     private Set<Cardtrade> cardtrades = new HashSet<Cardtrade>(0); 
  21.     /**卡与服务绑定信息集合**/ 
  22.     private Set<Cardserviceinfo> cardserviceinfos = new HashSet<Cardserviceinfo>(0); 
  23.     /**卡与手机绑定信息集合**/ 
  24.     private Set<Cardphoneinfo> cardphoneinfos = new HashSet<Cardphoneinfo>(0); 
  25.     /**实时定位信息集合**/ 
  26.     private Set<Locatedata> locatedatas = new HashSet<Locatedata>(0); 

如果每次加载一个cardinfo对象,就会把所有一对多的数据都会加载到内存中,尤其是数据量很大的实时定位数据,那太恐怖了!!

为了验证每次加载cardinfo对象时,是不是所有一对多的数据都会加载到内存中,我进行了测试,去获得cardinfo的cardparameters集合,结果取不出来cardparameters报错:

  1. failed to lazily initialize a collection of role: com.telezone.domain.Cardinfo.alarmrecords, no session or session was closed 

为什么项目中的没加载进来而且报错呢?

因为开启了延迟加载,查询cardinfo时并没有主动加载所关联的cardparameters也就是说,当用到另一个表的数据时,再去数据库中查询该表的数据。但是这个查询还需要使用之前查询所使用的连接。

关闭延迟加载的方法是加入lazy="false"

  1. <set name="cardparameters" inverse="true" lazy="false" cascade="delete">  
  2.             <key>  
  3.                 <column name="CARDID" precision="22" scale="0" />  
  4.             </key>  
  5.             <one-to-many class="com.telezone.domain.Cardparameter" />  
  6.    </set>  

然后就能得到cardinfo的cardparameters了。

验证了可以取到,但这种同时取出的做法十分不明智。也就是说我们不需要设置Cardinfo的一对多关系。只设置Cardparameter的多对一单向关系就可以了。