九、DBUtils的使用以及使用其编写通用的DAO

使用DBUtils提供的功能需要使用commons-dbutils-1.6.jar这个JAR包,在Apache官网可以下载到

使用DBUtils进行更新操

测试QueryRunner类的update方法 ,该方法可用于insert,update,delete操作
具体代码实现

@Test
    public void testQuertRunnerUpdate() {
        // 1.创建QueryRunner的实现类
        String sql = "delete from customers" + " where id in (?,?)";
        Connection connection = null;
        try {
            connection = JDBCTools.getConnection();
            queryRunner.update(connection, sql, 3, 4);

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCTools.release(null, null, connection);
        }
    }

我们可以查看一下update方法的源码,可以看到是调用的是重载形式的update:

conn:数据库连接

sql:SQL语句

params:填充占位符的参数

public int update(Connection conn, String sql, Object... params) throws SQLException {             
    return update(conn, false, sql, params);
}

看具体实现代码:

private int update(Connection conn, boolean closeConn, String sql, Object... params) throws SQLException {
        if (conn == null) {
            throw new SQLException("Null connection");
        }

        if (sql == null) {
            if (closeConn) {
                close(conn);
            }
            throw new SQLException("Null SQL statement");
        }
        //封装使用的是PreparedStatement
        PreparedStatement stmt = null;
        int rows = 0;

        try {
            stmt = this.prepareStatement(conn, sql);
           //填充占位符的操作
            this.fillStatement(stmt, params);
           //执行更新操作
            rows = stmt.executeUpdate();

        } catch (SQLException e) {
            this.rethrow(e, sql, params);

        } finally {
            close(stmt);
            if (closeConn) {
                close(conn);
            }
        }

        return rows;
    }

可以看到QueryRunner中封装的都是我们所熟悉的基本操作,测试我们的testQuertRunnerUpdate方法,可以发现对应id为3,4的记录已经被删除

测试QueryRunner的查询方法query

// 因为是线程安全的,所以queryRunner可以放到这个位置
    QueryRunner queryRunner = new QueryRunner();

    class MyResultSetHandler implements ResultSetHandler {

        @Override
        public Object handle(ResultSet resultSet) throws SQLException {
            List<Customer> customers = new ArrayList<Customer>();
            while (resultSet.next()) {
                int id = resultSet.getInt(1);
                String name = resultSet.getString(2);
                String email = resultSet.getString(3);
                Date birth = resultSet.getDate(4);
                Customer customer = new Customer(id, name, email, birth);
                customers.add(customer);
            }
            return customers;
        }

    }

    @Test
    public void testQuery() {
        QueryRunner queryRunner = new QueryRunner();
        Connection connection = null;
        try {
            connection = JDBCTools.getConnection();
            String sql = "select id,name,email,birth" + " from customers";
            Object obj = queryRunner.query(connection, sql,
                    new MyResultSetHandler());
            System.out.println(obj);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCTools.release(null, null, connection);
        }
    }

运行方法可以看到我们要查询的结果:

[Customer [id=1, name=ATGUIGU, email=simale@163.com, birth=2016-05-08], Customer [id=2, name=ABCDE, email=abcd@guigu.com, birth=2016-05-08], Customer [id=5, name=dsv, email=474405914@qq.com, birth=2016-05-10]]

我们查看一下query方法的源码

private <T> T query(Connection conn, boolean closeConn, String sql, ResultSetHandler<T> rsh, Object... params)
            throws SQLException {
        if (conn == null) {
            throw new SQLException("Null connection");
        }

        if (sql == null) {
            if (closeConn) {
                close(conn);
            }
            throw new SQLException("Null SQL statement");
        }

        if (rsh == null) {
            if (closeConn) {
                close(conn);
            }
            throw new SQLException("Null ResultSetHandler");
        }

        PreparedStatement stmt = null;
        ResultSet rs = null;
        T result = null;

        try {
            stmt = this.prepareStatement(conn, sql);
            this.fillStatement(stmt, params);
            rs = this.wrap(stmt.executeQuery());
            result = rsh.handle(rs);

        } catch (SQLException e) {
            this.rethrow(e, sql, params);

        } finally {
            try {
                close(rs);
            } finally {
                close(stmt);
                if (closeConn) {
                    close(conn);
                }
            }
        }

        return result;
    }

