Java-数据库连接池

强保臣
2023-12-01

传统连接获取Connection存在的问题

1)传统的JDBC数据库连接使用DriverManager来获取,每次向数据库建立连接都需要将Connection加载到内存中,再验证IP地址、用户名和密码,频繁的进行数据库连接操作将占用非常多的系统资源,容易造成服务器崩溃;

2)数据库连接使用完后都必须断开连接释放资源,如果程序出现异常而未能关闭,将导致数据库内存泄漏,最终导致重启数据库;

3)传统获取连接的方式 不能控制创建的连接数量,如果连接过多也可能导致内存泄漏致使MySQL数据库崩溃;

4)解决传统开发中的数据库连接问题可以采用数据库连接池技术(connection pool)。

 数据库连接池基本介绍

1)预先在缓冲池中放入一定数量的链接,当需要建立数据库连接时,只需要从“缓冲池”中取出,使用完毕后再“放回”;

2)数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是重新建立;

3)当应用程序向连接池请求的连接数量超过最大连接数量时,这些请求将被加入到等待队列中。

通过连接池链接数据库步骤

1)从连接池取出连接;

2)使用链接,操作SQL语句;

3)连接放回连接池(程序对连接的引用断开,连接依然可以重复使用)。

如果当前连接都被占用,则新的待连接程序进入等待队列。

数据库连接池种类

1)JDBC的数据库连接池使用 javax.sql.DataSource来表示,DataSource只是一个接口,该接口通常由第三方提供实现;

2)C3P0数据库连接池,速度相对较慢但是稳定性比较好(hibernate,spring都采用该连接池);

3)DBCP数据库连接池,速度相对C3P0较快,但稳定性较差;

4)Proxool数据库连接池,有监控链接池状态的功能,稳定性相对于C3P0差一些;

5)BoneCP数据库连接池,速度快;

6)Druid(德鲁伊)是Alibaba提供的数据库连接池,集DBCP、C3P0、Proxool优点于一身的数据库连接池。

C3P0测试代码

package com.pero.datasource;

import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.junit.Test;

import java.beans.PropertyVetoException;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;

/**
 * @author Pero
 * @version 1.0
 * @title: C3P0_
 * @date 2022/10/28  22:48
 */

public class C3P0_ {

    //使用方法一:在程序中指定相关参数(user、url、password)
    @Test
    public void testC3P0_01() throws IOException, PropertyVetoException, SQLException {
        //1.创建数据源对象
        ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
        //2.通过配置文件mysql.properties获取相关信息
        Properties properties = new Properties();
        properties.load(new FileInputStream("src\\mysql.properties"));
        //3.获取相关属性
        String user = properties.getProperty("user");
        String password = properties.getProperty("password");
        String url = properties.getProperty("url");
        String driver = properties.getProperty("driver");
        //4.给数据源comboPooledDataSource设置相关参数(连接管理交给数据源comboPooledDataSource)
        comboPooledDataSource.setDriverClass(driver);   //设置连接数据库驱动
        comboPooledDataSource.setJdbcUrl(url);
        comboPooledDataSource.setUser(user);
        comboPooledDataSource.setPassword(password);
        //5.设置初始化连接数和连接数上限
        comboPooledDataSource.setInitialPoolSize(10);   //初始化连接数
        comboPooledDataSource.setMaxPoolSize(50);   //连接数上线
        //6.获取链接
        long start = System.currentTimeMillis();
        for (int i = 0; i < 5000; i++) {
            Connection connection = comboPooledDataSource.getConnection();
            connection.close();
        }
        long end = System.currentTimeMillis();
        System.out.println("连接数据库5000次用时:" + (end - start));
    }

