10.25JDBC之Apache-DBUtils实现CRUD操作

Posted 俊king

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了10.25JDBC之Apache-DBUtils实现CRUD操作相关的知识,希望对你有一定的参考价值。

10.25JDBC之Apache-DBUtils实现CRUD操作

Apache-DBUtils简介

什么是Apache-DBUtils?

commons-dbutilsApache组织提供的一个开源的JDBC工具类库

API介绍

  • org.apache.commons.dbutils.QueryRunner

  • org.apache.commons.dbutils.ResultSetHandler

  • org.apache.commons.dbutils.DbUtils工具类

使用方式

导入依赖

        <!--dbutils依赖-->
       <dependency>
           <groupId>commons-dbutils</groupId>
           <artifactId>commons-dbutils</artifactId>
           <version>1.7</version>
       </dependency>

主要使用方法:

  • QueryRunner类下封装的方法

插入一条数据:

    @Test
   public void testInsert() throws Exception {
       Connection conn = null;
       try {
           //新建对象引用
           QueryRunner runner = new QueryRunner();

           //获取一个连接
           DruidTest dt = new DruidTest();
           conn = dt.getConnection();
           String sql = "insert into customers(name, email, birthday) values(?, ?, ?);";

           //调用方法
           /*
           传参:
           连接
           sql
           object对象
            */
           int insertCount = runner.update(conn, sql, "蔡徐坤", "cai@163.com", "1999-09-09");
           System.out.println("添加了" + insertCount + "记录!");
      }catch (Exception e){
           e.printStackTrace();
      }finally {
           //关闭练级
           JDBCUtils.closeResource(conn, null);
      }
  }

返回单个结果的封装方法:

    //测试查询操作,使用dbutils
   /*
   使用BeanHandler,是ResultSet接口的实现类。用于封装表中的一条记录
    */
   @Test
   public void testQuery1() {
       Connection conn = null;
       try {
           QueryRunner runner = new QueryRunner();
           //调用query当中的结果集处理器方法
           /*
           参数:
           连接
           sql
           结果集处理器--->这是一个接口,需要传接口的具体实现类的实例。结果集返回数据这一块通过接口进行处理。因为返回的情况是多样的。为了应对不同的结果所以定义一个接口作为标准
           object对象
            */
           conn = JDBCUtils.getConnection();
           String sql = "select id, name, birthday from customers where id = ?;";
           /*BeanHandler是结果集处理器的接口实现类--->没有空参构造器*/
           BeanHandler<Customer> handler = new BeanHandler<>(Customer.class);

           Customer customer = runner.query(conn, sql, handler, 23);

           System.out.println(customer);
      }catch (Exception e) {
           e.printStackTrace();
      }finally {
           //关闭资源
           JDBCUtils.closeResource(conn, null);
      }
  }

使用List封装返回的多个结果对象:

    //测试查询,使用dbutils封装多条返回记录
   /*
   BeanListHandler,是一个DBUtils的实现类。用于封装多条记录的返回结果
    */
   @Test
   public void testQuery2() throws SQLException {
       Connection conn = null;
       try {
           QueryRunner runner = new QueryRunner();

           conn = JDBCUtils.getConnection();
           String sql = "select id, name, birthday from customers where id < ?;";
           /*BeanListHandler是结果集处理器的接口实现类--->封装返回的多条记录*/
           BeanListHandler<Customer> handler = new BeanListHandler<>(Customer.class);

           List<Customer> list = runner.query(conn, sql, handler, 23);

           //打印list
           list.forEach(System.out::println);
      }catch (Exception e) {
           e.printStackTrace();
      }finally {
           //关闭资源
           JDBCUtils.closeResource(conn, null);
      }
  }

使用Map封装返回的单个结果对象:

    //返回一个Map
   /*
   MapHandler,封装返回的也是一条纪律
   返回的对象是以一个map的方式来呈现
   将字段与值作为map中的key和value
    */
   @Test
   public void testQuery3() {
       Connection conn = null;
       try {
           QueryRunner runner = new QueryRunner();
           //调用方法传入参数
           /*
           连接
           sql
           结果集处理器
           object对象
            */
           conn = JDBCUtils.getConnection();
           String sql = "select id, name, email, birthday from customers where id = ?;";
           /*使用maphandler处理结果集*/
           MapHandler handler = new MapHandler();
           Map<String, Object> map = runner.query(conn, sql, handler, 23);
           System.out.println(map);
      }catch (Exception e) {
           e.printStackTrace();
      }finally {
           //关闭资源
           JDBCUtils.closeResource(conn, null);
      }
  }

使用MapList封装返回的多个对象:

    //MapListHandler
   /*
   以map德形式返回字段和值
   返回多个结果集
    */
   @Test
   public void testQuery4() {
       Connection conn = null;
       try {
           QueryRunner runner = new QueryRunner();
           conn = JDBCUtils.getConnection();
           String sql = "select id, name, email, birthday from customers where id < ?;";
           /*使用MapListHandler作为结果集处理器*/
           MapListHandler handler = new MapListHandler();
           List<Map<String, Object>> list = runner.query(conn, sql, handler, 23);

           //循环打印list
           list.forEach(System.out::println);
      }catch (Exception e) {
           e.printStackTrace();
      }finally {
           //关闭资源
           JDBCUtils.closeResource(conn, null);
      }
  }

使用MapListHandler对返回的多个结果集对象进行封装:

    //MapListHandler
   /*
   以map德形式返回字段和值
   返回多个结果集
   每一条记录对应map中的key和value
    */
   @Test
   public void testQuery4() {
       Connection conn = null;
       try {
           QueryRunner runner = new QueryRunner();
           conn = JDBCUtils.getConnection();
           String sql = "select id, name, email, birthday from customers where id < ?;";
           /*使用MapListHandler作为结果集处理器*/
           MapListHandler handler = new MapListHandler();
           List<Map<String, Object>> list = runner.query(conn, sql, handler, 23);

           //循环打印list
           list.forEach(System.out::println);
      }catch (Exception e) {
           e.printStackTrace();
      }finally {
           //关闭资源
           JDBCUtils.closeResource(conn, null);
      }
  }

使用sql的内置函数进行查询操作:

    //使用sql函数进行查询操作返回封装的结果集
   @Test
   public void testQuery5() {
       Connection conn = null;
       try {
           QueryRunner runner = new QueryRunner();
           //获取连接
           conn = JDBCUtils.getConnection();
           //书写sql
           String sql = "select count(*) from customers;";
           //选择结果处理器
           /*使用salarhandler*/
           ScalarHandler handler = new ScalarHandler();
           //调用方法传入指定参数
           Long count = (Long) runner.query(conn, sql, handler);
           System.out.println(count);
      }catch (Exception e){
           e.printStackTrace();
      }finally {
           //关闭资源
           JDBCUtils.closeResource(conn, null);
      }
  }

data类型:

    //使用sql函数进行查询data类型的操作
   @Test
   public void testQuery6() {
       Connection conn = null;
       try {
           QueryRunner runner = new QueryRunner();
           //获取连接
           conn = JDBCUtils.getConnection();
           //书写sql
           String sql = "select max(birthday) from customers;";
           //选择结果处理器--->该类有空参构造器
           ScalarHandler handler = new ScalarHandler();
           //调用runner下的方法
           Data maxBirth = (Data) runner.query(conn, sql, handler);
           System.out.println(maxBirth);
      }catch (Exception e) {
           e.printStackTrace();
      }finally {
           //关闭资源
           JDBCUtils.closeResource(conn, null);
      }
  }

自定义DBUtils实现类进行查询操作

因为上诉的一些方法都是再Bean类下实现的方法。这些类统一实现了接口:Interface ResultSetHandler<T>这个泛型接口。

所以可以通过实现该接口的方式自定义查询的实现类和方法

