【MySQL】深入理解DBUtils及自定义DBUtils

本专栏将从基础开始,循序渐进,讲解数据库的基本概念以及使用,希望大家都能够从中有所收获,也请大家多多支持。
专栏地址: 数据库必知必会
相关软件地址:软件地址
如果文章知识点有错误的地方,请指正!大家一起学习,一起进步。

1 DBUtils

1.1 DBUtils的概述

​ DbUtils是Apache组织提供的一个对JDBC进行简单封装的开源工具类库,使用它能够简化JDBC应用程序的开发,同时也不会影响程序的性能

1.2 DBUtils的常用API介绍

  1. 创建QueryRunner对象的API

    public QueryRunner(DataSource ds) ,提供数据源(连接池),DBUtils底层自动维护连接connection

  2. QueryRunner执行增删改的SQL语句的API

    int update(String sql, Object... params),执行增删改的SQL语句, params参数就是可变参数,参数个数取决于语句中问号的个数

    eg: qr.update(“insert into user values(null,?,?,?)”,“zs”,“123456”,“张三”);

  3. 执行查询的SQL语句的API

    query(String sql, ResultSetHandler<T> rsh, Object... params),其中ResultSetHandler是一个接口,表示结果集处理者

小结

DBUtils: Apache开发的一个数据库工具包, 用来简化JDBC操作数据库的步骤

1.3 JavaBean

JavaBean说白了就是一个类, 用来封装数据用的

  1. JavaBean要求

    • 私有字段
    • 提供公共的get/set方法
    • 无参构造
    • 建议满参构造
    • 实现Serializable
  2. 字段和属性

    • 字段: 全局/成员变量 eg: private String username
    • 属性: 去掉get或者set首字母变小写 eg: setUsername-去掉set->Username-首字母变小写->username

    一般情况下,我们通过IDEA直接生成的set/get

小结

  1. JavaBean用来封装数据用的
  2. 字段和属性
    • 字段: 全局/成员变量 eg: private String username
    • 属性: 去掉get或者set首字母变小写 eg: setUsername-去掉set->Username-首字母变小写->username

1.4 使用DBUtils完成增删改

步骤

  1. 拷贝jar包
  2. 创建QueryRunner()对象,传入dataSource
  3. 调用update()方法

实现

public class UpdateTest {
    
    
    // 插入记录
    @Test
    public void insert() throws Exception {
    
    
        // 1.创建QueryRunner对象,传入连接池
        QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());

        // 2.调用update方法
        String sql = "insert into user values(null,?,?,?)";
        int rows = qr.update(sql, "tianqi", "123456", "田七");
        System.out.println("受影响的行数:" + rows);

    }

    // 删除记录  删除id为4的记录
    @Test
    public void delete() throws Exception {
    
    
        // 1.创建QueryRunner对象,传入连接池
        QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());

        // 2.调用update方法
        String sql = "delete from user where id = ?";
        int rows = qr.update(sql, 4);
        System.out.println("受影响的行数:" + rows);
    }

    // 修改记录  修改id为5的记录
    @Test
    public void update() throws Exception{
    
    
        // 1.创建QueryRunner对象,传入连接池
        QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());

        // 2.调用update方法
        String sql = "update user set password = ? where id = ?";
        int rows = qr.update(sql,"abcd",3);
        System.out.println("受影响的行数:" + rows);
    }
}

小结

  1. 创建QueryRuner()对象, 传入DataSource
  2. 调用update(String sql, Object…params)

1.5 使用DBUtils完成查询

目标

  • 掌握使用DBUtils完成查询

步骤

  1. 拷贝jar包
  2. 创建QueryRunner()对象 传入DataSource
  3. 调用query(sql, resultSetHandler,params)方法

1.5.1 ResultSetHandler结果集处理类介绍

img