    //使用方法二:使用配置文件模板来完成
    @Test
    public void testC3P0_02() throws SQLException {
        //1.先导入c3p0-config.xml文件src目录下
        //2.该文件指定了连接数据库和连接池的相关参数
        ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource("myc3p0");
        long start = System.currentTimeMillis();
        for (int i = 0; i < 5000; i++) {
            Connection connection = comboPooledDataSource.getConnection();
            connection.close();
        }
        long end = System.currentTimeMillis();
        System.out.println("连接数据库5000次耗时:" + (end - start));
    }
}
<c3p0-config>
    <named-config name="myc3p0">

        <!-- 驱动类 -->
        <property name="driverClass">com.mysql.jdbc.Driver</property>
        <!-- url -->
        <property name="jdbcUrl">jdbc:mysql://127.0.0.1:3306/pero_db01</property>
        <!-- 用户名 -->
        <property name="user">root</property>
        <!-- 密码 -->
        <property name="password">pero</property>
        <!-- 每次增长的连接数 -->
        <property name="acquireIncrement">5</property>
        <!-- 初始连接数 -->
        <property name="initialPoolSize">10</property>
        <!-- 最小连接数 -->
        <property name="minPoolSize">5</property>
        <!-- 最大连接数 -->
        <property name="maxPoolSize">50</property>

        <!-- 可连接的最多的命令对象数 -->
        <property name="maxStatements">5</property>

        <!-- 每个连接对象可连接的最多的命令对象数 -->
        <property name="maxStatementsPerConnection">2</property>

    </named-config>
</c3p0-config>

Druid测试代码

package com.pero.datasource;

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

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

/**
 * @author Pero
 * @version 1.0
 * @title: Druid_
 * @date 2022/10/28  22:57
 */

public class Druid_ {
    //添加Druid的jar包和相关配置文件
    @Test
    public void testDruid() throws Exception {
        //创建properties对象,读取配置文件
        Properties properties = new Properties();
        properties.load(new FileInputStream("src\\druid.properties"));
        //创建指定参数的数据库连接池(德鲁伊连接池)
        DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
        long start = System.currentTimeMillis();
        //建立连接
        for (int i = 0; i < 5000; i++) {
            Connection connection = dataSource.getConnection();
            connection.close();
        }
        long end = System.currentTimeMillis();
        System.out.println("数据库连接耗时:" + (end - start));
    }
}
#key=value
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/pero_db01?rewriteBatchedStatements=true
#url=jdbc:mysql://127.0.0.1:3306/pero_db01
username=root
password=pero
#initial connection size
initialSize=10
#min idle connection size
minIdle=5
#max active connection size
maxActive=20
#max wait time (5000 mil seconds)
maxWait=5000

德鲁伊工具类

package com.pero.datasource;

import com.alibaba.druid.pool.DruidDataSourceFactory;
import com.mysql.jdbc.ResultSetRow;
import com.sun.corba.se.spi.ior.IdentifiableFactory;

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

/**
 * @author Pero
 * @version 1.0
 * @title: JDBCUtilsByDruid
 * @date 2022/10/29  22:33
 */

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) {
            throw new RuntimeException(e);
        }
    }

    //获取connection
    public static Connection getConnection() throws SQLException {
        return ds.getConnection();
    }

    //关闭资源,将连接放回连接池
    public void close(ResultSet resultSet, Statement statement, Connection connection){
        try {
            if (resultSet != null){
                resultSet.close();
            }
            if (statement != null){
                statement.close();
            }
            if (connection != null){
                connection.close();
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }
}

测试代码

package com.pero.datasource;

import org.junit.Test;

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

/**
 * @author Pero
 * @version 1.0
 * @title: JDBCUtilsByDruid_Use
 * @date 2022/10/29  23:30
 */

public class JDBCUtilsByDruid_Use {
    @Test
    public void testUseDruid(){
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        String sql = "insert into admin values (?,?)";

        try {
            connection = JDBCUtilsByDruid.getConnection();    //com.alibaba.druid.pool.DruidPooledConnection
            preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setString(1,"pero");
            preparedStatement.setInt(2,951357);
            preparedStatement.executeUpdate();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            JDBCUtilsByDruid.close(null,preparedStatement,connection);
        }
    }

    @Test
    public void testSelect(){
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        String sql = "select * from admin";

        try {
            connection = JDBCUtilsByDruid.getConnection();
            preparedStatement = connection.prepareStatement(sql);
            resultSet = preparedStatement.executeQuery();
            while(resultSet.next()){
                String name = resultSet.getString("name");
                int password = resultSet.getInt("password");
                System.out.println(name + "\t" + password);
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            JDBCUtilsByDruid.close(resultSet,preparedStatement,connection);
        }

    }
}

Apache-DBUtils

问题分析

1)关闭connection后,resultSet结果集无法使用;

2)resultSet不利于数据管理

3)示意图

MySQL数据库

java程序

1.得到链接

2.发送SQL指令

意义:

相当于将表中的数据信息与ArrayList集合相对应的保存

返回resultSet

存在问题

1.结果集和connection是关联的,如果关闭连接则不能再使用结果集;

2.结果集不利于数据管理【只能使用一次】;

3.使用返回信息不方便。

将结果集记录,封装到ArrayList<数据表类名>
数据表信息

Java类==>(JavaBean,PoJO,Domain)

class Test {

        //属性

        private int id;

        private String name;

        ...

        //无参构造器

        //带参构造器

        //Getter And Setter

}

一个表数据对象对应一条表记录,表对象放入到ArrayList集合

方法演示测试代码

package com.pero.datasource;

import org.junit.Test;

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

/**
 * @author Pero
 * @version 1.0
 * @title: JDBCUtilsByDruid_Use
 * @date 2022/10/29  23:30
 */

public class JDBCUtilsByDruid_Use {

    //将ResultSet封装到ArrayList集合中
    @Test
    public void testSelectToArrayList() {
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        String sql = "select * from admins";
        ArrayList<Admins> adminsArrayList = new ArrayList<>();
        try {
            connection = JDBCUtilsByDruid.getConnection();
            preparedStatement = connection.prepareStatement(sql);
            resultSet = preparedStatement.executeQuery();
            while (resultSet.next()) {
                int id = resultSet.getInt("id");
                String user_name = resultSet.getString("user_name");
                String password = resultSet.getString("password");
                //把得到的resultSet信息封装到Admins对象,然后放入到ArrayList集合中
                Admins admins = new Admins(id, user_name, password);
                adminsArrayList.add(admins);
            }
            for (Admins admins : adminsArrayList) {
                System.out.println(admins.getId() + "\t" + admins.getName() +
                        "\t" + admins.getPassword());
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            JDBCUtilsByDruid.close(resultSet,preparedStatement,connection);
        }
        //因为ArrayList与connection没有任何关联,该集合可以复用
        //return list;
    }
}
package com.pero.datasource;

/**
 * @author Pero
 * @version 1.0
 * @title: Admins
 * @date 2022/10/30  22:02
 */

public class Admins {
    private Integer id;
    private String user_name;
    private String password;

    public Admins() {   //一定要给一个无参构造器【反射需要】
    }

    public Admins(Integer id, String user_name, String password) {
        this.id = id;
        this.user_name = user_name;
        this.password = password;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return user_name;
    }

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

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String toString() {
        return "Admins{" +
                "id=" + id +
                ", user_name='" + user_name + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}

Apache-DBUtils基本介绍

1)commons-dbutils是Apache组织提供的一个开源JDBC工具类库,它是对JDBC的封装,使用dbutils能极大简化jdbc编码的工作量;

DbUtils类

1)QueryRunner类:该类封装了SQL的的执行,并且是线程安全的,可实现增删改查、批处理;

2)使用QueryRunner类实现查询;

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

ArrayHandler:把结果集中的第一行数据转换成对象数组;
ArrayListHandler:把结果集中的每一行数据都转成一个数组,再存放到List中;
BeanHandler:将结果集中的第一行数据封装到一个对应的JavaBean实例中;
BeanListHandler:将结果集中的每一行数据都封装到一个对应的JavaBean实例中,存放到List中;
ColumnListHandler:将结果集中某一列的数据存放到List中;
KeyedHandler(name):将结果集中的每一行数据都封装到一个Map里(List<Map>),再把这些map再存到一个map里,其key为指定的列;
MapHandler:

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

MapListHandler:将结果集中的每一行数据都封装到一个Map中,然后再存放到List中;
ScalarHandler:获取结果集中第一行数据指定列的值,常用来进行单值查询。

测试代码1

package com.pero.datasource;

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;
import org.junit.Test;

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

/**
 * @author Pero
 * @version 1.0
 * @title: DBUtils_USE
 * @date 2022/10/31  16:52
 */

