浏览 1200 次
|
精华帖 (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;
}
}
声明:JavaEye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
|
|
| 返回顶楼 | |


