zoukankan      html  css  js  c++  java
  • 实现简易JDBC框架

    1 准备

    •  JDBC 基本知识
    •    JDBC元数据知识
    •  反射基本知识

    2:  两个问题

    • 业务背景:系统中所有实体对象都涉及到基本的CRUD操作。所有实体的CUD操作代码基本相同,仅仅是发送给数据库的sql语句不同而已,因此可以把CUD操作的所有相同代码抽取到工具类的一个update方法中,并定义参数接收变化的sql语句。

    • 实体的R操作,除sql语句不同之外,根据操作的实体不同,对ResultSet的映射也各不相同,因此可定义一个query方法,除以参数形式接收变化的sql语句外,可以使用策略模式由query方法的调用者决定如何把ResultSet中的数据映射到实体对象中。

    3: JDBC 封装 update query方法

      

    public class JdbcNewUtils {
        private JdbcNewUtils() {}
        /**
         * 这里可以使用properties进行替换
         */
        private static final String USER = "root";
        private static final String PWD = "root";
        private static final String URL = "jdbc:mysql://127.0.0.1:3306/day?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC&generateSimpleParameterMetadata=true";
        private static final String DRIVER= "com.mysql.jdbc.Driver";
        static {
            try {
                Class.forName(DRIVER);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
        
        public static Connection  getConnection() throws SQLException {
            Connection connection = DriverManager.getConnection(URL, USER, PWD);
            return connection;
        }
        /**
         *  CUD 返回影响数目
         * @param sql
         * @param args
         * @return int
         */
        public static int  update(String sql,Object [] args) {
            PreparedStatement ps = null;
            Connection conn = null;
            try {
                conn=getConnection();
                ps = conn.prepareStatement(sql);
                for (int i = 1; i <= args.length; i++) {
                    ps.setObject(i, args[i-1]);
                }
                return ps.executeUpdate();
            } catch (SQLException e) {
                e.printStackTrace();
            }finally {
                close(conn, ps);
            }
            return 0;
        }
        /**
          *  查询结果封装Bean
         * @param sql
         * @param args
         * @param rsh
         * @return Object
         */
        public static Object  query(String sql,Object [] args,ResultSetHandler  rsh) {
            PreparedStatement ps = null;
            Connection conn = null;
            try {
                conn=getConnection();
                ps = conn.prepareStatement(sql);
                for (int i = 0; i < args.length; i++) {
                    ps.setObject(i+1, args[i]);
                }
                return rsh.handle(ps.executeQuery());
            } catch (SQLException e) {
                e.printStackTrace();
            }finally {
                close(conn, ps);
            }
            return null;
        }
        
        /**
        * 关闭所有打开的资源
        */
        public static void close(Connection conn, Statement stmt) {
            if(stmt!=null) {
                try {
                    stmt.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if(conn!=null) {
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
        /**
        * 关闭所有打开的资源
        */
        public static void close(Connection conn, Statement stmt, ResultSet rs) {
            if(rs!=null) {
                try {
                    rs.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            close(conn, stmt);
        }
    
    }

    4: query

     每次查询根据查询的参数不同, 返回的ResultSet 也不同, 这个规则我们需要单独编写规则解析器, 这里用到了策略设计模式,

    将ResultSetHandler 定义解决问题的接口, handle为那些需要实现的具体解决的办法

    public interface ResultSetHandler {
        Object handle(ResultSet resultSet);
    }

     下面我实现了Beanhandler 和 BeanListHandler 分别是 单个的Bean 和一个列表的Bean

    package jdbc.simpleframwork;
    
    import java.lang.reflect.Field;
    import java.sql.ResultSet;
    import java.sql.ResultSetMetaData;
    import java.sql.SQLException;
    
    public class BeanHandler implements ResultSetHandler {
    
        private Class<?> obj;
        public BeanHandler(Class<?> obj) {
            this.obj = obj;
        }
        @Override
        public Object handle(ResultSet resultSet){
            try {
                if(!resultSet.next()) {
                    return null;
                }
                Object instance = obj.newInstance();
                ResultSetMetaData metaData = resultSet.getMetaData();
                int count = metaData.getColumnCount();
                for(int i=1;i<=count;i++) {
                    Field f = obj.getDeclaredField(metaData.getColumnName(i));
                    f.setAccessible(true);
                    f.set(instance, resultSet.getObject(i));
                }
                return instance;
            } catch (InstantiationException | IllegalAccessException e) {
                e.printStackTrace();
            } catch (SQLException e) {
                e.printStackTrace();
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            } catch (SecurityException e) {
                e.printStackTrace();
            }
            return null;
        }
    
    }
    package jdbc.simpleframwork;
    
    import java.lang.reflect.Field;
    import java.sql.ResultSet;
    import java.sql.ResultSetMetaData;
    import java.util.ArrayList;
    
    public class BeanListHandler implements ResultSetHandler {
    
        private Class<?> clazz;
    
        public BeanListHandler(Class<?> clazz) {
            super();
            this.clazz = clazz;
        }
    
        @Override
        public Object handle(ResultSet resultSet) {
            try {
                ArrayList<Object> objlist = new ArrayList<>();
                ResultSetMetaData metaData = resultSet.getMetaData();
                int count = metaData.getColumnCount();
                while (resultSet.next()) {
                    Object instace = clazz.newInstance();
                    for (int i = 0; i < count; i++) {
                        Field f = clazz.getDeclaredField(metaData.getColumnName(i + 1));
                        f.setAccessible(true);
                        f.set(instace, resultSet.getObject(i + 1));
                        f.setAccessible(false);
                    }
                    objlist.add(instace);
    
                }
                return objlist;
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
    }

    5 测试

    public class TestFramwork {
    
        public static void main(String[] args) throws SQLException {
            Connection conn = JdbcNewUtils.getConnection();
    
            String sql = "select * from student where id=?";
            PreparedStatement ps = conn.prepareStatement(sql);
            Student stu = (Student) JdbcNewUtils.query(sql, new Object[] { 1 }, new BeanHandler(Student.class));
            System.out.println(stu);
    
            String sql2 = "select * from student";
            ArrayList<Student> list = (ArrayList<Student>) JdbcNewUtils.query(sql2, new Object[] {},
                    new BeanListHandler(Student.class));
            System.out.println(list);
        }
    
    }

    6: 总结:

    Update系列操作:

    •   对于CUD操作,SQL只有站位符号的多少发生了改变,对于传递参数才是我们需要关注的地方,但是JDBC提供了一系列传递参数解析的办法,通过set系列函数,将参数值传递进行,所以我们只需要封装一个通用的update即可

    Query系列操作

    •   对R操作,就复杂得多,SQL语句的不同,返回的ResultSet也不同,可以单个Bean 或者一个List,一个Map等,可以看出来,实际上很多框架提供的也就是这些方法的封装

    对了 真正应用上 我们的DAO 一边是 下面的写法

    public class AccountDao {
        public void add(Account account) throws SQLException{
            String sql = "insert into account(name , money) values(?, ?)";
            Object[] params = {account.getName(), account.getMoney()};
            JdbcUtils.update(sql, params);
        }
        
        public void delete(int id ) throws SQLException{
            String sql = "delete from account where id = ?";
            Object[] params = {id};
            JdbcUtils.update(sql, params);
        }
        
        public void update(Account account) throws SQLException{
            String sql = "update account set name = ?, money = ? where id = ?";
            Object params[] = {account.getName(), account.getMoney(), account.getId()};
            JdbcUtils.update(sql, params);
        }
        
        public Account find(int id ) throws SQLException{
            String sql = "select * from account where id = ?";
            Object params[] = {id};
            return (Account) JdbcUtils.query(sql, params, new BeanHandler(Account.class));
        }
        
        public List getAll() throws SQLException{
            String sql = "select * from account";
            Object params[] = {};
            return (List)JdbcUtils.query(sql, params, new BeanListHandler(Account.class));
        }
    }
  • 相关阅读:
    kvm
    docker及lvs负载
    zookeeper,及k8s基础概念
    zabbix-proxy及ELK
    gitlab及jenkins
    绘图 Matplotlib Numpy Pandas
    Elasticsearch
    Git命令小结
    win黑窗口命令
    Linux基础命令
  • 原文地址:https://www.cnblogs.com/dgwblog/p/11798147.html
Copyright © 2011-2022 走看看