初步封装jdbc
2015-12-27 14:39
387 查看
单纯的通过jdbc来写数据库操作时,有很多“废话”代码,不写又不行,写了又嫌麻烦。一些持久层框架帮助我们解决了这些问题。大大加快了开发的效率。我刚接触反射,于是自己琢磨着写一个初步的jdbc封装,既可以练手,又可以复用,关键是自己造的小轮子,使用过程中,思路和注意点会非常清晰。若有错误,十分欢迎各位前辈指正!这只是一个初步的简单封装,用的一些初级的语句测试,都没有问题。不过如果是复杂的sql语句有可能会出现bug。一步一步来吧。遇到问题,用debug模式调试,效率很高,容易发现不起眼的细节问题。
说明一下自己的思路。首先,一定是面向对象的,传值和返回值,我们都是以一个对象作为参数传递。这样在不同的模块操作时,有利于一个整体的思路,并且扩展性稍好。其次,一个sql语句包含了字段名,我们只需要获取到字段名对应的值,那么sql语句就可以执行了。执行之后的结果,分为两部分,一是执行executeQuery,所以我们需要对获取到的记录进行封装,有几条就封装几个,最后装入一个ArrayList,作为返回值即可。二是执行executeUpdate,返回值是一个int的整数,只需判断是否大于零,返回true或者false即可。这是整个流程的整体思路。
以下是代码:
说明一下自己的思路。首先,一定是面向对象的,传值和返回值,我们都是以一个对象作为参数传递。这样在不同的模块操作时,有利于一个整体的思路,并且扩展性稍好。其次,一个sql语句包含了字段名,我们只需要获取到字段名对应的值,那么sql语句就可以执行了。执行之后的结果,分为两部分,一是执行executeQuery,所以我们需要对获取到的记录进行封装,有几条就封装几个,最后装入一个ArrayList,作为返回值即可。二是执行executeUpdate,返回值是一个int的整数,只需判断是否大于零,返回true或者false即可。这是整个流程的整体思路。
以下是代码:
public class CrudOperation { public Object operator(String sql,Object entity){ String[] array=entity.getClass().toString().split(" "); String className=array[1]; Object object=null; Connection con=null; PreparedStatement ps=null; ResultSet rs=null; int n=0; Map<String,Object> map=reflectForParameters(className,sql,entity); ArrayList<String> columnList=(ArrayList<String>) map.get("column"); ArrayList<Object> parameterList=(ArrayList<Object>) map.get("parameter"); ArrayList<String> returnTypeList=(ArrayList<String>) map.get("returnType"); ArrayList<Object> resultOfEntity=new ArrayList<Object>(); con=JdbcConnection.getConnection(); try { Class clazz=Class.forName(className); ps=con.prepareStatement(sql); for(int i=0;i<columnList.size();i++){ if("Integer".equalsIgnoreCase(returnTypeList.get(i))||"int".equalsIgnoreCase(returnTypeList.get(i))){ ps.setInt(i+1,(Integer) parameterList.get(i)); } else if("Date".equalsIgnoreCase(returnTypeList.get(i))){ ps.setDate(i+1, (Date) parameterList.get(i)); } else{ ps.setString(i+1, (String) parameterList.get(i)); } } if(sql.trim().startsWith("select")){ rs=ps.executeQuery(); ArrayList<Object> result=result=new ArrayList<Object>();//这句放到while(rs.next)下面,不然出bug,刚发现的 while(rs.next()){ Field[] fields=clazz.getDeclaredFields(); for(Field f:fields){ if(!"serialVersionUID".equals(f.getName().toString())){ if("int".equalsIgnoreCase(f.getType().toString().substring(f.getType().toString().lastIndexOf(".")+1)) ||"Integer".equalsIgnoreCase(f.getType().toString().substring(f.getType().toString().lastIndexOf(".")+1))){ resultOfEntity.add(rs.getInt(f.getName().toString())); } else if("Date".equalsIgnoreCase(f.getType().toString().substring(f.getType().toString().lastIndexOf(".")+1))){ resultOfEntity.add(rs.getDate(f.getName().toString())); } else{ resultOfEntity.add(rs.getString(f.getName().toString())); } } } // rs.next()为真,则有记录,将每一条记录都反射封装成对象,装入结果集 result.add(reflectToCreateEntity(className,resultOfEntity)); } object=result; } else{ n=ps.executeUpdate(); if(n>0){ object=true; } else{ object=false; } } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } finally{ if(rs!=null){ JdbcConnection.close(con, ps, rs); } else if(ps!=null){ JdbcConnection.close(con, ps); } else{ JdbcConnection.close(con); } } return object; } /** * 这个方法用于执行完数据库操作之后,封装所取出来的字段成为对象。 * 参数需求为className和resultOfEntity,其中resultOfEntity表示对象所有的字段的值,其顺序必须与数据库字段顺序一样,这一点在建表时先做好。 * 通过反射获取所有set方法,然后执行,最后获得该对象实体。 * 此处细节尤为重要,因为序列化的问题,导致反射获取field时,会获取到serialVersionUID,找不到匹配的方法,所以进行下一次循环 * 所以,i=1,但是,此时找到的却是第一个需要执行set方法的field,而i=1,则取出来的是resultOfEntity.get(1),错位了,所以需要减一 * @param className * @param resultOfEntity * @return */ public Object reflectToCreateEntity(String className,ArrayList<Object> resultOfEntity){ Object o=null; try { Class<?> clazz=Class.forName(className); Object entity=clazz.newInstance(); Field[] fields=clazz.getDeclaredFields(); Method[] methods=clazz.getDeclaredMethods(); for(int i=0;i<fields.length;i++){ if(!"serialVersionUID".equals(fields[i].getName().toString())){ for(int j=0;j<methods.length;j++){ if(("set"+fields[i].getName().toString()).equalsIgnoreCase(methods[j].getName().toString())){ //此处尤为重要,因为序列化的问题,导致反射获取field时,会获取到serialVersionUID,找不到匹配的方法,所以进行下一次循环 //所以,i=1,但是,此时找到的却是第一个需要执行set方法的field,而i=1,则取出来的是resultOfEntity.get(1),错位了,所以需要减一 methods[j].invoke(entity,resultOfEntity.get(i-1)); // if("Integer".equalsIgnoreCase(fields[i].getType().toString().substring(fields[i].getType().toString().lastIndexOf(".")+1))){ // methods[j].invoke(entity,Integer.valueOf((String)resultOfEntity.get(i-1))); // } // else{ // methods[j].invoke(entity,String.valueOf(resultOfEntity.get(i-1))); // } } } } } o=entity; } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } return o; } /** * 这个方法通过className sql entity来实现获取sql语句中的列名以及列名的值,然后返回供PreparedStatement操作ps.setString,ps.setInt等等方法。 * 具体实现细节为:先解析sql,获取其中的列名,然后存入columnList,接着通过反射获取entity内部的所有get方法,如果与列名匹配,则获得该方法的 * 返回值和执行结果,其中方法的返回值决定ps.setString ,ps.setInt,ps.setDouble等等。 * 由于insert语句较为特殊,所以获取方法有所不同,故首先做了一个判断 * @param className * @param sql * @param entity * @return */ public Map<String,Object> reflectForParameters(String className,String sql,Object entity){ Map<String,Object> map=new HashMap<String,Object>(); ArrayList<String> columnList=new ArrayList<String>(); ArrayList<Object> parameterList=new ArrayList<Object>(); ArrayList<String> returnTypeList=new ArrayList<String>(); if(sql.trim().startsWith("insert")){ int begin=sql.indexOf("("); int over=sql.indexOf(")"); String columns=sql.substring(begin+1,over); String[] array=columns.split(","); for(int i=0;i<array.length;i++){ columnList.add(array[i]); } } //sql的分解是根据空格,所以对sql语句有要求,逗号之间要写空格 else{ String[] array=sql.split(" "); for(int i=0;i<array.length;i++){ if(array[i].endsWith("=?")){ columnList.add(array[i].substring(0,array[i].indexOf("=?"))); } } } try { Class<?> clazz=Class.forName(className); Method[] methods=clazz.getDeclaredMethods(); for(int i=0;i<columnList.size();i++){ for(Method m:methods){ if(("get"+columnList.get(i)).equalsIgnoreCase(m.getName())){ returnTypeList.add((m.getReturnType().toString()).substring(m.getReturnType().toString().lastIndexOf(".")+1)); parameterList.add(m.invoke(entity)); } } } map.put("column", columnList); map.put("parameter", parameterList); map.put("returnType", returnTypeList); return map; } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } return null; } }
相关文章推荐
- java对世界各个时区(TimeZone)的通用转换处理方法(转载)
- java-注解annotation
- java-模拟tomcat服务器
- java-用HttpURLConnection发送Http请求.
- java-WEB中的监听器Lisener
- Android IPC进程间通讯机制
- Android之获取手机上的图片和视频缩略图thumbnails
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- 介绍一款信息管理系统的开源框架---jeecg
- 聚类算法之kmeans算法java版本
- java实现 PageRank算法
- PropertyChangeListener简单理解
- SQL中的三值逻辑
- c++11 + SDL2 + ffmpeg +OpenAL + java = Android播放器
- 插入排序
- 冒泡排序