具体实现类:

    /*
   自定义一个ResultSetHandler的实现类
    */
   @Test
   public void testQuery7() {
       Connection conn = null;
       try {
           QueryRunner runner = new QueryRunner();
           //获取连接
           conn = JDBCUtils.getConnection();
           //书写sql
           String sql = "select max(birthday) from customers;";
           //自定义一个匿名的结果集实现类--->在new的对象引用提供接口重写的方法
           /*
           提供匿名实现类的时候右边的泛型不能省略
            */
           ResultSetHandler<Customer> handler = new ResultSetHandler<Customer>(){
               //该方法返回的对象作为下面runner.query的返回值
               @Override
               public Customer handle(ResultSet resultSet) throws SQLException {
                   System.out.println("啥也不是!");
//                   return null;
                   //返回一个固定的结果集
//                   return new Customer(18, "帅气逼人", "Lucifer@163.com", new Date(655354523L));
                   //BeanHandler实际的结果集执行的逻辑是
                   if (resultSet.next()){
                       int id = resultSet.getInt("id");
                       String name = resultSet.getString("name");
                       String email = resultSet.getString("email");
                       Date birth = resultSet.getDate("birthday");
                       Customer customer = new Customer(id, name, email, birth);
                       return customer;
                  }
                   return null;
              }
          };
           //使用自定义的查询语句进行查询
           /*
           上述handle方法的返回值就是query的返回值
            */
           Customer customer = runner.query(conn, sql, handler, 23);
           System.out.println(customer);
      }catch (Exception e) {
           e.printStackTrace();
      }finally {
           //关闭资源
           JDBCUtils.closeResource(conn, null);
      }
  }

调用第三方工具类提供的关闭资源的方法

关闭资源:

    /*调用第三方sdk提供的工具类下的方法实现资源的关闭*/
   public static void closeResource2(Connection conn, PreparedStatement ps, ResultSet rs) {
       try {
           DbUtils.close(conn);
      }catch (SQLException e) {
           e.printStackTrace();
      }
       try {
           DbUtils.close(ps);
      }catch (SQLException e) {
           e.printStackTrace();
      }
       try {
           DbUtils.close(rs);
      }catch (SQLException e) {
           e.printStackTrace();
      }
  }

   /*调用第三方sdk提供的工具类,方法中处理异常*/
   public static void closeResource3(Connection conn, PreparedStatement ps, ResultSet rs) {
       DbUtils.closeQuietly(conn);
       DbUtils.closeQuietly(ps);
       DbUtils.closeQuietly(rs);
  }

 

It\'s a lonely road!!!

JDBC,连接池及CRUD操作

一,JDBC

 