public queryRunner(DataSource ds);
query(String sql, ResultSetHandler rsh, Object… params) 执行查询语句
参数ResultSetHandler是一个接口,表示结果集处理者(对查询结果的封装):
ResultSetHandler接口的实现类:
ArrayHandler:适合查询结果是一条记录的,会把这条记录的数据封装到一个Object数组
ArrayListHandler:适合查询结果是多条记录的,会把每条记录的数据封装到一个Object数组中,然后把这些数组添加到List集合
BeanHandler:适合查询结果是一条记录的,会把这条记录的数据封装到一个javaBean对象中
BeanListHandler:适合查询结果是多条记录的,会把每条记录的数据封装到一个javaBean对象中,然后把这些javaBean对象添加到List集合
ColumnListHandler:适合查询结果是单列多行的,会把该列的所有数据存储到List集合
KeyedHandle:适合查询结果是多条记录的,会把每条记录的数据封装到一个Map集合中,然后把这些Map集合添加到另一个Map集合
MapHandler:适合查询结果是一条记录的,会把这条记录的数据封装到一个Map集合
MapListHandler:适合查询结果是多条记录的,会把每条记录的数据封装到一个Map集合中,然后把这些Map集合添加到List集合
ScalarHandler:适合查询结果是单个值的,会把这个值封装成一个对象

代码实现

1.5.1.1 查询一条数据封装到JavaBean对象中(使用BeanHandler)

 @Test
    public void select1() throws Exception{
    
    
        // 1.创建QueryRunner对象,传入连接池
        QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());

        // 2.调用query(sql,resultSetHandler,args)方法
        String sql = "select * from user where id = ?";
        User user = qr.query(sql, new BeanHandler<User>(User.class), 3);
        System.out.println(user);

    }

1.5.1.2 查询多条数据封装到List中(使用BeanListHandler)

	 @Test
    public void select2() throws Exception{
    
    
        // 1.创建QueryRunner对象,传入连接池
        QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
        // 2.调用query方法
        String sql = "select * from user";
        List<User> list = qr.query(sql, new BeanListHandler<User>(User.class));
        for (User user : list) {
    
    
            System.out.println(user);
        }
    }

1.5.1.3 查询一条数据,封装到Map对象中(使用MapHandler)

  // 查询一条数据,封装到Map对象中(使用MapHandler)
    // 列名作为key,列中的值作为value
    @Test
    public void select3() throws Exception {
    
    
        // 1.创建QueryRunner对象,传入连接池
        QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
        // 2.调用query方法
        String sql = "select * from user where id = ?";
        Map<String, Object> map = qr.query(sql, new MapHandler(), 3);
        for (String key : map.keySet()) {
    
    
            System.out.println(key + ":" + map.get(key));
        }
    }

/*
password:123
nickname:aaa
id:3
username:wangwu
*/

1.5.1.4 查询多条数据,封装到List Map 对象中(使用MapListHandler)

  // 查询多条数据,封装到List<Map>对象中(使用MapListHandler)
    @Test
    public void select4() throws Exception{
    
    
        // 1.创建QueryRunner对象,传入连接池
        QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
        // 2.调用query方法
        String sql = "select * from user";
        List<Map<String, Object>> list = qr.query(sql, new MapListHandler());
        for (Map<String, Object> map : list) {
    
    
            // map--->每条记录
            for (String key : map.keySet()) {
    
    
                System.out.println(key + ":" + map.get(key));
            }
            System.out.println("=================================================");
        }
    }

1.5.1.5 查询单个数据(使用ScalarHandler())

    // 查询单个数据(使用ScalarHandler())
    @Test
    public void select5() throws Exception{
    
    
        // 1.创建QueryRunner对象,传入连接池
        QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
        // 2.调用query方法
        String sql = "select count(*) from user";
        Long count = (Long) qr.query(sql, new ScalarHandler());
        System.out.println("记录数:"+count);
    }

1.5.1.6 查询单列多个值(使用ArrayListHandler)

    // 查询单列多个值(ArrayListHandler)
    // 单列多值: 每列的数据封装成一个数组,再把所有的数组存储到List集合中
    // 多条记录: 每条记录的数据封装成一个数组,再把所有的数组存储到List集合中
    @Test
    public void select6() throws Exception{
    
    
        // 1.创建QueryRunner对象,传入连接池
        QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
        // 2.调用query方法
        String sql = "select username from user";
        List<Object[]> list = qr.query(sql, new ArrayListHandler());
        for (Object[] arr : list) {
    
    
            System.out.println(Arrays.toString(arr));
        }
    }

1.5.1.7 查询一条记录(使用ArrayHandler)

		// 查询一条记录(ArrayHandler)
    // 一条记录封装成一个数组,数组中的元素就是每列的值
    @Test
    public void select7() throws Exception{
    
    
        // 1.创建QueryRunner对象,传入连接池
        QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
        // 2.调用query方法
        String sql = "select * from user where id = ?";
        Object[] arr = qr.query(sql, new ArrayHandler(), 3);
        System.out.println(Arrays.toString(arr));
    }