public class DBUtils_USE {

    //使用apache-DBUtils 工具类 + druid完成对表的crud操作
    @Test
    //使用apache-dbUtils + druid查询多条语句
    public void testQueryMany() throws SQLException {    //返回结果为多行数据
        //获取链接
        Connection connection = JDBCUtilsByDruid.getConnection();
        String sql = "select * from admins where id >= ?";
        //使用DBUtils类和接口,先引入DBUtils相关jar文件,并导入到该项目中
        //创建QueryRunner
        QueryRunner queryRunner = new QueryRunner();
        //使用queryRunner对象的方法返回ArrayList结果集
        //query()方法通过连接并执行sql语句,得到一个结果集ResultSet并封装到ArrayList集合中,并返回集合
        //connection:连接;
        // sql:执行的sql语句;
        //BeanListHandler查询多条语句
        //new BeanListHandler<>(Admins.class):将ResultSet取出存放到Admins对象中然后封装到ArrayList中
        //Admins.class:底层利用反射机制查看Admins类中有哪些属性,来进行封装操作;
        //1:该位置是可变形参,可以传入多个参数,该参数是给sql语句中的?赋值;
        //ResultSet和PrepareStatement会在query()方法中进行了关闭
        List<Admins> query =
                queryRunner.query(connection, sql, new BeanListHandler<>(Admins.class), 1);
        for (Admins admins : query) {
            System.out.println(admins);
        }
        //释放资源
        JDBCUtilsByDruid.close(null,null,connection);
    }

    @Test
    //使用apache-dbUtils + druid查询一条语句
    public void testQuerySingle() throws SQLException {
        Connection connection = JDBCUtilsByDruid.getConnection();
        String sql = "select * from admins where id = ?";
        QueryRunner queryRunner = new QueryRunner();
        //查询单行记录,返回单个对象,使用的Handler是BeanHandler
        Admins query =
                queryRunner.query(connection, sql, new BeanHandler<>(Admins.class), 1);
        System.out.println(query);
        JDBCUtilsByDruid.close(null,null,connection);
    }

    //使用apache-dbUtils + druid 查询单行单列-返回一个Object对象
    @Test
    public void testScalar() throws SQLException {
        Connection connection = JDBCUtilsByDruid.getConnection();
        QueryRunner queryRunner = new QueryRunner();
        String sql = "select user_name from admins where id = ?";
        Object object = queryRunner.query(connection, sql, new ScalarHandler<>(), 3);
        System.out.println(object);
        JDBCUtilsByDruid.close(null,null,connection);
    }

    //使用apache-dbUtils + druid 完成DML(delete、insert、update)
    @Test
    public void testDML() throws SQLException {
        Connection connection = JDBCUtilsByDruid.getConnection();
        QueryRunner queryRunner = new QueryRunner();
        String sql_update = "update admins set password = ? where user_name = ?";
        String sql_insert = "insert into admins values (null,?,?)";
        String sql_delete = "delete from admins where id = ?";
        //执行DML操作调用queryRunner的update()方法,返回值为受影响的行数
        //int affectedRow = queryRunner.update(connection, sql_update, 213546, "jack0");
        //int affectedRow01 = queryRunner.update(connection, sql_insert, "lucy", 123456);
        int affectedRow02 = queryRunner.update(connection, sql_delete, 5);
        //System.out.println(affectedRow > 0 ? "成功" : "执行没有影响到表");
        //System.out.println(affectedRow01 > 0 ? "执行成功" : "执行没有影响到表");
        System.out.println(affectedRow02 > 0 ? "执行成功" : "执行结果没有影响到表");
        JDBCUtilsByDruid.close(null,null,connection);
    }
}

源码分析

