基于cglib反射的数据库查询结果封装为对象(简单的orm实现)
基于jar:cglib 2.2
数据库:mysql
背景:
目前正在写一个简单的新闻等文字分析系统(爬虫搜索引擎类型的,写着玩的),为了提高分析数据分析的效率,提高数据库与代码的交换效率,并没有使用hibernate等工具。但是这个系统也必须实现对查询结果的对象封装。
思路:
因此我采用特别查询到频繁的对象直接写在代码里面,其他查询不是很频繁的类采用以下代码进行动态字节码生成进行对象封装。
说明:
简单的orm代码实现,可以通过传人的数据库字段名称和对象字段名称,进行数据库查询内容进行自动封装
注意:这个只是演示cglib自动封装使用。正式环境中需要考虑以下问题:
1:动态字节码生成效率低,当特别频繁调用的时候肯定是效率瓶颈。
2:动态字节码生成肯定会给jvm内存中的方法区带来压力,也会给gc带来工作量。因此写相关代码一定要注意。
3:注意ResultSet一般不要用于数据传递。
对象封装类如下:
1 package com.zwh.base.dao; 2 3 import java.lang.reflect.Method; 4 import java.sql.Date; 5 import java.sql.ResultSet; 6 import java.sql.ResultSetMetaData; 7 import java.sql.SQLException; 8 import java.util.ArrayList; 9 import java.util.List; 10 11 import net.sf.cglib.reflect.FastClass; 12 import net.sf.cglib.reflect.FastMethod; 13 14 /** 15 * 用于与数据库查询使用的反射类,不知道咋设计啊,反正目前只用于数据库对象的封装 16 * @ClassName: Reflect 17 * @author ZHANGWENHAO zhangwenhao3@sina.com 18 * @date 2013-10-29 下午01:50:28 19 * @param <T> 20 */ 21 public class Reflect<T>{ 22 23 /** 24 * 通过cglib反射自动封装数据库查询数据,注意,临时产生新的字节码过多的时候,会内存溢出,目前3.2以上的hibernate版本据说是直接使用asm 但是效率不会比这个效率明显增加多少了(增加的效率应不是产生在动态生成字节码这一部分了) 25 * 这个效率是相当高的了,是直接调用的10倍左右,比有安全校验的java原生反射好很多 26 * @param columnsName 数据库字段名称数组 27 * @param fieldsName 对应的对象字段名称数组 28 * @param columnsType 对应的字段的类型(简单数据类型请传入class,不要传入type) 29 * @param rs 数据库查询结果 30 * @param classType 需要封装的对象类别 31 * @return 封装后的对象列表 32 * @author ZHANGWENHAO 33 * @date 2013-10-29 下午05:00:44 34 */ 35 public List<T> beanWrapper(String[] columnsName, String[] fieldsName, Class<?>[] columnsType, ResultSet rs, Class<T> classType){ 36 try { 37 // 判断数据库查询结果是否有一个列阶段 38 String columns = getAllColumn(rs); 39 int length = columnsName.length; 40 boolean[] keys = new boolean[length]; 41 for(int i=0;i<length;i++){ 42 // 获取是否有一个字段 43 keys[i] = columns.indexOf(columnsName[i])>=0; 44 } 45 // 对象反射阶段 46 FastClass fastClass = FastClass.create(classType); 47 List<T> result = new ArrayList<T>(); 48 while(rs.next()){ 49 T temp = classType.newInstance(); 50 for(int j=0;j<length;j++){ 51 // 拼写方法名 52 String methodStr="set"+fieldsName[j].replaceFirst(fieldsName[j].substring(0, 1), fieldsName[j].substring(0, 1).toUpperCase()); 53 Method method = classType.getMethod(methodStr, columnsType[j]); 54 FastMethod fastSetMethod = fastClass.getMethod(method); 55 if(keys[j]){//按照使用频率排列(按需书写) 为了提高效率啊 这里就不动态拼调用方法了,直接调用可是会快一个0的(10倍到100倍) 56 if(String.class.equals(columnsType[j])){//字符串 57 Object object = rs.getString(columnsName[j]); 58 fastSetMethod.invoke(temp, new Object[]{object}); 59 }else if(Integer.class.equals(columnsType[j])){//int 60 Object object = rs.getInt(columnsName[j]); 61 fastSetMethod.invoke(temp, new Object[]{object}); 62 }else if(Date.class.equals(columnsType[j])){//日期 63 Object object = rs.getDate(columnsName[j]); 64 fastSetMethod.invoke(temp, new Object[]{object}); 65 }else if(Double.class.equals(columnsType[j])){//double 66 Object object = rs.getDouble(columnsName[j]); 67 fastSetMethod.invoke(temp, new Object[]{object}); 68 }else if(Long.class.equals(columnsType[j])){//long 69 Object object = rs.getLong(columnsName[j]); 70 fastSetMethod.invoke(temp, new Object[]{object}); 71 }else if(Short.class.equals(columnsType[j])){ 72 Object object = rs.getShort(columnsName[j]); 73 fastSetMethod.invoke(temp, new Object[]{object}); 74 } 75 } 76 } 77 result.add(temp); 78 } 79 return result; 80 } catch (Exception e) { 81 System.out.println("通过反射,获取对象出错,对象名称"); 82 e.printStackTrace(); 83 return new ArrayList<T>(); 84 } 85 } 86 87 /** 88 * 采用字符串校验是否有一个字段,最轻量级,效率最高(在目前这个情况下是这样的) 89 * @return 90 * @author ZHANGWENHAO 91 * @throws SQLException 92 * @date 2013-9-22 下午03:42:46 93 */ 94 private String getAllColumn(ResultSet rs) throws SQLException{ 95 StringBuilder sb = new StringBuilder(); 96 ResultSetMetaData rsmd = rs.getMetaData(); 97 for(int i=1;i<=rsmd.getColumnCount();i++){ 98 sb.append(rsmd.getColumnName(i)).append(","); 99 } 100 return sb.toString(); 101 } 102 103 }
调用实例:
public List<SpiderModel> sqlResultToSpiderModel(ResultSet rs) { // 预留,参数传入,反正这个效率很高 String columnsName[] = new String[]{ "id", "source_name", "title_tag", "content_tag", "char_set" }; String fieldsName[] = new String[]{ "id", "sourceName", "titleTag", "contentTag", "charSet" }; Class<?> columnsType[] = new Class<?>[]{Integer.class,String.class,String.class,String.class,String.class}; Reflect<SpiderModel> reflect = new Reflect<SpiderModel>(); List<SpiderModel> result = reflect.beanWrapper(columnsName, fieldsName, columnsType, rs, SpiderModel.class); return result; }
说明:这个是我的数据库的测试测试代码,大家测试的时候请使用自己的数据库测试,rs使用原生的数据库查询方法生成conn.getStatement().executeQuery(sql);相关内容不再赘述。
代码有什么不合适的地方或者不对的地方,请各位大神多多指点,多多交流。
原创代码,转载请说明,并保留此出处http://www.cnblogs.com/zhangwenhao/p/3397068.html 。谢谢。