小结

  1. 步骤

    • 创建QueryRunner() 对象传入DataSource
    • 调用query(sql,ResultSetHandler, params…)
  2. ResultSetHandler

    • BeanHandler() 查询一条记录封装到JavaBean对象
    • BeanListHandler() 查询多条记录封装到List list
    • ScalarHandler() 封装单个记录的 eg:统计数量
    • ColumnListHandler() 封装单列多行记录
    • MapHandler() 查询一条记录封装到Map对象
    • MapListHandler() 查询多条记录封装到List list
    • ArrayHandler() 查询一条记录封装到数组中

    原理: 使用了反射+内省

  3. 注意实现

    封装到JavaBean条件, 查询出来的数据的列名必须和JavaBean属性一致

2 自定义DBUtils

​ 我们要自定义DBUtils, 就需要知道列名, 参数个数等, 这些可以通过数据库的元数据库进行获得.元数据在建立框架和架构方面是特别重要的知识,我们可以使用数据库的元数据来创建自定义JDBC工具包, 模仿DBUtils.

2.1 什么是元数据

​ 元数据(MetaData),即定义数据的数据。打个比方,就好像我们要想搜索一首歌的歌词(歌词本身是数据),而我们可以通过歌名,作者,专辑等信息来搜索,那么这些歌名,作者,专辑等等就是这首歌的元数据。因此数据库的元数据就是一些注明数据库信息的数据。

歌曲:aa

作词:bb

演唱: cc

时长: dd

​ 简单来说: 数据库的元数据就是 数据库、表、列的定义信息。

​ ① 由PreparedStatement对象的getParameterMetaData ()方法获取的是ParameterMetaData对象。

② 由ResultSet对象的getMetaData()方法获取的是ResultSetMetaData对象。

2.1.1 ParameterMetaData

概述

​ ParameterMetaData是由preparedStatement对象通过getParameterMetaData方法获取而来,ParameterMetaData可用于获取有关PreparedStatement对象和其预编译sql语句 中的一些信息. eg:参数个数,获取指定位置占位符的SQL类型

img

​ 获得ParameterMetaData:

`ParameterMetaData parameterMetaData =  preparedStatement.getParameterMetaData ()`

2.1.2 ParameterMetaData相关的API

  • int getParameterCount(); 获得参数个数
  • int getParameterType(int param) 获取指定参数的SQL类型。 (注:MySQL不支持获取参数类型)

实例代码

package com.hashnode.test;

import com.hashnode.utils.C3P0Utils;

import java.sql.Connection;
import java.sql.ParameterMetaData;
import java.sql.PreparedStatement;

public class Test1_参数元数据 {
    
    
    public static void main(String[] args) throws Exception{
    
    
        /*
            ParameterMetaData类:
                概述: 是一个参数元数据类,可以用来获取参数的元数据
                使用:
                    1.获取参数元数据类对象
                        PreparedStatement对象调用getParameterMetaData()方法
                    2.获取参数的元数据
                        ParameterMetaData相关的API
                            - int getParameterCount(); 获得参数个数
                            - int getParameterType(int param) 获取指定参数的SQL类型。 (注:MySQL不支持获取参数类型)

         */
        // 1.获取连接
        Connection connection = C3P0Utils.getConnection();

        // 2.预编译sql语句
        String sql = "select * from user where username = ? and password = ?";
        PreparedStatement ps = connection.prepareStatement(sql);

        // 3.通过PreparedStatement对象获取参数元数据对象
        ParameterMetaData pmd = ps.getParameterMetaData();// 参数元数据对象

        // 4.获取参数个数元数据   参数个数就是参数的元数据
        int count = pmd.getParameterCount();
        System.out.println("sql语句的参数个数:"+count);// 2

        // 5.获取参数类型元数据  参数类型也是参数的元数据  MySQL不支持获取参数类型
//        int parameterType = pmd.getParameterType(1);
//        System.out.println(parameterType);

//        String typeName = pmd.getParameterTypeName(1);
//        System.out.println(typeName);

    }
}

2.1.3 ResultSetMetaData

概述

​ ResultSetMetaData是由ResultSet对象通过getMetaData方法获取而来,ResultSetMetaData可用于获取有关ResultSet对象中列的类型和属性的信息。

img

​ 获得ResultSetMetaData:

`ResultSetMetaData resultSetMetaData =  resultSet.getMetaData()`