private <T> T query(Connection conn/*连接对象*/, boolean closeConn/*是否关闭连接*/, String sql/*sql命令*/, ResultSetHandler<T> rsh/*结果集的对象的集合*/, Object... params/*sql命令中对应?位置的值*/) throws SQLException {

        if (conn == null) {    //判断传入的连接对象是否为null,如果为null抛出Null connection连接异常
            throw new SQLException("Null connection");
        } else if (sql == null) {    //判断语句是否为空,如果为空则进行下一组判断
            if (closeConn) {    //判断closeConn是否为true,如果为true则关闭连接
                this.close(conn);
            }

            throw new SQLException("Null SQL statement");    //抛出Null SQL statement异常
        } else if (rsh == null) {    //判断接收的集合对象是否为null
            if (closeConn) {    //判断closeConn是否为true,如果为true则关闭连接
                this.close(conn);
            }

            throw new SQLException("Null ResultSetHandler");    //抛出Null ResultSetHandler异常
        } else {
            PreparedStatement stmt = null;    //定义preparedStatement、ResultSet、T引用
            ResultSet rs = null;
            T result = null;        

            try {
                stmt = this.prepareStatement(conn, sql);    //将preparedStatement对象传给stmt
                this.fillStatement(stmt, params);        //将params的值赋值给预处理对象stat中sql语句的问号
                rs = this.wrap(stmt.executeQuery());        //执行sql语句返回结果集,并将结果集resultSet对象经过处理后传给rs
                result = rsh.handle(rs);        //将结果集经过处理(使用到了反射机制获取Admins类中的信息对结果集进行封装)传入rsh(ArrayList集合)并指向result引用
            } catch (SQLException var33) {
                this.rethrow(var33, sql, params);    //异常抛出
            } finally {    //资源关闭
                try {
                    this.close(rs); 
                } finally {
                    this.close(stmt);
                    if (closeConn) {
                        this.close(conn);
                    }

                }
            }

            return result;    //返回结果
        }
    }

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

int,double等类型在Java中都必须用包装类,因为mysql中的所有类型都可能是null,而Java中只有引用类型才有null值;

JavaBean
int(11)Integer
varchar(32),char(1)String
doubleDouble
dateDate

BasicDAO(date access object数据访问对象)

apache-dbutils + Druid 虽然简化了JDBC开发,但依旧存在着不足:

1)SQL语句是固定的,不能通过参数传入,通用性不足,进行改进以便更好执行增删改查命令;

2)对于select操作,如果有返回值,则返回类型不能固定,需要使用泛型;

3)对于众多的数据表和复杂的业务需求,不可能只靠一个Java类来完成;

4)BasicDAO示意图:

TestDAO

1.根据业务需求使用对应的DAO;

2.职能划分各司其职,业务设计清晰。

调↓用

AppView

1.界面层;

2.调用service层的相关类,得到结果显示数据。

调↓用

ActorService/GoodsService/OrderService

1.业务层;

2.组织sql命令,并调用相应的XxxDAO,完成综合需求。

调↓用

DAO

                BasicDAO

1.将各类DAO共同的代码归类到BasicDAO;

2.简化代码,提高维护性和可读性。

继↑承

ActorDAO

完成对actor表的增删改查操作

可以有特有操作

GoodsDAO

完成对goods表的增删改查操作

可以有特有操作

OrderDAO

完成对order表的增删改查操作

可以有特有操作

操↓作操↓作操↓作
MySQL
actor表goods表order表
关↑联关↑联关↑联
JavaBean
Actor类  [JavaBean,domain,pojo]Goods类 [JavaBean,domain,pojo]Order类  [JavaBean,domain,pojo]

基本介绍

1)通用类BasicDAO是专门与数据库交互的,用以完成对数据库(表)的增删改查操作;

2)在BasicDAO的基础上实现一张表对应一个DAO,例如Actor表-Actor.java类(JavaBean)-ActorDAO.java。

BasicDAO应用设计

1)创建com.pero.dao_包;

2)在com.pero.dao_包下创建utils工具包,存放工具类;

 JDBCUtilsByDruid类

package com.pero.dao_.utils;

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 Pero
 * @version 1.0
 * @title: JDBCUtilsByDruid
 * @date 2022/10/29  22:33
 */

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) {
            throw new RuntimeException(e);
        }
    }

    //获取connection
    public static Connection getConnection() throws SQLException {
        return ds.getConnection();
    }

    //关闭资源,将连接放回连接池
    public static void close(ResultSet resultSet, Statement statement, Connection connection){
        try {
            if (resultSet != null){
                resultSet.close();
            }
            if (statement != null){
                statement.close();
            }
            if (connection != null){
                connection.close();
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }
}

3)在com.pero.dao_包下创建domain包,存放JavaBean文件;

