hibernate数据库:Hibernate通用序列化方案 避免延迟加载问题及序列化整个数据库至客户端

  在使用Ajax: Hibernate Entity => json, Flex RemoteObject: Hibernate Entity => ActionScript Object过程,经常碰到如下问题:

  问题:

  1.Hibernate碰到延迟加载属性访问时如果session被关闭则抛出LazyInitializationException

  2.Hibernate中one-to-many等关联关系在序列化时如果没有控制,则将整个数据库都有可能被全部序列化

  3.过多使用DTO/ValueObject解决这个问题.

  解决办法:

  对Entity对象生成个动态代理,拦截getXXXX思路方法,如果访问是延迟加载属性,则 null,而不抛出LazyInitializationException,递归生成属性代码,只要碰到未延迟加载属性,而序列化会自动停止.避免将整个Entity序列化传播,导致可能序列化整个数据库问题.

  类似解决方案:

  dwr中HibernateConverter,在序列化时如上类似,碰到延迟加载属性自动停止convert工作.而HibernateBeanSerializer则劳永逸,无论object => json都可以工作.

  使用用例:

  Java代码   

//role为原始对象 
role = (Role)roleDao.getById( Long(1)); 
//生成动态代理proxyRole,访问延迟加载属性将 null 
Role proxyRole = (Role) HibernateBeanSerializer<Role>(role).getProxy; 
assertNotNull(role.getResource);  
assertNull(proxyRole.getResource); //延迟加载,为null 
 
Hibernate.initialize(role.getResource); //抓取进来 
assertNotNull(proxyRole.getResource); //不为null


  源码.

  Java代码   

package cn.org.rapid_framework.util; 
 
import java.lang.reflect.Modier; 
import java.util.ArrayList; 
import java.util.Collection; 
import java.util.LinkedHashMap; 
import java.util.LinkedHashSet; 
import java.util.List; 
import java.util.Map; 
import java.util.Set; 
 
import org.aopalliance.ercept.MethodInterceptor; 
import org.aopalliance.ercept.MethodInvocation; 
import org.hibernate.Hibernate; 
import org.hibernate.collection.PersistentCollection; 
import org.hibernate.proxy.HibernateProxy; 
import org.springframework.aop.framework.ProxyFactory; 
import org.springframework.util.StringUtils; 
 
/** 
 * 用于Hibernate Object 序列化,访问延迟加载属性不会抛出LazyInitializationException,而会返回null值. 
 * 使用: 
 * <pre> 
 * Blog proxyBlog =  HibernateBeanSerializer(blog).getProxy; 
 * </pre> 
 * @author badqiu 
 * @param <T> 
 */ 
public  HibernateBeanSerializer <T> { 
 T proxy = null; 
 /** 
 */ 
 public HibernateBeanSerializer(T object,String... excludesProperties) { 
 (object  null) { 
  this.proxy = null; 
 } { 
  ProxyFactory pf =  ProxyFactory; 
  pf.TargetClass(object.getClass); 
  pf.Optimize(true); 
  pf.Target(object); 
  pf.ProxyTargetClass(true); 
  pf.Opaque(true); 
  pf.ExposeProxy(true); 
  pf.PreFiltered(true); 
  HibernateBeanSerializerAdvice beanSerializerAdvice =  HibernateBeanSerializerAdvice; 
  beanSerializerAdvice.ExcludesProperties(excludesProperties); 
  pf.addAdvice(beanSerializerAdvice); 
  
  this.proxy = (T)pf.getProxy; 
 } 
 } 
 
 public T getProxy{ 
  this.proxy; 
 } 
 
  private  HibernateBeanSerializerAdvice implements MethodInterceptor { 
 private String excludesProperties =  String[0]; 
 public String getExcludesProperties { 
   excludesProperties; 
 } 
 public void ExcludesProperties(String excludesProperties) { 
  this.excludesProperties = excludesProperties  null ?  String[0] : excludesProperties; 
 } 
 public Object invoke(MethodInvocation mi) throws Throwable { 
  String propertyName = getPropertyName(mi.getMethod.getName); 
  Class Type = mi.getMethod.getReturnType; 
  
  (propertyName  null) { 
   mi.proceed; 
  } 
  (!Hibernate.isPropertyInitialized(mi.getThis, propertyName)) { 
   null; 
  } 
  (isExclude(mi, propertyName)) { 
   null; 
  } 
  
  Object Value = mi.proceed; 
   processReturnValue(Type, Value); 
 } 
  
 private Object processReturnValue(Class Type, Object Value) { 
  (Value  null) 
   null; 
  (Type != null && Modier.isFinal(Type.getModiers)) { 
   Value; 
  } 
  //This might be a lazy-collection so we need to double check 
  (!Hibernate.isInitialized(Value)) { 
   null;   
  } 
  
  //this is Hibernate Object 
  (Value instanceof HibernateProxy) { 
    HibernateBeanSerializer(Value).getProxy; 
  } (Value instanceof PersistentCollection) { 
  (Type.isAssignableFrom(Map.)) { 
   Map proxyMap =  LinkedHashMap; 
   Map map = (Map)Value; 
   Set<Map.Entry> entrySet = map.entrySet; 
   for(Map.Entry entry : entrySet) { 
   proxyMap.put(entry.getKey,  HibernateBeanSerializer(entry.getValue)); 
   } 
    proxyMap; 
  } 
   
  Collection proxyCollection = null; 
  (Type.isAssignableFrom(Set.)) { 
   proxyCollection =  LinkedHashSet; 
  } (Type.isAssignableFrom(List.)) { 
   proxyCollection =  ArrayList; 
  } { 
    Value; 
  } 
   
  for(Object o : (Collection)Value) { 
   proxyCollection.add( HibernateBeanSerializer(o).getProxy); 
  } 
   proxyCollection; 
  } { 
   Value; 
  } 
 } 
 
 private boolean isExclude(MethodInvocation mi, String propertyName) 
  throws Throwable { 
  
  for(String excludePropertyName : excludesProperties) { 
  (propertyName.equals(excludePropertyName)) { 
    true; 
  } 
  } 
  
   false; 
 } 
  
 private  String getPropertyName(String methodName) { 
  String propertyName = null; 
  (methodName.startsWith("get")) { 
  propertyName = methodName.sub("get".length); 
  } (methodName.startsWith("is")) { 
  propertyName = methodName.sub("is".length); 
  } (methodName.startsWith("")) { 
  propertyName = methodName.sub("".length); 
  } 
   propertyName  null ? null : StringUtils.uncapitalize(propertyName); 
 } 
 } 
} 


  另这个类属于rapid-framework部分,v2.0版本flex RemoteObject将采用这个办法.preview版本即将发布



Tags:  数据库客户端 数据库客户端软件 hibernate延迟加载 hibernate数据库

延伸阅读

最新评论

发表评论