zoukankan      html  css  js  c++  java
  • 实现自己的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); } } }
  • 相关阅读:
    MySql插不进中文,以及IDEA连接MySql出现小段乱码问题
    安装Consul环境并启动
    格式化日期,首字母大写
    设计模式
    用户刷新页面,中止客户端面请求,怎么判断服务端也取消请求
    Token使用
    IdentityServer4搭建和使用
    Filter 过滤器
    添加Filter 并控制它的执行顺序
    在startup 添加数据库链接字符串
  • 原文地址:https://www.cnblogs.com/pokid/p/5823695.html
Copyright © 2011-2022 走看看