论坛首页 Java企业应用论坛

如何把数据库表中一条记录变成一个Java对象

浏览 3352 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2007-01-12  
    在hibernate中,把从数据库中查询到的一条记录拷贝到一个是实例,是采用反射的方式来完成的。其流程大致这样的:
//用户实体类,在后面的例子使用
public Class User{
    private int autoId;
    private String name;
    public int getAutoId(){
         return autoId;
    }
    
    public String getName(){
          return name;
 
Class<?> entityClass = Class.forName("User");
while(rs.next()){
    Object entity = entityClass.newInstance();
    //获取中实体的set方法,获取次方已经被缓存,通过缓存来查询的,此处只是用来说明问题
    Method m = entityClass.getMethod("setName");
     m.invoke(entity,rs.getString("name"));
    m = entityClass.getMethod("setAutoId");
    m.invoke(entity,rs.getInt("AutoId"));
}

我不知道oracle,bea和sun的ORM(简称,后面都会这样称呼)是不是也是这样实现,但是我知道我们公司早先的一款ORM和现在的一款ORM都是这样的方案来实现的。

【问题】
    众所周知,在java中,通过反射调用方法相当的消耗资源,而且速度比起直接执行原方法要慢出好多,所以在hibernate中,如果大量的对象被频繁的创建时,在这一块性能是有所下降的,尤其是在高速运行的系统中。这就出现了,有人宁愿直接使用JDBC,也不使用hibernate的现象。

【突发奇想】
    昨天在回家的公交车上,突然想到了早先我写的一个ORM。
    两年前,那时我还在毕业后的第一家公司任职,我在非上班的时间写了一个非常简单的ORM(和iBATIS相像,离开那家公司后我才知道iBATIS,不过在写那个ORM时,我在网上搜寻过,没有找到合适我们那个报表系统的ORM,更没有看到iBATIS,就是iBATIS也不完全适合),后来我把它直接用到了公司的报表系统中,大家也方便了不少。其中有个CallBack类,其结构大致如下:
   
       public interface ResultSetCallBack{
            public Object readEntity(ResultSet rs)throws SQLException;
       }
    

   使用人是只要实现这个接口就行了,以User为例,应该是这样的:
  
      //当时我们的数据不同步,所以没有缓存
      public UserCallBack implements ResultSetCallBack{
          public Object readEntity(ResultSet rs)throws SQLException{
            User user = new User();
            user.setAutoId(rs.getInteger("autoId"));
            user.setName(rs.getString("name"));
            return object;
          }
       }
    

   
    【想法】
    如果把hibernate中“数据拷贝到实例”的方式改用ResultSetCallBack的方式,那hibernate在这一块的性能肯定会有所提高(不知道这一块的性能在整个性能中占据的地位)。
     【实现方式】
      ResultSetCallBack所有的实现类都使用动态生成的方法来完成,至于工具可以采用ASM或者javassit。

【我的实现】

至于怎么实现的"ResultSetCallBack实现类"的动态生成,昨天晚上在家我基本上写好了一个。贴出来主要的部分,其他的可以看附件:

//EntitySetter.java
//CallBack类
public interface EntitySetter {
	public void setEntityProperties(Object object,ResultSet rs) throws SQLException;
}


//JsEntitySetterGenerator.java
//ResultSetCallBack实现类的动态生成类
public class JsEntitySetterGenerator {
	
	private final static ClassPool pool = ClassPool.getDefault();
	
	static{
		pool.importPackage("java.lang");
		pool.importPackage("java.sql");
		pool.importPackage("java.math");
		pool.importPackage("java.util");
	}
	
	private EntityMapping entityMapping;	

	public JsEntitySetterGenerator(EntityMapping em) {
		super();
		this.entityMapping = em;		
	}

	public byte[] generateEntitySetter() throws CannotCompileException,IOException {			
		CtClass c = generateEntitySetter0();
		return c.toBytecode();
	}
	public Class<?> generateEntitySetter(ClassLoader loader) throws CannotCompileException,IOException {			
		CtClass c = generateEntitySetter0();
		return c.toClass(loader, null);
	}
	
	private CtClass generateEntitySetter0() throws CannotCompileException{
		String now = Long.toHexString(System.currentTimeMillis());
		String className = "com/azk/entity/Z_" + now + "_"
				+ entityMapping.getTableName();		
		CtClass c = pool.makeClass(className);		
		List<EntityFieldMapping> list = entityMapping.getFieldMappingList();
		String entityClassInternalName = entityMapping.getClass().getName();
		StringBuffer src = new StringBuffer();
		src.append("public void setEntityProperties(Object obj,ResultSet rs)");
		src.append("		throws SQLException{");
		src.append(entityClassInternalName).append(" entity = (").append(
				entityClassInternalName).append("obj);");
		for (EntityFieldMapping mapping : list) {
			generateSetPropertySource(src, mapping);
		}
		src.append("}");
		CtMethod method = CtMethod.make(src.toString(), c);
		c.addMethod(method);
		return c;
	}

	private void generateSetPropertySource(StringBuffer src,
			EntityFieldMapping mapping) {
		ResultSetSupportedDateType dt = mapping.getDateType();
		if (ResultSetSupportedDateType.Byte == dt) {
			visitPrimitive(src, mapping, Byte.class);
		} else if (ResultSetSupportedDateType.Short == dt) {
			visitPrimitive(src, mapping, Short.class);
		} else if (ResultSetSupportedDateType.Int == dt) {
			visitPrimitive(src, mapping, Integer.class);
		} else if (ResultSetSupportedDateType.Long == dt) {
			visitPrimitive(src, mapping, Long.class);
		} else if (ResultSetSupportedDateType.Float == dt) {
			visitPrimitive(src, mapping, Float.class);
		} else if (ResultSetSupportedDateType.Double == dt) {
			visitPrimitive(src, mapping, Double.class);
		} else if (ResultSetSupportedDateType.Date == dt
				|| ResultSetSupportedDateType.String == dt
				|| ResultSetSupportedDateType.Timestamp == dt) {
			visitSimpleNonePrimitive(src, mapping);
		} else if (ResultSetSupportedDateType.Blob == dt) {
			visitBlobMethod(src, mapping);
		} else if (ResultSetSupportedDateType.Clob == dt) {
			visitClobMethod(src, mapping);
		}		
	}

	private void visitSimpleNonePrimitive(StringBuffer src,
			EntityFieldMapping mapping) {
		String resultSetMethod = mapping.getDateType().getResultSetMethodName();
		String propertyName = mapping.getPropertyName();
		EntitySetterMethodInfo inf = buildSetterInfo(propertyName);
		String fieldName = mapping.getTableFieldName();		
		src.append("entity.").append(inf.getMethodName()).append("(");		
		src.append("rs.").append(resultSetMethod).append("(\"").append(
				fieldName).append("\")");		
		src.append(");");
	}

	private void visitPrimitive(StringBuffer src, EntityFieldMapping mapping,
			Class<?> btAd) {
		String resultSetMethod = mapping.getDateType().getResultSetMethodName();
		String propertyName = mapping.getPropertyName();
		EntitySetterMethodInfo inf = buildSetterInfo(propertyName);
		String fieldName = mapping.getTableFieldName();
		// entity.setAge(
		src.append("entity.").append(inf.getMethodName()).append("(");
		if (inf.getParameterType() == btAd) {
			// new Integer(
			src.append("new ").append(btAd.getName()).append("(");
			// rs.getInt("age")
			src.append("rs.").append(resultSetMethod).append("(\"").append(
					fieldName).append("\")");
			// )
			src.append(")");
		} else {
			// rs.getInt("age")
			src.append("rs.").append(resultSetMethod).append("(\"").append(
					fieldName).append("\")");
		}
		// );
		src.append(");");
	}
	
	protected void visitBlobMethod(StringBuffer src, EntityFieldMapping mapping) {
		throw new UnsupportedDataType();
	}

	protected void visitClobMethod(StringBuffer src, EntityFieldMapping mapping) {
		throw new UnsupportedDataType();
	}

	private EntitySetterMethodInfo buildSetterInfo(String propertyName) {
		String fc = propertyName.substring(0, 1).toUpperCase();
		String methodName = "set" + fc + propertyName.substring(1);
		Method[] ms = entityMapping.getEntityClass().getMethods();
		for (Method method : ms) {
			if (method.getName().equals(methodName)) {
				Class<?>[] paramType = method.getParameterTypes();
				if (paramType.length == 1) {
					EntitySetterMethodInfo inf = new EntitySetterMethodInfo();
					inf.setDesc(Type.getMethodDescriptor(method));
					inf.setParameterType(paramType[0]);
					inf.setMethodName(methodName);
					return inf;
				}
			}
		}
		return null;
	}

	protected class EntitySetterMethodInfo {
		private String desc;

		private Class<?> parameterType;

		private String methodName;

		public String getDesc() {
			return desc;
		}

		public void setDesc(String desc) {
			this.desc = desc;
		}

		public Class<?> getParameterType() {
			return parameterType;
		}

		public void setParameterType(Class<?> parameterType) {
			this.parameterType = parameterType;
		}

		public String getMethodName() {
			return methodName;
		}

		public void setMethodName(String methodName) {
			this.methodName = methodName;
		}
	}

}



package com.azk.orm;

public class ResultSetSupportedDateType {
	public static final ResultSetSupportedDateType Byte = new ResultSetSupportedDateType(
			"B", "getByte");

	public static final ResultSetSupportedDateType Short = new ResultSetSupportedDateType(
			"S", "getShort");

	public static final ResultSetSupportedDateType Int = new ResultSetSupportedDateType(
			"I", "getInt");

	public static final ResultSetSupportedDateType Long = new ResultSetSupportedDateType(
			"J", "getLong");

	public static final ResultSetSupportedDateType Float = new ResultSetSupportedDateType(
			"F", "getFloat");

	public static final ResultSetSupportedDateType Double = new ResultSetSupportedDateType(
			"D", "getDoucle");

	public static final ResultSetSupportedDateType String = new ResultSetSupportedDateType(
			"java/lang/String", "getInt");

	public static final ResultSetSupportedDateType Date = new ResultSetSupportedDateType(
			"java/sql/Date", "getInt");

	public static final ResultSetSupportedDateType Timestamp = new ResultSetSupportedDateType(
			"java/sql/Timestamp", "getTimestamp");

	public static final ResultSetSupportedDateType BigDecimal = new ResultSetSupportedDateType(
			"java/math/BigDecimal", "getBigDecimal");

	public static final ResultSetSupportedDateType Clob = new ResultSetSupportedDateType(
			"java/sql/Clob", "getClob");

	public static final ResultSetSupportedDateType Blob = new ResultSetSupportedDateType(
			"java/sql/Blob", "getBlob");

	private String typeClassName;

	private String resultSetMethodName;

	private ResultSetSupportedDateType(String typeName,
			String resultSetMethodName) {
		this.typeClassName = typeName;
		this.resultSetMethodName = resultSetMethodName;
	}

	public String getTypeClassName() {
		return typeClassName;
	}

	public void setTypeClassName(String typeClassName) {
		this.typeClassName = typeClassName;
	}

	public String getResultSetMethodName() {
		return resultSetMethodName;
	}

	public void setResultSetMethodName(String resultSetMethodName) {
		this.resultSetMethodName = resultSetMethodName;
	}
}

论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics