简单通用JDBC辅助类封装(实例)
哎,最近很好久没写点东西了,由于工作的原因,接触公司自己研发的底层orm框架,偶然发现该框架在调用jdbc操作的时候参考的是hibernate里面的SimpleJdbcTemplate,这里我想到了在大学的时候自己用过的一个简单的jdbc封装,现在我将代码贴出来,和大家一起分享:
Config类:读取同一包下的数据库连接配置文件,这样是为了更好的通用性考虑
packagecom.tly.dbutil; importjava.io.IOException; importjava.util.Properties; publicclassConfig{ privatestaticPropertiesprop=newProperties(); static{ try{ //加载dbconfig.properties配置文件 prop.load(Config.class.getResourceAsStream("dbconfig.properties")); }catch(IOExceptione){ //TODOAuto-generatedcatchblock e.printStackTrace(); } } //设置常量 publicstaticfinalStringCLASS_NAME=prop.getProperty("CLASS_NAME"); publicstaticfinalStringDATABASE_URL=prop.getProperty("DATABASE_URL"); publicstaticfinalStringSERVER_IP=prop.getProperty("SERVER_IP"); publicstaticfinalStringSERVER_PORT=prop.getProperty("SERVER_PORT"); publicstaticfinalStringDATABASE_SID=prop.getProperty("DATABASE_SID"); publicstaticfinalStringUSERNAME=prop.getProperty("USERNAME"); publicstaticfinalStringPASSWORD=prop.getProperty("PASSWORD"); }
dbconfig.properties:数据库配置文件,你也可以用xml格式等,注意Config类里面该文件的调用位置
CLASS_NAME=com.mysql.jdbc.Driver DATABASE_URL=jdbc:mysql SERVER_IP=localhost SERVER_PORT=3306 DATABASE_SID=employees USERNAME=root PASSWORD=1
接下来就是数据库连接辅助类DBConn了
packagecom.employees.dbutil; importjava.sql.Connection; importjava.sql.DriverManager; importjava.sql.PreparedStatement; importjava.sql.ResultSet; importjava.sql.SQLException; publicclassDBConn{ //三属性、四方法 //三大核心接口 privateConnectionconn=null; privatePreparedStatementpstmt=null; privateResultSetrs=null; //四个方法 //method1:创建数据库的连接 publicConnectiongetConntion(){ try{ //1:加载连接驱动,Java反射原理 Class.forName(Config.CLASS_NAME); //2:创建Connection接口对象,用于获取MySQL数据库的连接对象。三个参数:url连接字符串账号密码 Stringurl=Config.DATABASE_URL+"://"+Config.SERVER_IP+":"+Config.SERVER_PORT+"/"+Config.DATABASE_SID; conn=DriverManager.getConnection(url,Config.USERNAME,Config.PASSWORD); }catch(ClassNotFoundExceptione){ e.printStackTrace(); }catch(SQLExceptione){ e.printStackTrace(); } returnconn; } //method2:关闭数据库的方法 publicvoidcloseConn(){ if(rs!=null){ try{ rs.close(); }catch(SQLExceptione){ e.printStackTrace(); } } if(pstmt!=null){ try{ pstmt.close(); }catch(SQLExceptione){ e.printStackTrace(); } } if(conn!=null){ try{ conn.close(); }catch(SQLExceptione){ e.printStackTrace(); } } } //method3:专门用于发送增删改语句的方法 publicintexecOther(PreparedStatementpstmt){ try{ //1、使用Statement对象发送SQL语句 intaffectedRows=pstmt.executeUpdate(); //2、返回结果 returnaffectedRows; }catch(SQLExceptione){ e.printStackTrace(); return-1; } } //method4:专门用于发送查询语句 publicResultSetexecQuery(PreparedStatementpstmt){ try{ //1、使用Statement对象发送SQL语句 rs=pstmt.executeQuery(); //2、返回结果 returnrs; }catch(SQLExceptione){ e.printStackTrace(); returnnull; } } }
平时的用上面的代码能够解决一些简单的CRUD的应用了,但是还有很多限制,比如每次程序拿连接都要new,这样就给系统加大了负担,没有事务,没有dataSource等等,今天看见一哥们在园里面写的一篇用反射解决直接以对象参数的方式CRUD,这个我以前也写过,没写完,主要是自己想写一个通用的DButil,最后研究来研究去,发现越来越和hibernate里面的simpleJdbcTemplate接近了,所以就直接去看hibernate的源码了,加上那段时间有些事,没有时间,就将这件事闲置起来了,现在把这个东西补上,也给自己回顾一下下
BaseDao类
packagecom.employees.dao; importjava.io.InputStream; importjava.lang.reflect.Method; importjava.lang.reflect.ParameterizedType; importjava.sql.Connection; importjava.sql.Date; importjava.sql.PreparedStatement; importjava.sql.ResultSet; importjava.util.ArrayList; importjava.util.Iterator; importjava.util.List; importcom.employees.dbutil.DBConn; publicclassBaseDAO<T>{ DBConnconn=newDBConn(); privateConnectionconnection=null; @SuppressWarnings("unused") privateClass<T>persistentClass; @SuppressWarnings("unchecked") publicBaseDAO(){ initConnection(); //获得参数化类型 ParameterizedTypetype=(ParameterizedType)getClass().getGenericSuperclass(); persistentClass=(Class<T>)type.getActualTypeArguments()[0]; } /** *获得数据库连接 */ publicvoidinitConnection(){ connection=conn.getConntion(); } /** *保存 */ publicvoidsave(Tentity)throwsException{ //SQL语句,insertintotablename( Stringsql="insertinto"+entity.getClass().getSimpleName().toLowerCase()+"("; //获得带有字符串get的所有方法的对象 List<Method>list=this.matchPojoMethods(entity,"get"); Iterator<Method>iter=list.iterator(); //拼接字段顺序insertintotablename(id,name,email, while(iter.hasNext()){ Methodmethod=iter.next(); sql+=method.getName().substring(3).toLowerCase()+","; } //去掉最后一个,符号insertinsertintotablename(id,name,email)values( sql=sql.substring(0,sql.lastIndexOf(","))+")values("; //拼装预编译SQL语句insertinsertintotablename(id,name,email)values(?,?,?, for(intj=0;j<list.size();j++){ sql+="?,"; } //去掉SQL语句最后一个,符号insertinsertintotablename(id,name,email)values(?,?,?); sql=sql.substring(0,sql.lastIndexOf(","))+")"; //到此SQL语句拼接完成,打印SQL语句 System.out.println(sql); //获得预编译对象的引用 PreparedStatementstatement=connection.prepareStatement(sql); inti=0; //把指向迭代器最后一行的指针移到第一行. iter=list.iterator(); while(iter.hasNext()){ Methodmethod=iter.next(); //此初判断返回值的类型,因为存入数据库时有的字段值格式需要改变,比如String,SQL语句是'"+abc+"' if(method.getReturnType().getSimpleName().indexOf("String")!=-1){ statement.setString(++i,this.getString(method,entity)); }elseif(method.getReturnType().getSimpleName().indexOf("Date")!=-1){ statement.setDate(++i,this.getDate(method,entity)); }elseif(method.getReturnType().getSimpleName().indexOf("InputStream")!=-1){ statement.setAsciiStream(++i,this.getBlob(method,entity),1440); }else{ statement.setInt(++i,this.getInt(method,entity)); } } //执行 conn.execOther(statement); //关闭连接 conn.closeConn(); } /** *修改 */ publicvoidupdate(Tentity)throwsException{ Stringsql="update"+entity.getClass().getSimpleName().toLowerCase()+"set"; //获得该类所有get方法对象集合 List<Method>list=this.matchPojoMethods(entity,"get"); //临时Method对象,负责迭代时装method对象. MethodtempMethod=null; //由于修改时不需要修改ID,所以按顺序加参数则应该把Id移到最后. MethodidMethod=null; Iterator<Method>iter=list.iterator(); while(iter.hasNext()){ tempMethod=iter.next(); //如果方法名中带有ID字符串并且长度为2,则视为ID. if(tempMethod.getName().lastIndexOf("Id")!=-1&&tempMethod.getName().substring(3).length()==2){ //把ID字段的对象存放到一个变量中,然后在集合中删掉. idMethod=tempMethod; iter.remove(); //如果方法名去掉set/get字符串以后与pojo+"id"想符合(大小写不敏感),则视为ID }elseif((entity.getClass().getSimpleName()+"Id").equalsIgnoreCase(tempMethod.getName().substring(3))){ idMethod=tempMethod; iter.remove(); } } //把迭代指针移到第一位 iter=list.iterator(); while(iter.hasNext()){ tempMethod=iter.next(); sql+=tempMethod.getName().substring(3).toLowerCase()+"=?,"; } //去掉最后一个,符号 sql=sql.substring(0,sql.lastIndexOf(",")); //添加条件 sql+="where"+idMethod.getName().substring(3).toLowerCase()+"=?"; //SQL拼接完成,打印SQL语句 System.out.println(sql); PreparedStatementstatement=this.connection.prepareStatement(sql); inti=0; iter=list.iterator(); while(iter.hasNext()){ Methodmethod=iter.next(); //此初判断返回值的类型,因为存入数据库时有的字段值格式需要改变,比如String,SQL语句是'"+abc+"' if(method.getReturnType().getSimpleName().indexOf("String")!=-1){ statement.setString(++i,this.getString(method,entity)); }elseif(method.getReturnType().getSimpleName().indexOf("Date")!=-1){ statement.setDate(++i,this.getDate(method,entity)); }elseif(method.getReturnType().getSimpleName().indexOf("InputStream")!=-1){ statement.setAsciiStream(++i,this.getBlob(method,entity),1440); }else{ statement.setInt(++i,this.getInt(method,entity)); } } //为Id字段添加值 if(idMethod.getReturnType().getSimpleName().indexOf("String")!=-1){ statement.setString(++i,this.getString(idMethod,entity)); }else{ statement.setInt(++i,this.getInt(idMethod,entity)); } //执行SQL语句 statement.executeUpdate(); //关闭预编译对象 statement.close(); //关闭连接 connection.close(); } /** *删除 */ publicvoiddelete(Tentity)throwsException{ Stringsql="deletefrom"+entity.getClass().getSimpleName().toLowerCase()+"where"; //存放字符串为"id"的字段对象 MethodidMethod=null; //取得字符串为"id"的字段对象 List<Method>list=this.matchPojoMethods(entity,"get"); Iterator<Method>iter=list.iterator(); while(iter.hasNext()){ MethodtempMethod=iter.next(); //如果方法名中带有ID字符串并且长度为2,则视为ID. if(tempMethod.getName().lastIndexOf("Id")!=-1&&tempMethod.getName().substring(3).length()==2){ //把ID字段的对象存放到一个变量中,然后在集合中删掉. idMethod=tempMethod; iter.remove(); //如果方法名去掉set/get字符串以后与pojo+"id"想符合(大小写不敏感),则视为ID }elseif((entity.getClass().getSimpleName()+"Id").equalsIgnoreCase(tempMethod.getName().substring(3))){ idMethod=tempMethod; iter.remove(); } } sql+=idMethod.getName().substring(3).toLowerCase()+"=?"; PreparedStatementstatement=this.connection.prepareStatement(sql); //为Id字段添加值 inti=0; if(idMethod.getReturnType().getSimpleName().indexOf("String")!=-1){ statement.setString(++i,this.getString(idMethod,entity)); }else{ statement.setInt(++i,this.getInt(idMethod,entity)); } //执行 conn.execOther(statement); //关闭连接 conn.closeConn(); } /** *通过ID查询 */ publicTfindById(Objectobject)throwsException{ Stringsql="select*from"+persistentClass.getSimpleName().toLowerCase()+"where"; //通过子类的构造函数,获得参数化类型的具体类型.比如BaseDAO<T>也就是获得T的具体类型 Tentity=persistentClass.newInstance(); //存放Pojo(或被操作表)主键的方法对象 MethodidMethod=null; List<Method>list=this.matchPojoMethods(entity,"set"); Iterator<Method>iter=list.iterator(); //过滤取得Method对象 while(iter.hasNext()){ MethodtempMethod=iter.next(); if(tempMethod.getName().indexOf("Id")!=-1&&tempMethod.getName().substring(3).length()==2){ idMethod=tempMethod; }elseif((entity.getClass().getSimpleName()+"Id").equalsIgnoreCase(tempMethod.getName().substring(3))){ idMethod=tempMethod; } } //第一个字母转为小写 sql+=idMethod.getName().substring(3,4).toLowerCase()+idMethod.getName().substring(4)+"=?"; //封装语句完毕,打印sql语句 System.out.println(sql); //获得连接 PreparedStatementstatement=this.connection.prepareStatement(sql); //判断id的类型 if(objectinstanceofInteger){ statement.setInt(1,(Integer)object); }elseif(objectinstanceofString){ statement.setString(1,(String)object); } //执行sql,取得查询结果集. ResultSetrs=conn.execQuery(statement); //记数器,记录循环到第几个字段 inti=0; //把指针指向迭代器第一行 iter=list.iterator(); //封装 while(rs.next()){ while(iter.hasNext()){ Methodmethod=iter.next(); if(method.getParameterTypes()[0].getSimpleName().indexOf("String")!=-1){ //由于list集合中,method对象取出的方法顺序与数据库字段顺序不一致(比如:list的第一个方法是setDate,而数据库按顺序取的是"123"值) //所以数据库字段采用名字对应的方式取. this.setString(method,entity,rs.getString(method.getName().substring(3).toLowerCase())); }elseif(method.getParameterTypes()[0].getSimpleName().indexOf("Date")!=-1){ this.setDate(method,entity,rs.getDate(method.getName().substring(3).toLowerCase())); }elseif(method.getParameterTypes()[0].getSimpleName().indexOf("InputStream")!=-1){ this.setBlob(method,entity,rs.getBlob(method.getName().substring(3).toLowerCase()).getBinaryStream()); }else{ this.setInt(method,entity,rs.getInt(method.getName().substring(3).toLowerCase())); } } } //关闭结果集 rs.close(); //关闭预编译对象 statement.close(); returnentity; } /** *过滤当前Pojo类所有带传入字符串的Method对象,返回List集合. */ privateList<Method>matchPojoMethods(Tentity,StringmethodName){ //获得当前Pojo所有方法对象 Method[]methods=entity.getClass().getDeclaredMethods(); //List容器存放所有带get字符串的Method对象 List<Method>list=newArrayList<Method>(); //过滤当前Pojo类所有带get字符串的Method对象,存入List容器 for(intindex=0;index<methods.length;index++){ if(methods[index].getName().indexOf(methodName)!=-1){ list.add(methods[index]); } } returnlist; } /** *方法返回类型为int或Integer类型时,返回的SQL语句值.对应get */ publicIntegergetInt(Methodmethod,Tentity)throwsException{ return(Integer)method.invoke(entity,newObject[]{}); } /** *方法返回类型为String时,返回的SQL语句拼装值.比如'abc',对应get */ publicStringgetString(Methodmethod,Tentity)throwsException{ return(String)method.invoke(entity,newObject[]{}); } /** *方法返回类型为Blob时,返回的SQL语句拼装值.对应get */ publicInputStreamgetBlob(Methodmethod,Tentity)throwsException{ return(InputStream)method.invoke(entity,newObject[]{}); } /** *方法返回类型为Date时,返回的SQL语句拼装值,对应get */ publicDategetDate(Methodmethod,Tentity)throwsException{ return(Date)method.invoke(entity,newObject[]{}); } /** *参数类型为Integer或int时,为entity字段设置参数,对应set */ publicIntegersetInt(Methodmethod,Tentity,Integerarg)throwsException{ return(Integer)method.invoke(entity,newObject[]{arg}); } /** *参数类型为String时,为entity字段设置参数,对应set */ publicStringsetString(Methodmethod,Tentity,Stringarg)throwsException{ return(String)method.invoke(entity,newObject[]{arg}); } /** *参数类型为InputStream时,为entity字段设置参数,对应set */ publicInputStreamsetBlob(Methodmethod,Tentity,InputStreamarg)throwsException{ return(InputStream)method.invoke(entity,newObject[]{arg}); } /** *参数类型为Date时,为entity字段设置参数,对应set */ publicDatesetDate(Methodmethod,Tentity,Datearg)throwsException{ return(Date)method.invoke(entity,newObject[]{arg}); } }
EmployeesDao继承BaseDAO,可以直接使用父类的方法,增加了代码的复用
packagecom.employees.dao; importjava.util.ArrayList; importjava.util.List; importcom.employees.po.Employees; publicclassEmployeesDaoextendsBaseDAO<Employees>{ //添加员工信息的操作 publicbooleanaddEmployees(finalEmployeesemployees)throwsException{ save(employees); returntrue; } //将员工信息添加到表格中 publicList<Employees>addEmployees(intid)throwsException{ List<Employees>lstEmployees=newArrayList<Employees>(); Employeesemployees=findById(id); //将当前封转好的数据装入对象中 lstEmployees.add(employees); returnlstEmployees; } publicvoiddeleteEmp(finalEmployeesentity)throwsException{ this.delete(entity); } publicvoidupdateEmp(finalEmployeesentity)throwsException{ this.update(entity); } }
po层的代码就不贴了,现在用junit4做一下测试
packagecom.employees.dao; importorg.junit.Test; importcom.employees.po.Employees; publicclassEmployeesDaoTest{ @Test publicvoidtestAdd()throwsException{ Employeesemp=newEmployees(); emp.setPname("tly"); emp.setPsex("男"); emp.setPbeliefs("xxxxx"); emp.setPaddr("天河"); emp.setPhobby("打篮球"); emp.setPsubject("计算机"); emp.setPtel("123456"); EmployeesDaodao=newEmployeesDao(); dao.addEmployees(emp); } @Test publicvoidtestUpdate()throwsException{ EmployeesDaodao=newEmployeesDao(); Employeesemp=dao.findById(14); emp.setPtel("999999"); dao.updateEmp(emp); } @Test publicvoidtestdelete()throwsException{ EmployeesDaodao=newEmployeesDao(); Employeesemp=dao.findById(15); dao.deleteEmp(emp); } }
经过测试,这三个方法都能正常运行,时间仓促,有些代码是参考其他哥们的,有些地方可能考虑的不是很全面或者有些代码会有冗余,BaseDAO中做通用crud操作没有写全,要是哪位小伙伴有兴趣,可以接下去写写,比如查询,批量化操作等等,如果测试通过的话,记得给我发一份啊,呵呵
以上这篇简单通用JDBC辅助类封装(实例)就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持毛票票。