2.1.3.1 resultSetMetaData 相关的API

  • getColumnCount(); 获取结果集中列项目的个数
  • getColumnName(int column); 获得数据指定列的列名
  • getColumnTypeName();获取指定列的SQL类型
  • getColumnClassName();获取指定列SQL类型对应于Java的类型

实例代码

     public class Test2_结果集元数据 {
    
    
    public static void main(String[] args) throws Exception {
    
    
        /*
            ResultSetMetaData类:
                概述:是一个结果集元数据类,可以用来获取结果集的元数据
                使用:
                    1.获取结果集元数据类的对象
                        ResultSet的对象调用getMetaData()方法
                    2.获取结果集的元数据
                        ResultSetMetaData 相关的API
                        - getColumnCount(); 获取结果集中列项目的个数
                        - getColumnName(int column); 获得数据指定列的列名
                        - getColumnTypeName();获取指定列的SQL类型
                        - getColumnClassName();获取指定列SQL类型对应于Java的类型

         */
        // 1.获取连接
        Connection connection = C3P0Utils.getConnection();

        // 2.预编译sql语句
        String sql = "select * from user where username = ? and password = ?";
        PreparedStatement ps = connection.prepareStatement(sql);

        // 3.设置参数
        ps.setString(1, "zs");
        ps.setString(2, "123456");

        // 4.执行sql语句
        ResultSet resultSet = ps.executeQuery();

        // 5.获取结果集的元数据对象
        ResultSetMetaData rsmd = resultSet.getMetaData();

        // 1.获取列的数量
        int columnCount = rsmd.getColumnCount();
        System.out.println("列的个数:" + columnCount);//4

        // 2.获取列的名字
        for (int i = 1; i <= columnCount; i++) {
    
    
            System.out.println(rsmd.getColumnName(i));
        }
        System.out.println("==================================");
        // 3.获取列的MySQL类型
        for (int i = 1; i <= columnCount; i++) {
    
    
            System.out.println(rsmd.getColumnTypeName(i));
        }
        System.out.println("==================================");


        // 4.获取列在Mysql中的类型对应于java中的类型
        for (int i = 1; i <= columnCount; i++) {
    
    
            System.out.println(rsmd.getColumnClassName(i));
        }
    }
}

小结

  1. 元数据: 描述数据的数据. mysql元数据: 用来定义数据库, 表 ,列信息的 eg: 参数的个数, 列的个数, 列的类型…
  2. mysql元数据:
    • ParameterMetaData
    • ResultSetMetaData

2.2 自定义DBUtils增删改

需求

  • 模仿DBUtils, 完成增删改的功能

分析

  1. 创建MyQueryRunner类, 定义dataSource, 提供有参构造方法
  2. 定义int update(String sql, Object…params)方法

0.非空判断
1.从dataSource里面获得connection
2.根据sql语句创建预编译sql语句对象
3.获得参数元数据对象, 获得参数的个数
4.遍历, 从params取出值, 依次给参数? 赋值
5.执行
6.释放资源

实现

public class MyQueryRunner {
    
    

    private DataSource dataSource;

    public MyQueryRunner(DataSource dataSource) {
    
    
        this.dataSource = dataSource;
    }

    public MyQueryRunner() {
    
    
    }

    /**
     * 增删改的方法
     * @param sql
     * @param args
     * @return rows
     */
    public int update(String sql,Object... args) throws Exception{
    
    
        // 非空判断
        // 连接池为空
        if (dataSource == null){
    
    
            throw new RuntimeException("连接池不能为null");
        }

        if (sql == null){
    
    
            throw  new RuntimeException("sql语句不能为空");
        }

         // 1.获得连接
        Connection connection = dataSource.getConnection();

        // 2.预编译sql语句
        PreparedStatement ps = connection.prepareStatement(sql);

        // 3.设置参数
        // 3.1 获得参数元数据类的对象
        ParameterMetaData pmd = ps.getParameterMetaData();

        // 3.2 根据参数元数据类的对象,获取参数个数(元数据)
        int count = pmd.getParameterCount();

        // 3.3 给参数赋值
        for (int i = 0; i < count; i++) {
    
    
            ps.setObject(i+1,args[i]);
        }

        // 4.执行sql语句
        int rows = ps.executeUpdate();

        // 5.释放资源
        C3P0Utils.release(null,ps,connection);

        // 6.返回影响的行数
        return  rows;
    }
}

猜你喜欢

转载自blog.csdn.net/Learning_xzj/article/details/125024889