其中最关键的是这四个语句:

            stmt = this.prepareStatement(conn, sql);
            this.fillStatement(stmt, params);
            rs = this.wrap(stmt.executeQuery());
            result = rsh.handle(rs);
测试DBUtils工具类 QueryRunner:
 * query(Connection conn,String sql,ResultSetHandler rsh){ 
 * 这三个步骤就是为了得到结果集 
 * stmt = this.prepareStatement(conn, sql);
 * this.fillStatement(stmt, params);
 * rs = this.wrap(stmt.executeQuery());
 * 调用传入的ResultSetHandler对象的handle方法,并且把前面得到的ResultSet对象作为参数传入
 * result =rsh.handle(rs); 
 * 把result作为结果返回 
 * return result
 * }

测试BeanHandler的用法
BeanHandler:把结果集的第一条记录转为创建BeanHandler 对象时传入的Class参数对应的对象。

具体测试代码:

public void testBeanHandler() {
        Connection connection = null;
        try {
            connection = JDBCTools.getConnection();
            String sql = "select id,name,email,birth"
                    + " from customers where id=?";
            Customer customer = queryRunner.query(connection, sql,
                    new BeanHandler(Customer.class), 5);
            System.out.println(customer);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCTools.release(null, null, connection);
        }
    }

查看源码可以看到query函数中用到的handler函数实现的功能是这样的

1   @Override
2     public T handle(ResultSet rs) throws SQLException {
3         return rs.next() ? this.convert.toBean(rs, this.type) : null;
4     }

实现的功能是把结果集的第一条记录转为创建BeanHandler 对象时传入的Class参数对应的对象。

其中的toBean方法的实现方式:(多看源码吧,有点乱了)

public <T> T toBean(ResultSet rs, Class<T> type) throws SQLException {

        PropertyDescriptor[] props = this.propertyDescriptors(type);

        ResultSetMetaData rsmd = rs.getMetaData();
        int[] columnToProperty = this.mapColumnsToProperties(rsmd, props);

        return this.createBean(rs, type, props, columnToProperty);
    }

测试BeanListHandler的用法
和前面那个差不多,只不过将查询的结果放到了一个List容器中了

@Test
    public void testBeanListHandler() {
        Connection connection = null;
        try {
            connection = JDBCTools.getConnection();
            String sql = "select id,name,email,birth" + " from customers";
            List<Customer> customers = queryRunner.query(connection, sql,
                    new BeanListHandler(Customer.class));
            System.out.println(customers);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCTools.release(null, null, connection);
        }
    }

运行结果:

[Customer [id=1, name=ATGUIGU, email=simale@163.com, birth=2016-05-08], Customer [id=2, name=ABCDE, email=abcd@guigu.com, birth=2016-05-08], Customer [id=5, name=dsv, email=474405914@qq.com, birth=2016-05-10]]

测试MapHandler的用法

MapHandler:返回SQL对应的第一条记录对应的Map对象 键:SQL查询的列名(不是列别名) 值:列的值

@Test
    public void testMapHandler() {
        Connection connection = null;
        try {
            connection = JDBCTools.getConnection();
            String sql = "select id,name,email,birth" + " from customers";
            Map<String, Object> result = queryRunner.query(connection, sql,
                    new MapHandler());
            System.out.println(result);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCTools.release(null, null, connection);
        }
    }

运行结果:

{id=1, name=ATGUIGU, email=simale@163.com, birth=2016-05-08}

测试ScalarHandler的用法

ScalarHandle:把结果集转为一个数值(可以是任意基本数据类型和字符串,Date等)返回

@Test
    public void testScalarHandler() {
        Connection connection = null;
        try {
            connection = JDBCTools.getConnection();
            String sql = "select count(id) from customers";
            Object result = queryRunner.query(connection, sql,
                    new ScalarHandler());
            System.out.println(result);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCTools.release(null, null, connection);
        }
    }

运行结果:3

至此为止我们学习了JDBC中常用的一些知识点,下面我们就使用DBUtils编写通用的DAO(DAO其实就是封装了操作数据库数据的一些方法的接口)

使用DButils编写通用的DAO

第一步:先写一个访问数据的DAO接口

package com.atguigu.jdbc;

import java.sql.Connection;
import java.util.List;

/**
 * 访问数据的DAO接口
 * 里面定义好访问数据表的各种方法
 * @author Administrator
 * @param T:DAO处理的实体类的类型
 */
public interface DAO {
    /**
     * 批量处理的方法
     * @param connection
     * @param sql
     * @param args:填充占位符的Object[]类型的可变参数
     */
    void batch(Connection connection,
    String sql,Object[] ...args);
    /**
     * 返回一个具体的一个值,例如总人数,平均工资
     * 某一个认得email
     * @param connection
     * @param sql
     * @param args
     * @return
     */
    <E> E getForValue(Connection connection,
    String sql,    Object ...args);
    
    /**
     * 返回T的一个集合
     * @param <T>
     * @param connection
     * @param sql
     * @param args
     * @return
     */
    <T> List<T> getForList(Connection connection,
    String sql,Object ...args);
    /**
     * 返回一个T的对象
     * @param <T>
     * @param connection
     * @param sql
     * @param args 
     * @return
     * @throws Exception 
     */
    <T> T get(Connection connection,String sql,Object ...args) throws Exception;
    /**
     * 
     * @param connection:数据库连接
     * @param sql:SQL语句
     * @param args:填充占位符的可变参数
     */
    void update(Connection connection,String sql,Object ...args);
}

第二步:定义实现该接口的实例类JdbcDAOImpl

package com.atguigu.jdbc;

import java.sql.Connection;
import java.util.List;

import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;

/**
 * 使用QueryRunner提供其具体的实现
 * @author Administrator
 *
 * @param <T>:子类需传入的泛型类型
 */
public class JdbcDAOImpl<T> implements DAO {
    private QueryRunner queryRunner=null;
    private Class<T> type; 
    public  JdbcDAOImpl() {
        queryRunner=new QueryRunner();
        type= (Class<T>) ReflectionUtils.getGenericSuperClass(getClass(),0);
    }
    @Override
    public void batch(Connection connection, String sql, Object[]... args) {
    }

    @Override
    public <E> E getForValue(Connection connection, String sql, Object... args) {
        
        return null;
    }

    @Override
    public  List<T> getForList(Connection connection, String sql,
            Object... args) {
        
        return null;
    }

    @Override
    public  T get(Connection connection, String sql, Object... args) throws Exception {
        
        return  queryRunner.query(connection, sql,
        new BeanHandler<>(type),args);
    }

    @Override
    public void update(Connection connection, String sql, Object... args) {
    }

    
}

第三步:定义一个具体操作的类继承自JdbcDAOImpl

1 package com.atguigu.jdbc;
2 
3 public class CustomerDAO extends JdbcDAOImpl<Customer>{
4     
5 }

第四步:我们测试一下我们已经实现的get方法,其他的方法实现过程类似

package com.atguigu.jdbc;

import static org.junit.Assert.*;

import java.sql.Connection;

import org.junit.Test;

public class CustomerDaoTest {
    CustomerDAO customerDAO=new CustomerDAO();

    @Test
    public void testBatch() {
        fail("Not yet implemented");
    }

    @Test
    public void testGetForValue() {
        fail("Not yet implemented");
    }

    @Test
    public void testGetForList() {
        fail("Not yet implemented");
    }

    @Test
    public void testGet() {
        Connection connection=null;
        try {
            connection=JDBCTools.getConnection();
            String sql = "select id,name,email,birth"
                    + " from customers where id=?";
            Customer customer=customerDAO.get(connection, sql, 5);
            System.out.println(customer);
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            JDBCTools.release(null, null, connection);
        }
    }

    @Test
    public void testUpdate() {
        fail("Not yet implemented");
    }

}

运行一下:

Customer [id=5, name=dsv, email=474405914@qq.com, birth=2016-05-10]

可以通过我们的get方法得到我们想要的数据信息

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值