JDBC进阶 + 数据源

本文介绍了如何对JDBC的查询操作进行重构,利用接口和父类实现通用的增删改查功能。通过反射和元数据,将结果集转化为对象属性。此外,文章还探讨了JDBC数据源的概念,解释了数据源如何管理和控制数据库连接,以及连接池的实现原理,其中代理模式起到了关键作用。

JDBC进阶

上回我们知道了,通过工厂模式+配置文件动态连接数据库;
这次的主要目的呢,则是将增删改查想办法重构掉;比如查询,到哪里的操作不都是一样的嘛;所以我们自然就想到了将查询操作重构掉;

然后我们思考一下类的组织,有这么一个接口,其中声明了增删改查,我们的类实现这个接口== 我们的类必须实现增删改查,不实现这些,你也叫数据库操作吗?然后我们要将这个类的增删改查的实际操作重构掉;这个类只需要知道该干什么,需要什么齐活;

首先是接口,实现类必须实现增删改查;

public interface UserDAO {
    public ArrayList<Users> findUsers();
    public boolean findUser(Users users);
    public int insertUser(Users users);
    public int update(Users users);
    public int delete(Users users);
}

我们的目标是这样的,只需要参数,和做什么;

public class UserDAOImp1 extends BaseDAO implements UserDAO {
    @Override
    public ArrayList<Users> findUsers() {
       String sql = "select userid Userid ,username Username,userage Userage," +
               "gender Gender,birthday Birthday,address Address  from users";
       return findObjs(sql,Users.class);
    }
        @Override
    public boolean findUser(Users user) {
        // TODO Auto-generated method stub
        return false;
    }

然后就是重点的重构过程了:其实就是增加了一个父类;

public class BaseDAO {
    public ArrayList findObjs(String sql , Class clazz)
    {
        Connection connection = null;
        PreparedStatement ps  = null;
        ResultSet rs = null;
        ArrayList objs = new ArrayList();
        try {
            connection = JDBCUtils.getConnection();
            ps = connection.prepareStatement(sql);
            System.out.println(sql);
            rs = ps.executeQuery();
            while(rs.next()){
                Object obj = mappingObj(rs,clazz);              //这里取结果集就厉害了;来什么取什么
                objs.add(obj);
            }
            JDBCUtils.free(rs, ps, connection);


        } catch (SQLException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return objs;
    }
    private Object mappingObj(ResultSet rs,Class clazz) throws SQLException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{
        //实例化映射对象
        Object obj = clazz.newInstance();
        //获取映射对象的方法
        Method[] methods = clazz.getMethods();
        //获取结果集中元数据信息
        ResultSetMetaData meta = rs.getMetaData();
        // 按字段数目循环结果集中记录,进行对象映射
        System.out.println(meta.getColumnCount());
        for(int i=1;i<=4;i++){
            // 构造当前列的set方法名称
            String colname = meta.getColumnLabel(i);
            String methodname = "set" + colname;
            System.out.println(methodname);
            // 循环查找同名方法,并通过反射调用该方法,设置属性
            for(Method method:methods){
                if(method.getName().equals(methodname)){
                    System.out.println(methodname+"find");
                    method.invoke(obj, rs.getObject(i));
                    break;
                }
            }

        }
        return obj;
    }
}

上面就是最重要的部分,反射+元数据;我们为什么重构,因为对任意一个表,查询操作是不是都只是将全部数据拿出来。然后放到结果集里;那我们将结果集抽象成对象,必然得set很多啊;比如这样:

  Users users = new Users();
               users.setUserid(resultSet.getInt(1));
               users.setUsername(resultSet.getString(2));
               users.setUserage(resultSet.getInt(3));
               users.setGender(resultSet.getInt(4));
               users.setBirthday(resultSet.getDate(5));
               users.setAddress(resultSet.getString(6));
               arrayList.add(users);

现在的情况是什么呢?
你给我你要将结果集放在什么对象里;我从结果集里看看元数据(我的数据长什么样,是不是符合要求);如果符合,如果搭配就初始化到对象中的属性去;而结果集是怎么来的,通过sql语句,sql语句怎么来的?你自己传进去的;
你可以怎么想呢?,你找了一个函数,然后告诉他:去那边找找有没有足球,然后放到这个足球框里;要求和对象都是你给的;这个函数当然也就可以做找篮球,放篮球框里;如果是更改的话,就是:“你找找有没有没气的皮球”,用这个皮球代替一下;

JDBC 数据源

其实这个也很好理解,就是连接是一种资源;在浏览网页的时候,和数据库建立的连接,要可以控制啊;就像A,B之间有5条路,每次一条路只能通过一个人;一旦有人走,就等于可用路线少了;反过来,如果这个人走完了,那么必然总路线有多了一个;
这里写图片描述

数据源要做什么呢? 首先来一个用户,是不是得申请一个连接,所以会有getConnection()方法;数据源有一大堆的连接,那么他们从哪里来的,一定得有创建的啊;还有就是数据源的数据结构,一大堆的数据结构,用的时候,就给一个,结束,就返回一个;所以建造了一个链表;

public class MyDataSource implements DataSource {
    private LinkedList<Connection> connPool = new LinkedList();
    private static String url ;
    private static String username ;
    private static String password ;
    /*
        创建Connection;
     */
    private Connection createConnection(){
        Properties prop = new Properties();
        InputStream in = this.getClass().getClassLoader()
            .getResourceAsStream("db.properties");
        try {
            prop.load(in);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        url = prop.getProperty("url");
        username = prop.getProperty("username");
        password = prop.getProperty("password");
        try {
            Class.forName(prop.getProperty("drivername"));
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        Connection realConn = null;
        try {
            realConn = DriverManager.getConnection(url,username,password);
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        Connection myConn = new MyConnection(realConn, this.connPool);
        return myConn;
    }

    /*
    获取一个connection,得到一个连接,
     */
    @Override
    public Connection getConnection(){
        if(this.connPool.size()>0){
            Connection conn = (Connection)this.connPool.removeFirst();
//          System.out.println(conn.toString());
            return  conn;
        }else{
            return createConnection();
        }
    }
    /*
    还有好多需要重写的方法;
    */
}

这里使用到了代理,一个连接,怎么也不应该结束连接的时候,还能放到连接池中吧;而很显然,这件事也不适合数据源去做;因为你可以创建连接,但是不能关闭连接,关闭连接是连接自己的行为;所以为了让连接和连接池发生关系,我们使用了代理;(不恰当的比喻)就像中介,既有我们的需求,又有市场的情况,所以就能调和两者;

public class MyConnection implements Connection {
    private Connection realConn;
    private LinkedList<Connection> connPool;
    public MyConnection(Connection rConn, LinkedList<Connection> cPool){
        this.realConn=rConn;
        this.connPool=cPool;
    }

    @Override
    public void clearWarnings() throws SQLException {
        // TODO Auto-generated method stub
        this.realConn.clearWarnings();

    }

    @Override
    public void close() throws SQLException {
        this.connPool.addLast(this);
//      System.out.println(realConn.toString());

    }

    @Override
    public void commit() throws SQLException {
        this.realConn.commit();

    }
    /*
    还有好多需要重写的方法;
    */
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值