实现自己的JDBC框架
使用JDBC操作数据库时,dao层的增删改查有很多重复的代码,比如下面的
public int getTotal() { Connection conn = null;//通用代码 PreparedStatement ps = null;//通用代码 ResultSet rs = null;//通用代码 try { conn = ...//获取连接//通用代码 ps = conn.prepareStatement("select count(*) from blog");//只有sql语句不同 rs = ps.executeQuery(); if (rs.next()) { return rs.getInt(1); } } catch (SQLException e) { e.printStackTrace(); } finally { try { rs.close();//通用代码 ps.close();//通用代码 conn.close();//通用代码 } catch (SQLException e) { e.printStackTrace(); } } return 0; }
如果做一个简单的增删改查,会发现很多代码都是通用的,如果重复使用无疑会让代码显得很冗余
如果使用框架开发,框架会帮我们省去这些麻烦,或者有很多开源的工具类也可以比如apache的DBUtil工具类
不过看了黑马的教学视频,感觉完全可以自定义一个JDBC框架来帮我们省去很多麻烦(虽然我是造轮子,不过学习初期造轮子还是很有帮助的)
自定义JDBC框架
对于增删改里面重复的代码最多,且不包含结果集(查询包含的结果集需要封装,所以单独定义),用update方法统一代表增删改,query方法代表查询
对于过程,我们发现用JDBC增删改查里面只有sql语句不一样,sql语句里的占位符又会不一样,所以考虑自定义方法里传入参数包含sql语句和sql语句中需要传入的参数(用数组表示),对于查询由于需要封装结果集到Bean中,但是Bean类实现不知道,所以无法直接封装,考虑使用策略模式
下面直接上代码,具体解释留在注释中
由于使用了DBCP数据源,所以用的DBCP数据源获取数据库连接,这里就不上DBCP的代码了
主类DBAssist
public class DBAssist { //设置连接从数据源获取
//也可以不使用数据源,自己随便定义个Connection连接 private DataSource ds; public DBAssist(DataSource ds){ this.ds=ds; } //增删改 public void update(String sql,Object[] params){ Connection conn=null; PreparedStatement ps=null; ResultSet rs=null; try{ conn=ds.getConnection();//得到链接 ps=conn.prepareStatement(sql); //设置参数, //ParameterMetaData方法获取参数信息 ParameterMetaData pmd=ps.getParameterMetaData(); //获取sql语句中的占位符?个数 int parameterCount=pmd.getParameterCount(); //获取的参数个数与传入的参数个数比较 if(parameterCount>0){ if(params==null||params.length<1) throw new IllegalArgumentException("the parameter is wrong"); if(params.length!=parameterCount) throw new IllegalArgumentException("the parameter is wrong"); for(int i=0;i<parameterCount;i++){ ps.setObject(i+1, params[i]); } } ps.executeUpdate(); }catch(Exception e){ throw new DBAssistException(e); }finally{ release(conn,ps,rs); } } //查询,由于不知道具体的Bean类,考虑使用策略模式 //ResultSetHandler为抽象出的策略接口,策略类需继承该类以完成封装 //策略类框架会给出实现 public Object query(String sql,Object[] params,ResultSetHandler rsh){ Connection conn=null; PreparedStatement ps=null; ResultSet rs=null; try{ conn=ds.getConnection(); ps=conn.prepareStatement(sql); ParameterMetaData pmd=ps.getParameterMetaData(); int parameterCount=pmd.getParameterCount();//sql语句中的占位符个数 if(parameterCount>0){ if(params==null||params.length<1) throw new IllegalArgumentException("the parameter is wrong"); if(params.length!=parameterCount) throw new IllegalArgumentException("the parameter is wrong"); for(int i=0;i<parameterCount;i++){ ps.setObject(i+1, params[i]); } } //得到查询结果集 rs=ps.executeQuery(); //封装结果集到对象中去,这里使用策略模式,最好提供实现类(类似于注册器) return rsh.handler(rs); }catch(Exception e){ throw new DBAssistException(e); }finally{ release(conn,ps,rs); } } //关闭连接 private void release(Connection conn,Statement stmt,ResultSet rs){ if(rs!=null){ try { rs.close(); } catch (SQLException e) { e.printStackTrace(); } rs=null; } if(stmt!=null){ try { stmt.close(); } catch (SQLException e) { e.printStackTrace(); } stmt=null; } if(conn!=null){ try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } conn=null; } } }
此时已经可以用update方法进行增删改的功能了
对于查询,query方法中的策略接口代码如下
public interface ResultSetHandler { public Object handler(ResultSet rs); }
具体策略类有两个,分别用来查询单行和查询多行(利用反射填充Bean中的字段)
public class BeanHandler implements ResultSetHandler { private Class<? extends Object> clazz; public BeanListHandler(Class<? extends Object> clazz) { this.clazz = clazz; } public List<Object> handler(ResultSet rs) { try { List<Object> list = new ArrayList<Object>(); while (rs.next()) { Object bean = clazz.newInstance();
//查询数据库中的元数据信息 ResultSetMetaData rsmd = rs.getMetaData(); int count = rsmd.getColumnCount(); for (int i = 0; i < count; i++) { String columnName = rsmd.getColumnName(i + 1); Object columnValue = rs.getObject(i + 1); Field field = clazz.getDeclaredField(columnName); field.setAccessible(true); field.set(bean, columnValue); } list.add(bean); } return list; } catch (Exception e) { e.printStackTrace(); } return null; } }
)
//bean中字段名必须与数据库中字段名一致 public class BeanListHandler implements ResultSetHandler { private Class<? extends Object> clazz; public BeanHandler(Class<? extends Object> clazz) { this.clazz=clazz; } //查询单记录 public Object handler(ResultSet rs) { try { Object bean=clazz.newInstance(); if(rs.next()){
ResultSetMetaData rsmd=rs.getMetaData(); int count=rsmd.getColumnCount(); for(int i=0;i<count;i++){ String columnName=rsmd.getColumnName(i+1); Object columnValue=rs.getObject(i+1); Field field=clazz.getDeclaredField(columnName); field.setAccessible(true); field.set(bean,columnValue); } return bean; } } catch (Exception e) { e.printStackTrace(); } return null; } }
Bean类
public class Blog { private int id; private int category_id; private String title; private String content; private Date created_time;
...
//getter和setter方法 @Override public String toString() { return "Blog [id=" + id + ", category_id=" + category_id + ", title=" + title + ", content=" + content + ", created_time=" + created_time + "]"; } }
自定义异常类
public class DBAssistException extends RuntimeException { public DBAssistException() { } public DBAssistException(String message) { super(message); } public DBAssistException(Throwable cause) { super(cause); } public DBAssistException(String message, Throwable cause) { super(message, cause); } public DBAssistException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { super(message, cause, enableSuppression, writableStackTrace); } }
最后测试下
public void update(){ String sql="update blog set created_time=? where id=?"; dba.update(sql, new Object[]{new Date(System.currentTimeMillis()),1}); }
//查询单行记录测试 public void query(){ String sql="select * from blog"; Blog blog=(Blog) dba.query(sql, null,new BeanHandler(Blog.class)); System.out.println(blog.getTitle().length()); }
//查询多行记录测试 @SuppressWarnings("unchecked") public List<Blog> query2(){ String sql="select * from blog"; List<Blog> list=(List<Blog>) dba.query(sql, null,new BeanListHandler(Blog.class)); return list; } public static void main(String args[]) { BlogDao test = new BlogDao();System.out.println(test.update()); test.query(); List<Blog> list=test.query2(); for(Blog l:list){ System.out.println(l); } } }