使用JPA(Hibernate)中的问题总结

除非特别声明,Hibernate版本都是3.x。


 1. Hibernate 3复合主键(composite-id)与NULL值:在Hibernate 3中,如果复合主键中的一个属性(key-property)为null值,那么整个对象返回值等于null。
一个解决办法是,新建一个视图(view),对可能等于null值的字段使用mysql中的coalesce函数(其他数据库可能叫做isnull函数或NVL函数),将null列转换为一个特殊值。当然最好的办法是尽量不要用复合主键(推荐使用proxy id或unique id), composite id是evil!(除非legacy database系统万不得已这样做)。


2.不要试图对non-persistent对象赋临时属性(等价问题:区分persistent和non-persistent对象):JPA中,non-persistent对象转换为持久化对象之后,两个对象的hash id可能会不一样,比如在一个用@Transaction标记的方法M中,已知对象A是持久化对象,它的一个属性objects是一个collection(暂时不考虑lazy load的问题,并且假定该集合中的元素已经是持久化对象),如果往objects中添加一个non-persistent对象b,在Transaction结束时,通过hibernate的cascade=ALL,会将所有的关联对象持久化,设对象b的持久化化身(incarnation)为b',此时b'跟b的object hash id不一样(注意hash id与entity id不一样;另外,如果使用@GeneratedValue(strategy=IDENTITY)作为entity id的生成方式, entity id在事务commit之前就从数据库得到id值了,从而可以在方法M中使用这个entity id)。如果在方法M中给b赋一个临时属性(transient),那么方法调用结束(同时事务完成)时这个临时属性在持久化的对象b'中不复存在(此时非持久化对象b已经被GC'ed, sigh!)

解决办法是,在方法M中显式调用DAO的save方法,将b持久化为b',然后给b'赋一个临时属性。如果要使用对象b,千万不要依赖hibernate作flush时自动持久化。


3. 不能简单地清除Collection属性,需要显式删除:

假设持久化对象A有一个Collection类型的属性values,而且values不为空,如果现在要清空values,然后添加2个新的元素x和y。下面的写法(伪代码)是错误的:
List newValz = new ArrayList();
newValz.add(x);
newValz.add(y);
A.setValues(newValz);
service.save(A);
这是因为values集合中原来的对象已经是持久化对象,如果这样调用,相当于往values集合中添加两个元素x和y,但是values原来的持久化对象并没有清除。正确做法是:显式调用DAO层的remove方法,逐个将values中的持久化对象删除,然后保存newValz:
List newValz = new ArrayList();
newValz.add(x);
newValz.add(y);
service.save(A,newValz);

其中service.save(A,newValz)方法如下(伪代码):
for(Object val:A.getValues()){
   dao.remove(val);
}
A.setValues(newValz);
this.save(A);


你可能感兴趣的:(DAO,Hibernate,数据库,object,jpa,null)