`
wuyunlong
  • 浏览: 9471 次
  • 来自: ...
文章分类
社区版块
存档分类
最新评论

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

阅读更多
    在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持久化.pdf

    3. **游离状态(Detached)**:持久化对象在某些情况下可能会从Session的缓存中移除,但仍与数据库中的一条记录相对应,这时它就变成了游离对象。游离对象需要手动管理,以确保数据同步。 对象状态的转换主要由...

    Java分页技术+数据库

    2. **MyBatis分页**:MyBatis是一个流行的持久层框架,它允许在Mapper XML文件或注解中直接写SQL,支持动态SQL,分页插件如PageHelper可以简化分页逻辑。配置好插件后,只需在查询方法上添加Page对象,MyBatis会自动...

    hibernate对象三状态及OneToOne&OneToMany&ManyToMany

    3. 持久态(Persistent):对象已通过Session保存,与数据库中的一条记录对应。一旦对象变为持久态,Hibernate会负责它的生命周期管理,包括插入、更新和删除操作。 二、一对一(OneToOne)关系映射 在数据库设计...

    java就业数据库面试题.pdf

    - **代码复用**:可以通过一个存储过程调用另一个存储过程,简化复杂的操作流程。 - **减少网络流量**:存储过程可以执行一系列SQL语句,减少了与数据库交互的次数,从而降低了网络开销。 - **安全性增强**:存储...

    数据库—教务管理系统

    每个实体变为一个表,每条关系变为表间的关系。例如,“学生”实体对应“Student”表,“教师”对应“Teacher”表,“课程”对应“Course”表,“学生选课”关系可以转化为“Enrollment”表,包含学生学号和课程号...

    Hibernate中对象的三种状态

    持久态对象拥有唯一的数据库标识,并且与数据库中的一条记录相对应。在Session的生命周期内,对持久态对象的修改会被跟踪,当调用`flush()`方法时,这些更改会被同步到数据库。如果Session关闭,再打开新的Session,...

    hibernate持久化对象生命周期[参照].pdf

    - Hibernate保证每个Session实例的缓存中,每条数据库记录仅对应一个持久化对象。这意味着在不同Session实例中,相同数据库记录可能会有不同的持久化对象实例。 - 如果试图让一个Java对象同时被两个Session实例...

    java生成UUID通用唯一识别码 中文WORD版

    - 数据库记录的主键:UUID可以作为数据库表记录的主键,保证每条记录的唯一性,尤其在分布式数据库系统中。 - 临时ID:在需要临时唯一标识的场景下,UUID是一个好选择,因为它不会与其他系统产生的ID冲突。 - ...

    SSH面试题详细总结.pdf

    - 一对多(OneToMany):一个实体对应数据库表中的多条记录,通常使用Set或List集合存储。 - 多对多(ManyToMany):两个实体之间有多对多关系,通常通过中间表来实现。 了解这些核心概念对于理解和使用Hibernate...

    JPA学习笔记-EJB-05JPA实体对象状态和实体对象的高级操作

    此时,该对象仅仅是一个普通的Java Bean,并没有与数据库建立关联。 2. **托管状态(Managed State)** 一旦瞬时状态的对象通过`persist()`方法被实体管理器管理后,该对象转变为托管状态。在此状态下,实体管理...

    Java23种设计模式(总结)

    将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。 - **适用场景**: - 有多个对象可以处理一个请求,哪个对象处理该请求运行时刻自动确定。 - 在不明确指定接收者的情况下,向多个对象...

    05_传智播客hibernate教程_实体对象的三种状态与saveOrUpdate方法

    例如,如果你试图更新一个已存在于数据库中的对象,但该对象的ID未知或已被错误地设置,`saveOrUpdate`可能会意外地插入一条新记录而不是更新原有记录。因此,在使用`saveOrUpdate`时,需确保对象的状态和标识符的...

    Java分页源代码代码

    在Java编程中,分页是数据管理中一个重要的概念,特别是在处理大数据集合时,它可以有效地减少内存消耗并提高用户体验。本项目提供了一套完整的Java分页源代码,包含与数据库交互的部分,使得开发者可以直接运行并...

    jdbc基础和参考

    ORM:使用元数据信息来描述对象和数据库之间的关系,并且能够自动实现java中持久化对象到关系型数据库中表的映射 脏检查:自动对缓存中的数据进行检查,并且选择在合适的时机和数据库之间进行交互,以保持数据的...

    从oracle生成表的数据字典方法

    当 `COLUMN_ID` 为 1 时,表示第一条记录,此时返回表的注释;否则返回空字符串。 - 使用了多个 **JOIN** 来关联不同的视图: - `user_tables` 与 `user_tab_columns` 联接,获取表及其列信息。 - `user_tab_...

    java面试800题

    Q0030 在数据库中什么代表一条记录? 主健 Q0031 如何编写效率高的SQL语句? "1.根据查询条件建立合适的index 2.因为SQL是从右向左解析,多表查询时,记录数少的表放在右边 3.多个条件时,收敛快的条件放在右边。 4...

    Hibernate中的实体状态及转换

    3. **游离状态(Detached)**:游离状态的实体对象已经离开了Session的管理,但它的主键ID仍然与数据库中的一条记录对应。这意味着对象与数据库有连接,但当前Session不知道这个对象。游离状态的对象可以通过Session的...

    Hibernate中的merge使用详情解说.docx

    它们代表了数据库中的一条记录,但不再受Hibernate的管理。 2. **merge()操作**: - 当你对一个游离态对象调用`merge()`时,Hibernate首先检查该对象的ID。如果ID存在,那么: - 如果数据库中找不到匹配的ID,`...

    原生Java操作mysql数据库过程解析

    例如,插入一条记录: ```java String sql = "INSERT INTO table (column1, column2) VALUES (?, ?)"; pstmt = conn.prepareStatement(sql); pstmt.setString(1, value1); pstmt.setString(2, value2); pstmt...

Global site tag (gtag.js) - Google Analytics