Actor类

package com.pero.dao_.domain;

import java.util.Date;

/**
 * @author Pero
 * @version 1.0
 * @title: Actor
 * @date 2022/11/5  17:25
 */

public class Actor {

    /**
     *  数据库中actor表的列属性
     */
    private Integer id;
    private String name;
    private String sex;
    private Date date;
    private Integer phone;

    /**
     * 空构造器,方便反射使用
     */
    public Actor() {
    }

    /**
     * 全属性构造器
     */
    public Actor(Integer id, String name, String sex, Date date, Integer phone) {
        this.id = id;
        this.name = name;
        this.sex = sex;
        this.date = date;
        this.phone = phone;
    }

    /**
     * Setter and Getter
     */
    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public Date getDate() {
        return date;
    }

    public void setDate(Date date) {
        this.date = date;
    }

    public Integer getPhone() {
        return phone;
    }

    public void setPhone(Integer phone) {
        this.phone = phone;
    }

    /**
     * toString
     */
    @Override
    public String toString() {
        return "Actor{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", sex='" + sex + '\'' +
                ", date=" + date +
                ", phone=" + phone +
                '}';
    }
}

4)在com.pero.dao_包下创建dao包,存放XxxDAO和BasicDAO类;

BasicDAO类

package com.pero.dao_.dao;

import com.pero.datasource.JDBCUtilsByDruid;
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;

import javax.lang.model.element.VariableElement;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;

/**
 * @author Pero
 * @version 1.0
 * @title: BasicDAO
 * @date 2022/11/5  17:48
 */

public class BasicDAO<T> {  //指定具体类型

    private QueryRunner queryRunner = new QueryRunner();
    Connection connection = null;

    /*
     * 功能描述: <增删改操作>
     * <>
     * @Param: [sql,parameters]
     * @Return: int
     * @Author: pero
     * @Date: 2022/11/6 12:41
     */
    public int update(String sql, Object...parameters){

        try {
            connection = JDBCUtilsByDruid.getConnection();
            int update = queryRunner.update(connection,sql, parameters);
            return update;
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            JDBCUtilsByDruid.close(null,null,connection);
        }
    }

    /*
     * 功能描述: <返回多个对象(多行查询结果),针对任意表>
     * <end>
     * @Param: [sql, clazz, parameters]
     * @Return: java.util.List<T>
     * @Author: pero
     * @Date: 2022/11/5 20:27
     */
    public List<T> queryMultiply(String sql, Class<T> clazz, Object... parameters){
        try {
            connection = JDBCUtilsByDruid.getConnection();
            return queryRunner.query(connection, sql, new BeanListHandler<T>(clazz), parameters);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            JDBCUtilsByDruid.close(null,null,connection);
        }
    }

    /*
     * 功能描述: <查询单行结果>
     * <end>
     * @Param: [sql, clazz, parameters]
     * @Return: T
     * @Author: pero
     * @Date: 2022/11/5 20:45
     */
    public T querySingle(String sql, Class<T> clazz, Object...parameters){
        try {
            connection = JDBCUtilsByDruid.getConnection();
            return queryRunner.query(connection, sql, new BeanHandler<T>(clazz), parameters);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            JDBCUtilsByDruid.close(null,null,connection);
        }
    }

    /*
     * 功能描述: <查询单行单列的方法,返回单值>
     * <>
     * @Param: [sql,parameters]
     * @Return: [Object]
     * @Author: pero
     * @Date: 2022/11/5 20:58
     */
    public Object queryScalar(String sql, Object...parameters){
        try {
            connection = JDBCUtilsByDruid.getConnection();
            return queryRunner.query(connection,sql, new ScalarHandler(), parameters);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            JDBCUtilsByDruid.close(null,null,connection);
        }
    }
}

 ActorDAO类

package com.pero.dao_.dao;

import com.pero.dao_.domain.Actor;

/**
 * @author Pero
 * @version 1.0
 * @title: ActorDAO
 * @date 2022/11/6  12:53
 */