二,连接数据库代码:

    @Test
    public void testConnection1() {
        try {
            //1.提供java.sql.Driver接口实现类的对象
            Driver driver = null;
            driver = new com.mysql.jdbc.Driver();

            //2.提供url,指明具体操作的数据
            String url = "jdbc:mysql://localhost:3306/test";

            //3.提供Properties的对象,指明用户名和密码
            Properties info = new Properties();
            info.setProperty("user", "root");
            info.setProperty("password", "abc123");

            //4.调用driver的connect(),获取连接
            Connection conn = driver.connect(url, info);
            System.out.println(conn);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
连接方式一

 过于原始,并不推荐,一共有五种方式,具体可以去尚硅谷jdbc课程资料里查看,这里直接到最终版。

@Test
    public  void testConnection5() throws Exception {
        //1.加载配置文件
        InputStream is = ConnectionTest.class.getClassLoader().getResourceAsStream("jdbc.properties");
        Properties pros = new Properties();
        pros.load(is);
        
        //2.读取配置信息
        String user = pros.getProperty("user");
        String password = pros.getProperty("password");
        String url = pros.getProperty("url");
        String driverClass = pros.getProperty("driverClass");

        //3.加载驱动
        Class.forName(driverClass);

        //4.获取连接
        Connection conn = DriverManager.getConnection(url,user,password);
        System.out.println(conn);

    }
连接方式五(最终版)

其中,配置文件声明在工程的src目录下:【jdbc.properties】

user=root
password=abc123
url=jdbc:mysql://localhost:3306/test
driverClass=com.mysql.jdbc.Driver

说明:使用配置文件的方式保存配置信息,在代码中加载配置文件

使用配置文件的好处:

①实现了代码和数据的分离,如果需要修改配置信息,直接在配置文件中修改,不需要深入代码 ②如果修改了配置信息,省去重新编译的过程。

三,使用PreparedStatement实现CRUD操作

    //通用的增、删、改操作(体现一:增、删、改 ; 体现二:针对于不同的表)
    public void update(String sql,Object ... args){
        Connection conn = null;
        PreparedStatement ps = null;
        try {
            //1.获取数据库的连接
            conn = JDBCUtils.getConnection();
            
            //2.获取PreparedStatement的实例 (或:预编译sql语句)
            ps = conn.prepareStatement(sql);
            //3.填充占位符
            for(int i = 0;i < args.length;i++){
                ps.setObject(i + 1, args[i]);
            }
            
            //4.执行sql语句
            ps.execute();
        } catch (Exception e) {
            
            e.printStackTrace();
        }finally{
            //5.关闭资源
            JDBCUtils.closeResource(conn, ps);
            
        }
    }
增、删、改操作
// 通用的针对于不同表的查询:返回一个对象 (version 1.0)
    public <T> T getInstance(Class<T> clazz, String sql, Object... args) {

        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            // 1.获取数据库连接
            conn = JDBCUtils.getConnection();

            // 2.预编译sql语句,得到PreparedStatement对象
            ps = conn.prepareStatement(sql);

            // 3.填充占位符
            for (int i = 0; i < args.length; i++) {
                ps.setObject(i + 1, args[i]);
            }

            // 4.执行executeQuery(),得到结果集:ResultSet
            rs = ps.executeQuery();

            // 5.得到结果集的元数据:ResultSetMetaData
            ResultSetMetaData rsmd = rs.getMetaData();

            // 6.1通过ResultSetMetaData得到columnCount,columnLabel;通过ResultSet得到列值
            int columnCount = rsmd.getColumnCount();
            if (rs.next()) {
                T t = clazz.newInstance();
                for (int i = 0; i < columnCount; i++) {// 遍历每一个列

                    // 获取列值
                    Object columnVal = rs.getObject(i + 1);
                    // 获取列的别名:列的别名,使用类的属性名充当
                    String columnLabel = rsmd.getColumnLabel(i + 1);
                    // 6.2使用反射,给对象的相应属性赋值
                    Field field = clazz.getDeclaredField(columnLabel);
                    field.setAccessible(true);
                    field.set(t, columnVal);

                }

                return t;

            }
        } catch (Exception e) {

            e.printStackTrace();
        } finally {
            // 7.关闭资源
            JDBCUtils.closeResource(conn, ps, rs);
        }

        return null;

    }
实现查询操作

,操作BLOB类型字段(二进制)(具体看学习资料)

五, 批量插入(不常用,具体看学习资料)

六: 数据库事务(详细内容看学习资料)

【案例:用户AA向用户BB转账100】

public void testJDBCTransaction() {
    Connection conn = null;
    try {
        // 1.获取数据库连接
        conn = JDBCUtils.getConnection();
        // 2.开启事务
        conn.setAutoCommit(false);
        // 3.进行数据库操作
        String sql1 = "update user_table set balance = balance - 100 where user = ?";
        update(conn, sql1, "AA");

        // 模拟网络异常
        //System.out.println(10 / 0);

        String sql2 = "update user_table set balance = balance + 100 where user = ?";
        update(conn, sql2, "BB");
        // 4.若没有异常,则提交事务
        conn.commit();
    } catch (Exception e) {
        e.printStackTrace();
        // 5.若有异常,则回滚事务
        try {
            conn.rollback();
        } catch (SQLException e1) {
            e1.printStackTrace();
        }
    } finally {
        try {
            //6.恢复每次DML操作的自动提交功能
            conn.setAutoCommit(true);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        //7.关闭连接
        JDBCUtils.closeResource(conn, null, null); 
    }  
}
案例

其中,对数据库操作的方法为:

//使用事务以后的通用的增删改操作(version 2.0)
public void update(Connection conn ,String sql, Object... args) {
    PreparedStatement ps = null;
    try {
        // 1.获取PreparedStatement的实例 (或:预编译sql语句)
        ps = conn.prepareStatement(sql);
        // 2.填充占位符
        for (int i = 0; i < args.length; i++) {
            ps.setObject(i + 1, args[i]);
        }
        // 3.执行sql语句
        ps.execute();
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        // 4.关闭资源
        JDBCUtils.closeResource(null, ps);

    }
}
使用事务以后的通用的增删改操作

七:DAO及相关实现类(详细内容看学习资料,分页等)

  • DAO:Data Access Object访问数据信息的类和接口,包括了对数据的CRUD(Create、Retrival、Update、Delete),而不包含任何业务相关的信息。有时也称作:BaseDAO

  • 作用:为了实现功能的模块化,更有利于代码的维护和升级。

 

 

 

package com.atguigu.bookstore.dao;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;

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


/**
 * 定义一个用来被继承的对数据库进行基本操作的Dao
 * 
 * @author HanYanBing
 *
 * @param <T>
 */
public abstract class BaseDao<T> {
    private QueryRunner queryRunner = new QueryRunner();
    // 定义一个变量来接收泛型的类型
    private Class<T> type;

    // 获取T的Class对象,获取泛型的类型,泛型是在被子类继承时才确定
    public BaseDao() {
        // 获取子类的类型
        Class clazz = this.getClass();
        // 获取父类的类型
        // getGenericSuperclass()用来获取当前类的父类的类型
        // ParameterizedType表示的是带泛型的类型
        ParameterizedType parameterizedType = (ParameterizedType) clazz.getGenericSuperclass();
        // 获取具体的泛型类型 getActualTypeArguments获取具体的泛型的类型
        // 这个方法会返回一个Type的数组
        Type[] types = parameterizedType.getActualTypeArguments();
        // 获取具体的泛型的类型·
        this.type = (Class<T>) types[0];
    }

    /**
     * 通用的增删改操作
     * 
     * @param sql
     * @param params
     * @return
     */
    public int update(Connection conn,String sql, Object... params) {
        int count = 0;
        try {
            count = queryRunner.update(conn, sql, params);
        } catch (SQLException e) {
            e.printStackTrace();
        } 
        return count;
    }

    /**
     * 获取一个对象
     * 
     * @param sql
     * @param params
     * @return
     */
    public T getBean(Connection conn,String sql, Object... params) {
        T t = null;
        try {
            t = queryRunner.query(conn, sql, new BeanHandler<T>(type), params);
        } catch (SQLException e) {
            e.printStackTrace();
        } 
        return t;
    }

    /**
     * 获取所有对象
     * 
     * @param sql
     * @param params
     * @return
     */
    public List<T> getBeanList(Connection conn,String sql, Object... params) {
        List<T> list = null;
        try {
            list = queryRunner.query(conn, sql, new BeanListHandler<T>(type), params);
        } catch (SQLException e) {
            e.printStackTrace();
        } 
        return list;
    }

    /**
     * 获取一个但一值得方法,专门用来执行像 select count(*)...这样的sql语句
     * 
     * @param sql
     * @param params
     * @return
     */
    public Object getValue(Connection conn,String sql, Object... params) {
        Object count = null;
        try {
            // 调用queryRunner的query方法获取一个单一的值
            count = queryRunner.query(conn, sql, new ScalarHandler<>(), params);
        } catch (SQLException e) {
            e.printStackTrace();
        } 
        return count;
    }
}
BaseDao

八:数据库连接池

 数据库连接池在初始化时将创建一定数量的数据库连接放到连接池中,这些数据库连接的数量是由最小数据库连接数来设定的。无论这些数据库连接是否被使用,连接池都将一直保证至少拥有这么多的连接数量。连接池的最大数据库连接数量限定了这个连接池能占有的最大连接数,当应用程序向连接池请求的连接数超过最大连接数量时,这些请求将被加入到等待队列中。

 

  • JDBC 的数据库连接池使用 javax.sql.DataSource 来表示,DataSource 只是一个接口,该接口通常由服务器(Weblogic, WebSphere, Tomcat)提供实现,也有一些开源组织提供实现:

                 Druid 是阿里提供的数据库连接池,据说是集DBCP 、C3P0 、Proxool 优点于一身的数据库连接池,但是速度不确定是否有BoneCP快。

 

  • DataSource 通常被称为数据源,它包含连接池和连接池管理两个部分,习惯上也经常把 DataSource 称为连接池

  • DataSource用来取代DriverManager来获取Connection,获取速度快,同时可以大幅度提高数据库访问速度。

  • 特别注意:

    • 数据源和数据库连接不同,数据源无需创建多个,它是产生数据库连接的工厂,因此整个应用只需要一个数据源即可。

    • 当数据库访问结束后,程序还是像以前一样关闭数据库连接:conn.close(); 但conn.close()并没有关闭数据库的物理连接,它仅仅把数据库连接释放,归还给了数据库连接池。

package com.atguigu.druid;

import java.sql.Connection;
import java.util.Properties;

import javax.sql.DataSource;

import com.alibaba.druid.pool.DruidDataSourceFactory;

public class TestDruid {
    public static void main(String[] args) throws Exception {
        Properties pro = new Properties();         pro.load(TestDruid.class.getClassLoader().getResourceAsStream("druid.properties"));
        DataSource ds = DruidDataSourceFactory.createDataSource(pro);
        Connection conn = ds.getConnection();
        System.out.println(conn);
    }
}
druid

其中,src下的配置文件为:【druid.properties】

url=jdbc:mysql://localhost:3306/test?rewriteBatchedStatements=true
username=root
password=123456
driverClassName=com.mysql.jdbc.Driver

initialSize=10 //初始连接数
maxActive=20 //最大了解数 maxWait=1000 //最大等待时间,单位毫秒 filters=wall //属性类型是字符串,通过别名的方式配置扩展插件,常用的插件有: 监控统计用的filter:stat日志用的filter:log4j防御sql注入的filter:wall
//资料里有更多

九:Apache-DBUtils实现CRUD操作

9.1 Apache-DBUtils简介

  • commons-dbutils 是 Apache 组织提供的一个开源 JDBC工具类库,它是对JDBC的简单封装,学习成本极低,并且使用dbutils能极大简化jdbc编码的工作量,同时也不会影响程序的性能。

  • API介绍:

    • org.apache.commons.dbutils.QueryRunner

    • org.apache.commons.dbutils.ResultSetHandler

    • 工具类:org.apache.commons.dbutils.DbUtils

 

 

 

9.2 主要API的使用

9.2.1 DbUtils

  • DbUtils :提供如关闭连接、装载JDBC驱动程序等常规工作的工具类,里面的所有方法都是静态的。主要方法如下:

    • public static void close(…) throws java.sql.SQLException: DbUtils类提供了三个重载的关闭方法。这些方法检查所提供的参数是不是NULL,如果不是的话,它们就关闭Connection、Statement和ResultSet。

    • public static void closeQuietly(…): 这一类方法不仅能在Connection、Statement和ResultSet为NULL情况下避免关闭,还能隐藏一些在程序中抛出的SQLEeception。

    • public static void commitAndClose(Connection conn)throws SQLException: 用来提交连接的事务,然后关闭连接

    • public static void commitAndCloseQuietly(Connection conn): 用来提交连接,然后关闭连接,并且在关闭连接时不抛出SQL异常。

    • public static void rollback(Connection conn)throws SQLException:允许conn为null,因为方法内部做了判断

    • public static void rollbackAndClose(Connection conn)throws SQLException

    • rollbackAndCloseQuietly(Connection)

    • public static boolean loadDriver(java.lang.String driverClassName):这一方装载并注册JDBC驱动程序,如果成功就返回true。使用该方法,你不需要捕捉这个异常ClassNotFoundException。

9.2.2 QueryRunner类

  • 该类简单化了SQL查询,它与ResultSetHandler组合在一起使用可以完成大部分的数据库操作,能够大大减少编码量。

  • QueryRunner类提供了两个构造器:

    • 默认的构造器

    • 需要一个 javax.sql.DataSource 来作参数的构造器

  • QueryRunner类的主要方法:

    • 更新

      • public int update(Connection conn, String sql, Object... params) throws SQLException:用来执行一个更新(插入、更新或删除)操作。

      • ......

    • 插入

      • public <T> T insert(Connection conn,String sql,ResultSetHandler<T> rsh, Object... params) throws SQLException:只支持INSERT语句,其中 rsh - The handler used to create the result object from the ResultSet of auto-generated keys. 返回值: An object generated by the handler.即自动生成的键值

      • ....

    • 批处理

      • public int[] batch(Connection conn,String sql,Object params)throws SQLException: INSERT, UPDATE, or DELETE语句

      • public <T> T insertBatch(Connection conn,String sql,ResultSetHandler<T> rsh,Object params)throws SQLException:只支持INSERT语句

      • .....

    • 查询

      • public Object query(Connection conn, String sql, ResultSetHandler rsh,Object... params) throws SQLException:执行一个查询操作,在这个查询中,对象数组中的每个元素值被用来作为查询语句的置换参数。该方法会自行处理 PreparedStatement 和 ResultSet 的创建和关闭。

// 测试添加
@Test
public void testInsert() throws Exception {
    QueryRunner runner = new QueryRunner();
    Connection conn = JDBCUtils.getConnection3();
    String sql = "insert into customers(name,email,birth)values(?,?,?)";
    int count = runner.update(conn, sql, "何成飞", "he@qq.com", "1992-09-08");

    System.out.println("添加了" + count + "条记录");
        
    JDBCUtils.closeResource(conn, null);

}
测试添加

9.2.3 ResultSetHandler接口及实现类

  • 该接口用于处理 java.sql.ResultSet,将数据按要求转换为另一种形式。

  • ResultSetHandler 接口提供了一个单独的方法:Object handle (java.sql.ResultSet .rs)。

  • 接口的主要实现类:

    • ArrayHandler:把结果集中的第一行数据转成对象数组。

    • ArrayListHandler:把结果集中的每一行数据都转成一个数组,再存放到List中。

    • BeanHandler:将结果集中的第一行数据封装到一个对应的JavaBean实例中。就是说该实现类return一个JavaBean类型

    • BeanListHandler:将结果集中的每一行数据都封装到一个对应的JavaBean实例中,存放到List里。就是说该实现类return一个list里面放着JavaBean。

    • ColumnListHandler:将结果集中某一列的数据存放到List中。

    • KeyedHandler(name):将结果集中的每一行数据都封装到一个Map里,再把这些map再存到一个map里,其key为指定的key。

    • MapHandler:将结果集中的第一行数据封装到一个Map里,key是列名,value就是对应的值。

    • MapListHandler:将结果集中的每一行数据都封装到一个Map里,然后再存放到List

    • ScalarHandler:查询单个值对象

/*
 * 测试查询:查询一条记录
 * 
 * 使用ResultSetHandler的实现类:BeanHandler
 */
@Test
public void testQueryInstance() throws Exception{
    QueryRunner runner = new QueryRunner();

    Connection conn = JDBCUtils.getConnection3();
        
    String sql = "select id,name,email,birth from customers where id = ?";
        
    //
    BeanHandler<Customer> handler = new BeanHandler<>(Customer.class);
    Customer customer = runner.query(conn, sql, handler, 23);
    System.out.println(customer);    
    JDBCUtils.closeResource(conn, null);
}
查询一条记录
/*
 * 测试查询:查询多条记录构成的集合
 * 
 * 使用ResultSetHandler的实现类:BeanListHandler
 */
@Test
public void testQueryList() throws Exception{
    QueryRunner runner = new QueryRunner();

    Connection conn = JDBCUtils.getConnection3();
        
    String sql = "select id,name,email,birth from customers where id < ?";
        
    //
    BeanListHandler<Customer> handler = new BeanListHandler<>(Customer.class);
    List<Customer> list = runner.query(conn, sql, handler, 23);
    list.forEach(System.out::println);
        
    JDBCUtils.closeResource(conn, null);
}
查询多条记录构成的集合
/*
 * 自定义ResultSetHandler的实现类
 */
@Test
public void testQueryInstance1() throws Exception{
    QueryRunner runner = new QueryRunner();

    Connection conn = JDBCUtils.getConnection3();
        
    String sql = "select id,name,email,birth from customers where id = ?";
        
    ResultSetHandler<Customer> handler = new ResultSetHandler<Customer>() {

        @Override
        public Customer handle(ResultSet rs) throws SQLException {
            System.out.println("handle");
//            return new Customer(1,"Tom","tom@126.com",new Date(123323432L));
                
            if(rs.next()){
                int id = rs.getInt("id");
                String name = rs.getString("name");
                String email = rs.getString("email");
                Date birth = rs.getDate("birth");
                    
                return new Customer(id, name, email, birth);
            }
            return null;
                
        }
    };
        
    Customer customer = runner.query(conn, sql, handler, 23);
        
    System.out.println(customer);
        
    JDBCUtils.closeResource(conn, null);
}
自定义ResultSetHandler的实现类
/*
 * 如何查询类似于最大的,最小的,平均的,总和,个数相关的数据,
 * 使用ScalarHandler
 * 
 */
@Test
public void testQueryValue() throws Exception{
    QueryRunner runner = new QueryRunner();

    Connection conn = JDBCUtils.getConnection3();
        
    //测试一:
//    String sql = "select count(*) from customers where id < ?";
//    ScalarHandler handler = new ScalarHandler();
//    long count = (long) runner.query(conn, sql, handler, 20);
//    System.out.println(count);
        
    //测试二:
    String sql = "select max(birth) from customers";
    ScalarHandler handler = new ScalarHandler();
    Date birth = (Date) runner.query(conn, sql, handler);
    System.out.println(birth);
        
    JDBCUtils.closeResource(conn, null);
}
查询类似于最大的,最小的,平均的,总和,个数相关的数据

JDBC总结

总结
@Test
public void testUpdateWithTx() {
        
    Connection conn = null;
    try {
        //1.获取连接的操作(
        //① 手写的连接:JDBCUtils.getConnection();
        //② 使用数据库连接池:C3P0;DBCP;Druid
        //2.对数据表进行一系列CRUD操作
        //① 使用PreparedStatement实现通用的增删改、查询操作(version 1.0 \\ version 2.0)
//version2.0的增删改public void update(Connection conn,String sql,Object ... args){}
//version2.0的查询 public <T> T getInstance(Connection conn,Class<T> clazz,String sql,Object ... args){}
        //② 使用dbutils提供的jar包中提供的QueryRunner类
            
        //提交数据
        conn.commit();
            
    
    } catch (Exception e) {
        e.printStackTrace();

以上是关于10.25JDBC之Apache-DBUtils实现CRUD操作的主要内容,如果未能解决你的问题,请参考以下文章

JDBC,连接池及CRUD操作

10.25算法训练——裸线段树

Java 中Apache-DBUtils类的使用详解

Java 中Apache-DBUtils类的使用详解

JavaJDBC Part6 DBUtils工具依赖

通俗易懂的JDBC教程-JDBC与ORM发展与联系#私藏项目实操分享#