写自己的JDBC框架
当我一开始接触对于java操作数据库的时候,使用的是JDBC框架(因为你不得不承认不是所有的项目都需要hibernate)。一开始的编程我都是没有任何的感觉的,因为对jdbc并不是非常的懂,慢慢的,随着Demo越来越多,我发现JDBC框架是繁琐并且枯燥的。不难发现,基本所有的Dem的DAO层对于数据库的操作都少不了(CRUD)。我开始想着,我们学的java思想不就是要对其公共的进行封装么?于是我开始试着去“偷懒”......
看着这些代码。我觉得可以将之分为两种类型:“改” 和 “查”。没错,基本所有的‘增’,‘删’,‘改’都有着很多的相似点,例如返回时void,唯一不同的就是sql语句,以及对于sql语句中的参数。所以,我将sql语句,以及sql语句中的操作值进行抽取,以参数的形式传给一个公共的方法。参数由于有多个,我将其存在一个数组中。作为一个编辑者,我们并不知道用户传进的是什么类型的值,所以我选取了Object类型的数组进行封装。
对于‘查’。其实有很多的原理类似于‘改’。唯一让我不同的是对于用户需要返回的是什么类型,我们作为设计者是无法得知的。或许很多人这个时候就开始不知所措。其实这个时候需要的是一种开发中的思想。对于我们无法知道的,我们可以给框架的调用者返回一个接口。因为用户肯定知道自己的需求是什么,在接口中暴露一个处理方法给用户自己去实现。所以在‘查’这个方法中我们需要用户传给我们的就是:sql语句,参数数组,一个如何去处理这个结果集的接口(如果接口没在以下说出,可以在开发中自己写一个接口实现)
对于这个接口(ResultSetHandler)的实现,我给大家封装了三个最常用的:返回一个bean对象(BeanHandler),返回一个封装所有bean的集合(ListBeanHandler),返回一个获取所有数据的数量的接口(IntResultSetHandler)。
当我写完这个自己整合过的JDBC后,虽然写的不是很全面。但是在Dao层上每一个‘增’,‘删’,‘改’方法我可以不超过4行代码。‘查’方法同样变得很整洁。(具体看代码)在数据库的资源释放,一个项目中对于数据库的如何更好的初始化一般操作都差不多了。
以下我已数据库连接池dbcp作为一个小Demo
为什么用数据库连接池获取链接以及如何用数据库连接池获取链接自己去百度详细了解咯~~~
代码:
1 package cn.itcast.utils; 2 3 import java.io.IOException; 4 import java.io.InputStream; 5 import java.sql.Connection; 6 import java.sql.PreparedStatement; 7 import java.sql.ResultSet; 8 import java.sql.SQLException; 9 import java.util.Properties; 10 11 import javax.sql.DataSource; 12 13 import org.apache.commons.dbcp.BasicDataSourceFactory; 14 15 public class JdbcUtils { 16 17 private static DataSource ds=null; 18 static { 19 try { 20 InputStream intput=JdbcUtils.class.getClassLoader().getResourceAsStream("dbcpconfig.properties"); 21 Properties pro=new Properties(); 22 pro.load(intput); 23 BasicDataSourceFactory factory=new BasicDataSourceFactor(); 24 ds=factory.createDataSource(pro); 25 } catch (Exception e) { 26 throw new ExceptionInInitializerError(e); 27 } 28 } 29 30 31 public static Connection getConnection() throws SQLException{ 32 return ds.getConnection(); 33 } 34 35 public static void realease(Connection conn,PreparedStatement ps,ResultSet rs){ 36 if(conn!=null){ 37 try { 38 conn.close(); 39 } catch (SQLException e) { 40 e.printStackTrace(); 41 } 42 conn=null; 43 } 44 45 if(ps!=null){ 46 try { 47 ps.close(); 48 } catch (SQLException e) { 49 e.printStackTrace(); 50 } 51 ps=null; 52 } 53 54 if(rs!=null){ 55 try { 56 rs.close(); 57 } catch (SQLException e) { 58 e.printStackTrace(); 59 } 60 rs=null; 61 } 62 } 63 64 //用于对数据的增,删 ,改 65 public void update(String sql,Object params[]) throws SQLException{ 66 Connection conn=null; 67 PreparedStatement ps=null; 68 ResultSet rs=null; 69 try{ 70 conn=getConnection(); 71 ps=conn.prepareStatement(sql); 72 for(int i=0;i<params.length;i++){ 73 ps.setObject(i+1, params[i]); 74 } 75 ps.executeUpdate(); 76 }finally{ 77 realease(conn, ps, rs); 78 } 79 } 80 81 //用于对数据的查找 82 public static Object query(String sql,Object params[],ResultSetHandler handler) throws SQLException{ 83 Connection conn=null; 84 PreparedStatement ps=null; 85 ResultSet rs=null; 86 try{ 87 conn=getConnection(); 88 ps=conn.prepareStatement(sql); 89 for(int i=0;i<params.length;i++){ 90 ps.setObject(i+1, params[i]); 91 } 92 rs=ps.executeQuery(); 93 //由于不知道对结果集的处理,这个地方就暴露一个接口,让使用者去调用。 94 return handler.handel(rs); 95 }finally{ 96 realease(conn, ps, rs); 97 } 98 } 99 100 }
以下是接口:
package cn.itcast.utils; import java.sql.ResultSet; //由于不知道对结果集的处理,这个地方就暴露一个接口,让使用者去调用。 public interface ResultSetHandler { public Object handel(ResultSet rs); }
以下是接口的实现类:
package cn.itcast.utils; import java.lang.reflect.Field; import java.sql.ResultSet; import java.sql.ResultSetMetaData; //再写一些具体的实现接口 public class BeanHandler implements ResultSetHandler { private Class clazz; //初始化的时候创建一个封装Bean的实体,可以通过实现类的构造函数的方法传人 public BeanHandler(Class clazz) { this.clazz=clazz; } @Override public Object handel(ResultSet rs) { try { if(!rs.next()){ return null; } //创建封装结果集的bean Object bean= clazz.newInstance(); //得到结果集的元数据,以获取结果集的信息 ResultSetMetaData meta=rs.getMetaData(); int count=meta.getColumnCount(); for(int i=0;i<count;i++){ //获取到结果集每列的列名 String name=meta.getColumnName(i+1); Object value=rs.getObject(name); //利用反射,反射出bean上与列名相应的属性,并将value直接反射到对应的属性上 Field f=bean.getClass().getField(name); //由于一般的bean的属性都是private的,所以要将其的强行解除 f.setAccessible(true); f.set(bean, value); } return bean; } catch (Exception e) { throw new RuntimeException(); } } }
package cn.itcast.utils; import java.lang.reflect.Field; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; public class ListBeanHandler implements ResultSetHandler { private Class clazz; public ListBeanHandler(Class clazz) { this.clazz=clazz; } @Override public Object handel(ResultSet rs) { List list=new ArrayList(); try { while(rs.next()){ Object bean=clazz.newInstance(); ResultSetMetaData meta=rs.getMetaData(); int count=meta.getColumnCount(); for(int i=0;i<count;i++){ String name=meta.getColumnName(i+1); Object value=rs.getObject(name); Field f=bean.getClass().getField(name); f.setAccessible(true); f.set(bean, value); } list.add(bean); } } catch (Exception e) { throw new RuntimeException(e); } return null; } }
package cn.itcast.utils; import java.sql.ResultSet; import java.sql.SQLException; //专门用于计算数据条数的 public class IntResultSetHandler implements ResultSetHandler { public Object handel(ResultSet rs) { try { if(rs.next()){ return rs.getInt(1); } } catch (Exception e) { throw new RuntimeException(e); } return 0; } }
以上就是封装后的代码。我们在增删查改的是只需要在对应的方法中传进相应的SQL语句还有所需的参数或者对应的接口实现类。
以下是我自己写的一个小Demo中的代码数量,分别为使用这种方法前DAO层的截图

使用这种方法后DAO层的截图


浙公网安备 33010602011771号