public class ActorDAO extends BasicDAO<Actor>{
    //具有BasicDAO所有的方法
    //根据业务需求编写特有方法

}

5)在com.pero.dao_包下创建test包,存放测试类。

package com.pero.dao_.test;

import com.pero.dao_.dao.ActorDAO;
import com.pero.dao_.domain.Actor;
import org.apache.commons.dbutils.QueryRunner;
import org.junit.Test;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.List;
import java.util.Properties;

/**
 * @author Pero
 * @version 1.0
 * @title: TestDAO
 * @date 2022/11/6  12:55
 */

public class TestDAO {

    //测试actor表的增删改查操作
    @Test
    /*
     * 功能描述: <多行查询>
     * <>
     * @Param: []
     * @Return: void
     * @Author: pero
     * @Date: 2022/11/6 14:18
     */
    public void testActorSelectForMultiply(){
        ActorDAO actorDAO = new ActorDAO();
        List<Actor> actors =
                actorDAO.queryMultiply("select * from actor where id > ?", Actor.class, 3);
        for (Actor actor : actors) {
            System.out.println(actor);
        }
    }

    @Test
    /*
     * 功能描述: <单行查询>
     * <>
     * @Param: []
     * @Return: void
     * @Author: pero
     * @Date: 2022/11/6 14:26
     */
    public void testActorSelectForSingle(){
        ActorDAO actorDAO = new ActorDAO();
        Actor actor =
                actorDAO.querySingle("select * from actor where id = ?", Actor.class, 5);
        System.out.println(actor);
    }

    @Test
    /*
     * 功能描述: <单行单列查询>
     * <>
     * @Param: []
     * @Return: void
     * @Author: pero
     * @Date: 2022/11/6 14:32
     */
    public void testActorSelectForScalar(){
        ActorDAO actorDAO = new ActorDAO();
        Object scalar =
                actorDAO.queryScalar("select name from actor where id = ?", 4);
        System.out.println(scalar);
    }

    @Test
    /*
     * 功能描述: <添加数据>
     * <>
     * @Param: []
     * @Return: void
     * @Author: pero
     * @Date: 2022/11/6 18:16
     */
    public void testActorInsertForUpdate() throws IOException {
        ActorDAO actorDAO = new ActorDAO();
        Properties properties = new Properties();
        properties.load(new FileInputStream("src\\actorFile.properties"));
        String name = properties.getProperty("name");
        String sex = properties.getProperty("sex");
        String borndate = properties.getProperty("borndate");
        String phone = properties.getProperty("phone");
        int update =
                actorDAO.update("insert into actor values (null,?,?,?,?)",name,sex,borndate,phone);
        System.out.println(update > 0 ? "数据添加成功" : "添加操作未对数据库表产生影响");
    }

    @Test
    /*
     * 功能描述: <修改数据>
     * <>
     * @Param: []
     * @Return: void
     * @Author: pero
     * @Date: 2022/11/6 18:57
     */
    public void testActorUpdateForUpdate() throws IOException {
        ActorDAO actorDAO = new ActorDAO();
        Properties properties = new Properties();
        properties.load(new FileInputStream("src\\actorFile.properties"));
        String name = properties.getProperty("name");
        String sex = properties.getProperty("sex");
        String borndate = properties.getProperty("borndate");
        String phone = properties.getProperty("phone");
        int update =
                actorDAO.update("update actor set name = ?, sex = ?, borndate = ?, phone = ? where id = ?", name, sex, borndate, phone, 5);
        System.out.println(update > 0 ? "修改成功" : "操作语句未对表产生影响");
    }

    @Test
    /*
     * 功能描述: <删除指定行数据>
     * <>
     * @Param: []
     * @Return: void
     * @Author: pero
     * @Date: 2022/11/6 19:03
     */
    public void testActorDeleteForUpdate(){
        ActorDAO actorDAO = new ActorDAO();
        int update =
                actorDAO.update("delete from actor where id = ?", 6);
        System.out.println(update > 0 ? "删除成功" : "操作语句未对表产生影响");
    }
}

actorFile.properties

name=marry
sex=woman
borndate=2002-05-31
phone=136656326

 类似资料: