JDBC03——数据库连接池、DButils、mysql表和JavaBean的数据类型映射关系

基本介绍

问题引出

  • 连接5000次数据库

1.不即时关闭连接——抛出异常

package com.recorder.conn;

import com.recorder.jdbcutils.JdbcUtils;
import org.junit.jupiter.api.Test;

/**
 * @author 紫英
 * @version 1.0
 * @discription 数据库连接5000问题
 */
public class ConQuestion {

    @Test
    public void con(){
        for (int i = 0; i < 5000; i++) {

            JdbcUtils.getConnection();
            //做一些工作,比如得到 PreparedStatement ,发送 sql
            // ..........

        }
    }
}

2.及时关闭连接——耗费时间过久

package com.recorder.conn;

import com.recorder.jdbcutils.JdbcUtils;
import org.junit.jupiter.api.Test;

import java.sql.Connection;

/**
 * @author 紫英
 * @version 1.0
 * @discription 数据库连接5000问题
 */
public class ConQuestion {

    @Test
    public void con() {
        long start = System.currentTimeMillis();
        System.out.println("开始连接.....");

        for (int i = 0; i < 5000; i++) {

            Connection connection = JdbcUtils.getConnection();
            //做一些工作,比如得到 PreparedStatement ,发送 sql
            // ..........
            JdbcUtils.close(null,null,connection);

        }
        long end = System.currentTimeMillis();
        System.out.println("传统方式5000 次 耗时=" + (end - start));//传统方式 5000次
    }

}

问题分析

 

 3.就像火车站安检,如果人数过多需要分批进入,一次性涌入会造成混乱。

基本介绍

 

 

 

 放回连接池指Java程序不在对连接池中的链接进行引用,该连接依旧存在。

 

连接池种类

 

C3P0

第一种方式(不推荐)

 public void testC3P0_01() throws Exception {
        //1. 创建一个数据源对象
        ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
        //2. 通过配置文件 jdbc.properties 获取相关连接的信息
        Properties properties = new Properties();
        properties.load(new FileInputStream("src\\jdbc.properties"));
        //读取相关的属性值
        String user = properties.getProperty("user");
        String password = properties.getProperty("password");
        String driver = properties.getProperty("driver");
        String url = properties.getProperty("url");
        //给数据源 comboPooledDataSource 设置相关的参数
        // 注意:连接管理是由 comboPooledDataSource 来管理
        comboPooledDataSource.setDriverClass(driver);
        comboPooledDataSource.setJdbcUrl(url);
        comboPooledDataSource.setUser(user);
        comboPooledDataSource.setPassword(password);
        //设置初始化连接数
        comboPooledDataSource.setInitialPoolSize(10);
        //最大连接数
        comboPooledDataSource.setMaxPoolSize(50);
        //测试连接池的效率, 测试对 mysql 5000 次操作
        long start = System.currentTimeMillis();
        for (int i = 0; i < 5000; i++) {
            Connection connection = comboPooledDataSource.getConnection();
            //这个方法就是从 DataSource 接口 实现的
            //System.out.println("连接 OK");
            connection.close();
        }
        long end = System.currentTimeMillis();
        //c3p0 5000 连接 mysql 耗时=391
        System.out.println("c3p0 5000 连接 mysql 耗时=" + (end - start));

    }

 

第二种方式(推荐——通过XML配置文件)

 

//第二种方式 使用配置文件模板来完成
    // 1. 将 c3p0 提供的 c3p0.config.xml 拷贝到 src 目录下
    // 2. 该文件指定了连接数据库和连接池的相关参数
    @Test
    public void testC3P0_02() throws SQLException {
        ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource("recorder");
        //测试 5000 次连接
         long start = System.currentTimeMillis();
        System.out.println("开始执行....");
        for (int i = 0; i < 5000; i++) {
            Connection connection = comboPooledDataSource.getConnection();
        //System.out.println("连接 OK~");
            connection.close();
        }
        long end = System.currentTimeMillis();
        //c3p0 的第二种方式 耗时=413
        System.out.println("c3p0 的第二种方式(500000) 耗时=" + (end - start));

    }

 

Druid(德鲁伊)

代码演示

可以看出效率还是很高的

package com.recorder.conn;

import com.alibaba.druid.pool.DruidDataSourceFactory;
import org.junit.jupiter.api.Test;

import javax.sql.DataSource;
import java.io.FileInputStream;
import java.sql.Connection;
import java.util.Properties;

/**
 * @author 紫英
 * @version 1.0
 * @discription 德鲁伊连接池
 */
public class Druid {

    @Test
    public void testDruid() throws Exception {

        //1. 加入 Druid jar 包
        // 2. 加入 配置文件 druid.properties , 将该文件拷贝项目的 src 目录
        // 3. 创建 Properties 对象, 读取配置文件
        Properties properties = new Properties();
        properties.load(new FileInputStream("src\\druid.properties"));
        //4. 创建一个指定参数的数据库连接池, Druid 连接池
        DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
        long start = System.currentTimeMillis();
        for (int i = 0; i < 500000; i++) {
            Connection connection = dataSource.getConnection();
            //System.out.println(connection.getClass());
            //System.out.println("连接成功!");
            connection.close();
        }
        long end = System.currentTimeMillis();
        System.out.println("druid 连接池 操作 500000 耗时=" + (end - start));


    }

}
德鲁伊

c3p0

 

将 JdbcUtils 工具类改成 Druid(德鲁伊)实现

package com.recorder.jdbcutils;

import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

/**
 * @author 紫英
 * @version 1.0
 * @discription 基于 druid 数据库连接池的工具类
 */
public class JDBCUtilsByDruid {

    private static DataSource ds;

    //在静态代码块完成 ds 初始化
    static {

        Properties properties = new Properties();
        try {
            properties.load(new FileInputStream("src\\druid.properties"));
            ds = DruidDataSourceFactory.createDataSource(properties);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //编写 getConnection 方法
    public static Connection getConnection() throws SQLException {
        return ds.getConnection();
    }

    //关闭连接,这里注意: 在数据库连接池技术中,close 不是真的断掉连接
    // 而是把使用的 Connection 对象放回连接池,因为这里的connection是上面的return ds.getConnection()得到的
    public static void close(ResultSet set, Statement statement, Connection connection) {
        try {
            //判断是否为空
            if (set != null) {
                set.close();
            }
            if (statement != null) {
                statement.close();
            }
            if (connection != null) {
                connection.close();
            }
        } catch (SQLException e) {
            //将编译异常转成运行异常抛出
            throw new RuntimeException(e);
        }
    }
}

使用德鲁伊工具类:

package com.recorder.jdbcutils;

import org.junit.jupiter.api.Test;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

/**
 * @author 紫英
 * @version 1.0
 * @discription
 */
public class Druid_use {

    @Test
    public void dmlTest(){

        //1.得到链接
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        //2.组织SQL
        String sql = "insert into admin values(?,?)";
        try {
            connection = JDBCUtilsByDruid.getConnection();
            //3.创建preparedstatement对象
            preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setString(1, "admin");
            preparedStatement.setString(2, "666");
            preparedStatement.executeUpdate();
            System.out.println("添加成功");
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            //关闭资源
            //dml语句没有结果集所以写null
            JDBCUtilsByDruid.close(null, preparedStatement, connection);
        }

    }

}

 

 

Apache—DBUtils

问题引出

 

 

 

 

JavaBean

也可以叫domain pojo——指与数据库中表对应的Java类 

代码模拟(土方法实现)

package com.recorder.DBUtils;

/**
 * @author 紫英
 * @version 1.0
 * @discription admin表
 */
public class Admin {

    private String name;
    private String pwd;

    public Admin() {
        //一定要带一个无参构造器,方便底层反射
    }

    @Override
    public String toString() {
        return "Admin{" +
                "name='" + name + '\'' +
                ", pwd='" + pwd + '\'' +
                '}';
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPwd() {
        return pwd;
    }

    public void setPwd(String pwd) {
        this.pwd = pwd;
    }

    public Admin(String name, String pwd) {
        this.name = name;
        this.pwd = pwd;
    }
}
package com.recorder.DBUtils;

import com.recorder.jdbcutils.JDBCUtilsByDruid;
import org.junit.jupiter.api.Test;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;

/**
 * @author 紫英
 * @version 1.0
 * @discription 使用土方法来解决 ResultSet =封装=> Arraylist
 */
public class BeanTest {

    @Test
    public /*ArrayList<Admin>*/ void testSelectToArrayList() {

        System.out.println("使用 druid 方式完成");
        //1. 得到连接
        Connection connection = null;
        //2. 组织一个 sql
        String sql = "select * from admin ";
        PreparedStatement preparedStatement = null;
        ResultSet set = null;
        ArrayList<Admin> list = new ArrayList<>();
        //创建 ArrayList 对象,存放 actor 对象
        //3. 创建 PreparedStatement 对象

        try {
            connection = JDBCUtilsByDruid.getConnection();
            System.out.println(connection.getClass());//运行类型 com.alibaba.druid.pool.DruidPooledConnection preparedStatement = connection.prepareStatement(sql);
            //执行, 得到结果集
            preparedStatement = connection.prepareStatement(sql);
            set = preparedStatement.executeQuery();
            //遍历该结果集
            while (set.next()) {
                String name = set.getString("name");
                String pwd = set.getString("pwd");
                //把得到的 resultset 的记录,封装到 Actor 对象,放入到 list 集合
                list.add(new Admin(name, pwd));
            }
            System.out.println("list 集合数据=" + list);
            for (Admin admin : list) {
                System.out.println("name=" + admin.getName() + "\tpwd= " + admin.getPwd());
            }


        } catch (SQLException e) {
            e.printStackTrace();
        }


    }
}

 

 

DButils实现封装

下载地址:DbUtils – Download Apache Commons DbUtils

 

基本介绍

ResultSetHandler结果集处理类(8个实现类)

QueryRunner核心类:

  1. QueryRunner(DataSource ds) ;传入参数为连接池
  2. update(String sql, Object… params) ,执行dml语句
  3. query(String sql, ResultSetHandler rsh, Object… params) ,执行 select操作

 代码演示

 查询多行(返回一个arraylist——使用 BeanListHandler)

package com.recorder.DBUtils;

import com.recorder.jdbcutils.JDBCUtilsByDruid;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.junit.jupiter.api.Test;

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

/**
 * @author 紫英
 * @version 1.0
 * @discription DBUtils + druid完成数据封装
 */
public class DBUtils_use {

    //使用 apache-DBUtils 工具类 + druid 完成对表的 crud 操作
    @Test
    public void queryManyTest() throws SQLException {
        //1.得到链接(德鲁伊方式)
        Connection connection = JDBCUtilsByDruid.getConnection();
        //2. 使用 DBUtils 类和接口 , 先引入 DBUtils 相关的 jar , 加入到本 Project
        //3. 创建 QueryRunner
        QueryRunner queryRunner = new QueryRunner();
        //4. 执行相关的方法,返回 ArrayList 结果集
        String sql = "select * from admin";
        //说明
        //(1) query 方法就是执行 sql 语句,得到 resultset ---封装到 --> ArrayList 集合中
        //(2) 返回集合
        //(3) connection: 连接
        //(4) sql : 执行的 sql 语句
        //(5) new BeanListHandler<>(Actor.class):再将resultset -> Actor 对象 -> 封装到 ArrayList
        //底层使用反射机制 去获取 Actor 类的属性,然后进行封装
        //(6) 1 就是给 sql 语句中的? 赋值,可以有多个值,因为是可变参数 Object... params
//(7) 底层得到的 resultset、PreparedStatment会在 query关闭 
        List<Admin> admins = queryRunner.query(connection, sql, new BeanListHandler<>(Admin.class));
        System.out.println("输出集合的信息");
        for (Admin admin : admins) {
            System.out.println(admin);
        }
        //释放资源
        JDBCUtilsByDruid.close(null, null, connection);
    }

}

查询单行数据——返回一个对应的Javabean对象(使用BeanHandler)


//使用 apache-DBUtils 工具类 + druid 完成对表的单行数据查询

@Test
public void queryManyTest_single() throws SQLException { //1.得到链接(德鲁伊方式) Connection connection = JDBCUtilsByDruid.getConnection(); //2. 使用 DBUtils 类和接口 , 先引入 DBUtils 相关的 jar , 加入到本 Project //3. 创建 QueryRunner QueryRunner queryRunner = new QueryRunner(); //4. 执行相关的方法,返回 ArrayList 结果集 String sql = "select * from admin where name = 'along'"; Admin admin = queryRunner.query(connection, sql, new BeanHandler<>(Admin.class)); System.out.println("查询到的的信息:" + admin); //释放资源 JDBCUtilsByDruid.close(null, null, connection); }

 

 

查询单行单列(返回一个object对象——使用ScalarHandler)

 //使用 apache-DBUtils 工具类 + druid 完成对表的单行单列数据查询
    @Test
    public void queryManyTest_obj() throws SQLException {
        //1.得到链接(德鲁伊方式)
        Connection connection = JDBCUtilsByDruid.getConnection();
        //2. 使用 DBUtils 类和接口 , 先引入 DBUtils 相关的 jar , 加入到本 Project
        //3. 创建 QueryRunner
        QueryRunner queryRunner = new QueryRunner();
        //4. 执行相关的方法,返回 ArrayList 结果集
        String sql = "select pwd from admin where name = 'along'";

        Object obj = queryRunner.query(connection, sql, new ScalarHandler());
        System.out.println("查询到的的信息:" + obj);

        //释放资源
        JDBCUtilsByDruid.close(null, null, connection);
    }

 

DML语句(返回受影响的行数——使用queryRunner.execute)

 //使用 apache-DBUtils 工具类 + druid 完成对表的DML
    @Test
    public void queryManyTest_dml() throws SQLException {
        //1.得到链接(德鲁伊方式)
        Connection connection = JDBCUtilsByDruid.getConnection();
        //2. 使用 DBUtils 类和接口 , 先引入 DBUtils 相关的 jar , 加入到本 Project
        //3. 创建 QueryRunner
        QueryRunner queryRunner = new QueryRunner();
        //4. 执行相关的方法,返回 ArrayList 结果集
        String sql = "update admin set pwd = ? where name = ?";
        //String sql = "delete from admin  where name = ?";
        //String sql = "insert into admin values(?,?)";

        int i = queryRunner.update(connection, sql, "alonggiao", "along");
        System.out.println(i > 0 ? i + "行更新成功" : "表未受影响");

        //释放资源
        JDBCUtilsByDruid.close(null, null, connection);
    }

 

 

源码分析

 queryRunner.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");
        } else if (sql == null) {
            if (closeConn) {
                this.close(conn);
            }

            throw new SQLException("Null SQL statement");
        } else if (rsh == null) {
            if (closeConn) {
                this.close(conn);
            }

            throw new SQLException("Null ResultSetHandler");
        } else {
            PreparedStatement stmt = null;  //定义PreparedStatement
            ResultSet rs = null; 用于接收返回的ResultSet
            Object result = null; 作为返回值的ArrayList

            try {
                stmt = this.prepareStatement(conn, sql); 创建PreparedStatement
                this.fillStatement(stmt, params); 对sql语句的占位符(?)进行赋值
                rs = this.wrap(stmt.executeQuery()); 执行sql语句,返回ResultSet
                result = rsh.handle(rs); 将返回的resultset封装到 arraylist【result】(使用反射对传入的class对象进行处理)
            } catch (SQLException var33) {
                this.rethrow(var33, sql, params);
            } finally {
                try {
                    this.close(rs); 关闭resultset
                } finally {
                    this.close(stmt); 关闭preparedstatement
                    if (closeConn) {
                        this.close(conn);
                    }
                }
            }

            return result;
        }
    }

 

 

 

mysql表和JavaBean的数据类型映射关系

主要可以分为:数值型、字符型和日期型

  • 数值型使用对用的包装类
  • 字符型对应String
  • 日期使用java.util包下面的Date类型

posted @ 2022-02-20 23:00  紫英626  阅读(118)  评论(0编辑  收藏  举报

紫英