Commons Pool 连接 OceanBase 数据库示例程序

本文将介绍如何使用 Commons Pool、MySQL Connector/J 和 OceanBase 数据库构建一个应用程序,实现基本的数据库操作,包括创建表、插入数据、更新数据、删除数据、查询数据和删除表等。

image.png点击下载 commonpool-mysql-client 示例工程

前提条件

  • 您已安装 OceanBase 数据库并且创建了 MySQL 模式租户。

  • 您已安装 JDK 1.8 和 Maven。

  • 您已安装 Eclipse。

    说明

    本文档运行代码使用的工具是 Eclipse IDE for Java Developers 2022-03 版本,您也可以根据个人喜好选择适合自己的工具运行的示例代码。

操作步骤

说明

本文中给出的操作步骤是在 Windows 环境下使用 Eclipse IDE for Java Developers 2022-03 编译和运行该项目的步骤。如果您使用的是其他操作系统环境或编译器,那么操作步骤可能会略有不同。

  1. commonpool-mysql-client项目导入到 Eclipse 中。

  2. 获取 OceanBase 数据库 URL。

  3. 修改commonpool-mysql-client项目中的数据库连接信息。

  4. 运行commonpool-mysql-client项目。

步骤一:将 commonpool-mysql-client 项目导入到 Eclipse 中

  1. 打开 Eclipse,在菜单栏上选择 File->Open Projects from File System

  2. 在弹出的对话框中,点击 Directory 按钮选择项目所在的目录,然后点击 Finish 完成导入。

    说明

    当使用 Eclipse 导入 Maven 项目时,Eclipse 会自动检测项目中的pom.xml文件,并根据文件中描述的依赖关系自动下载所需的依赖库,并将它们添加到项目中。

    image.png

  3. 查看项目情况。

    image.png

步骤二:获取 OceanBase 数据库 URL

  1. 联系 OceanBase 数据库部署人员或者管理员获取相应的数据库连接串。

    示例如下:

    obclient -hxxx.xxx.xxx.xxx -P3306 -utest_user001 -p****** -Dtest

    更多连接串的信息,请参见 获取连接参数

  2. 根据 OceanBase 数据库连接串信息填写下面 URL 的对应信息。

    jdbc:mysql://$host:$port/$database_name?user=$user_name&password=$password&useSSL=false

    参数说明:

    • $hostOceanBase 数据库连接的域名。

    • $port:OceanBase 数据库连接端口,MySQL 模式租户默认是 3306。

    • $database_name:需要访问的数据库名称。

    • $user_name:租户的连接账号。

    • $password:提供账户密码。

    更多有关 MySQL Connector/J 连接属性信息,请参见 Configuration Properties

    示例如下:

    jdbc:mysql://xxx.xxx.xxx.xxx:3306/test?user=test_user001&password=******&useSSL=false

步骤三:修改 commonpool-mysql-client 项目中的数据库连接信息

根据步骤二:获取 OceanBase 数据库 URL中获取的信息修改文件commonpool-mysql-client/src/main/resources/db.properties中的数据库连接信息。

image.png

示例如下:

  • OBServer 节点的 IP 地址为xxx.xxx.xxx.xxx

  • 访问端口使用的是 3306。

  • 需要访问的数据库名称为test

  • 租户的连接账户是test_user001

  • 密码是******

代码如下:

...
db.url=jdbc:mysql://xxx.xxx.xxx.xxx:3306/test?useSSL=false
db.username=test_user001
db.password=******
...

步骤四:运行 commonpool-mysql-client 项目

  1. 在项目导航器视图中,找到并展开 src/main/java 目录。

  2. 右键点击 Main.java 文件,然后选择 Run As->Java Application

    image.png

  3. 在 Eclipse 的控制台窗口中来查看输出结果。

    image.png

项目代码介绍

点击 commonpool-mysql-client 下载项目代码,是一个名称为commonpool-mysql-client.zip的压缩包。

解压后,得到一个名为commonpool-mysql-client的文件夹。目录结构如下所示:

commonpool-mysql-client
├── src
│   └── main
│       ├── java
│       │   └── com
│       │       └── example
│       │           └── Main.java
│       └── resources
│           └── db.properties
└── pom.xml

文件说明:

  • src:源代码根目录。

  • main:主代码目录,包含应用程序的主要逻辑。

  • java:Java 源代码目录。

  • com:Java 包目录。

  • example:示例项目的包目录。

  • Main.java:主类程序示例文件,包含创建表、插入、删除、更新和查询数据等逻辑。

  • resources:资源文件目录,包含配置文件等。

  • db.properties:连接池的配置文件,包含了数据库连接的相关参数。

  • pom.xml:Maven 项目的配置文件,用于管理项目的依赖和构建设置。

pom.xml 代码介绍

pom.xml文件是 Maven 项目的配置文件,定义了项目的依赖项、插件和构建规则等信息。Maven 是一个 Java 项目管理工具,可以自动下载依赖项、编译和打包项目等操作。

本文pom.xml文件的代码主要包括以下几个部分:

  1. 文件声明语句。

    声明本文件是一个 XML 文件,使用的 XML 版本是1.0,字符编码方式是UTF-8

    代码如下:

    <?xml version="1.0" encoding="UTF-8"?>
  2. 配置 POM 的命名空间和 POM 模型版本。

    1. 通过xmlns指定 POM 的命名空间为http://maven.apache.org/POM/4.0.0

    2. 通过xmlns:xsi指定 XML 命名空间http://www.w3.org/2001/XMLSchema-instance

    3. 通过xsi:schemaLocation指定 POM 的命名空间为http://maven.apache.org/POM/4.0.0和 POM 的 XSD 文件的位置为http://maven.apache.org/xsd/maven-4.0.0.xsd

    4. 通过<modelVersion>元素指定了该 POM 文件使用的 POM 模型版本为4.0.0

    代码如下:

    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
      <modelVersion>4.0.0</modelVersion>
    
     <!-- 其他配置 -->
    
    </project>
  3. 配置基本信息。

    1. 通过<groupId>指定项目所属组织为com.example

    2. 通过<artifactId>指定项目的名称为commonpool-mysql-client

    3. 通过<version>项目的版本号为1.0-SNAPSHOT

    代码如下:

        <groupId>com.example</groupId>
        <artifactId>commonpool-mysql-client</artifactId>
        <version>1.0-SNAPSHOT</version>
  4. 配置项目源文件的属性。

    指定 Maven 的编译器插件为maven-compiler-plugin,并设置了源代码和目标 Java 版本都为 8。这意味着项目的源代码使用 Java 8 特性编写,且编译后的字节码也将兼容 Java 8 运行时环境。这样设置可以确保项目在编译和运行时能够正确地处理 Java 8 的语法和特性。

    说明

    Java 1.8 和 Java 8 是同一个版本的不同命名方式。

    代码如下:

        <build>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <configuration>
                        <source>8</source>
                        <target>8</target>
                    </configuration>
                </plugin>
            </plugins>
        </build>
  5. 配置项目所依赖组件。

    1. 添加mysql-connector-java依赖库,用于与数据库进行交互:

      1. 通过<groupId>指定依赖项所属的组织为mysql

      2. 通过<artifactId>指定依赖项的名称为mysql-connector-java

      3. 通过<version>指定依赖项的版本号为5.1.40

      代码如下:

              <dependency>
                  <groupId>mysql</groupId>
                  <artifactId>mysql-connector-java</artifactId>
                  <version>5.1.40</version>
              </dependency>
    2. 添加commons-pool2依赖库,以便在项目中能够使用该库的功能和类:

      1. 通过<groupId>指定依赖项所属的组织为org.apache.commons

      2. 通过<artifactId>指定依赖项的名称为commons-pool2

      3. 通过<version>指定依赖项的版本号为2.7.0

      代码如下:

              <dependency>
                  <groupId>org.apache.commons</groupId>
                  <artifactId>commons-pool2</artifactId>
                  <version>2.7.0</version>
              </dependency>

db.properties 代码介绍

db.properties是本文示例的连接池配置文件,其中包含了连接池的配置属性。这些属性包括数据库 URL、用户名、密码、连接池其他可选项。

本文db.properties文件的代码主要包括以下几个部分:

  1. 配置数据库连接参数。

    1. 配置数据库连接的 URL,包括主机 IP、端口号、需要访问的数据库。

    2. 配置数据库用户名。

    3. 配置数据库密码。

    代码如下:

    db.url=jdbc:mysql://$host:$port/$database_name?useSSL=false
    db.username=$user_name
    db.password=$password

    参数解释:

    • $hostOceanBase 数据库连接的域名。

    • $port:OceanBase 数据库连接端口,MySQL 模式租户默认是 3306。

    • $database_name:需要访问的数据库名称。

    • $user_name:租户的连接账号。

    • $password:提供账户密码。

  2. 配置其他连接池的参数。

    1. 设置连接池的最大连接数为 10。这表示连接池中最多可以同时拥有 10 个连接。

    2. 设置连接池的最大空闲连接数为 5。当连接池中的连接数量超过最大空闲连接数时,多余的连接将被关闭。

    3. 设置连接池的最小空闲连接数为 2。即使连接池中没有正在使用的连接,也会保持至少 2 个空闲连接。

    4. 设置从连接池获取连接的最大等待时间为 5000 毫秒。如果连接池中没有可用连接,获取连接的操作将会等待,直到超过最大等待时间为止。

    代码如下:

    pool.maxTotal=10
    pool.maxIdle=5
    pool.minIdle=2
    pool.maxWaitMillis=5000
说明

具体的属性(参数)配置取决于项目需求和数据库的特点,建议您根据实际情况进行调整和配置。

Commons Pool 2 常用配置参数:

参数

描述

url

指定连接数据库的 URL 地址,包括数据库类型、主机名、端口号、数据库名称等信息。

username

连接数据库所需的用户名。

password

连接数据库所需的密码。

maxTotal

指定对象池中允许创建的最大对象数量。

maxIdle

指定对象池中允许保持的最大空闲对象数量。

minIdle

指定对象池中保持的最小空闲对象数量。

blockWhenExhausted

指定当对象池耗尽时,对borrowObject操作的行为。

  • trueborrowObject方法将阻塞,直到有可用对象为止。

  • falseborrowObject方法将立即抛出NoSuchElementException异常。

maxWaitMillis

指定borrowObject方法在池耗尽时的最大等待时间(毫秒)。

testOnBorrow

指定在borrowObject方法调用时是否对对象进行验证。

  • true:每次borrowObject方法调用时都会调用对象的validateObject方法进行验证。

  • false:不进行验证。

testOnReturn

指定在returnObject方法调用时是否对对象进行验证。

  • true:每次returnObject方法调用时都会调用对象的validateObject方法进行验证。

  • false:不进行验证。

testWhileIdle

指定当对象处于空闲状态时是否对它们进行验证,具体的含义如下:

  • 当设置为true时,表示在对象池中的空闲对象被借出之前,会定期对它们调用validateObject方法进行验证。此验证操作可确保空闲对象仍然有效可用。

  • 当设置为false时,表示不对空闲对象进行验证,即不会调用validateObject方法。

timeBetweenEvictionRunsMillis

指定空闲对象的驱逐线程调度的时间间隔(毫秒)。

numTestsPerEvictionRun

指定每次驱逐线程调度时要检查的空闲对象数量。

Main.java 代码介绍

Main.java文件是示例程序的一部分,代码演示了如何使用 Commons Pool 2 执行数据库操作。本文Main.java文件的代码主要包括以下几个部分:

  1. 定义包和导入必要的类。

    1. 声明当前代码所属的包名为com.example

    2. 导入java.io.IOException类,用于处理输入输出异常。

    3. 导入java.sql.Connection类,用于表示与数据库的连接。可以使用该对象执行 SQL 语句并获取结果。

    4. 导入java.sql.DriverManager类,用于管理驱动程序的加载和数据库连接的建立。可以使用该类获取数据库连接。

    5. 导入java.sql.ResultSet类,用于表示 SQL 查询的结果集。可以使用该对象遍历和操作查询结果。

    6. 导入java.sql.SQLException类,用于处理 SQL 语句相关的异常情况。

    7. 导入java.sql.Statement类,用于执行 SQL 语句的对象。可以通过Connection对象的createStatement方法创建。

    8. 导入java.util.Properties类,是一个键值对的集合,用于加载和保存配置信息。可以从配置文件中加载数据库的连接信息。

    9. 导入org.apache.commons.pool2.ObjectPool类,是一个对象池接口,定义了池化对象的基本操作,如获取、归还对象等。

    10. 导入org.apache.commons.pool2.PoolUtils类,提供了一些工具方法,用于方便地操作对象池。

    11. 导入org.apache.commons.pool2.PooledObject类,是一种实现了对象池管理的包装对象。可以通过实现该接口来管理池化对象的生命周期。

    12. 导入org.apache.commons.pool2.impl.GenericObjectPool类,是ObjectPool接口的默认实现类,实现了连接池的基本功能。

    13. 导入org.apache.commons.pool2.impl.GenericObjectPoolConfig类,是GenericObjectPool的配置类,用于设置连接池的属性。

    14. 导入org.apache.commons.pool2.impl.DefaultPooledObject类,是PooledObject接口的默认实现类,用于管理池化对象的包装。它可以包含实际的连接对象以及其他一些管理信息。

    代码如下:

    package com.example;
    
    import java.io.IOException;
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.sql.Statement;
    import java.util.Properties;
    
    import org.apache.commons.pool2.ObjectPool;
    import org.apache.commons.pool2.PoolUtils;
    import org.apache.commons.pool2.PooledObject;
    import org.apache.commons.pool2.impl.GenericObjectPool;
    import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
    import org.apache.commons.pool2.impl.DefaultPooledObject;
  2. 创建一个Main类,并定义main方法。

    定义一个Main类和main方法,main方法用于演示如何使用连接池从数据库中执行一系列的操作。具体步骤如下:

    1. 定义一个名为Main的公共类,作为程序的入口点。类名需要与文件名保持一致。

    2. 定义一个公共静态方法main,作为程序的起始执行点。

      1. 加载数据库配置文件:

        1. 创建一个Properties对象,用于存储数据库配置信息。

        2. 通过 Main 类的类加载器获取db.properties资源文件的输入流,并使用Properties对象的load()方法加载该输入流,将属性文件中的键值对加载到props对象中。

        3. 捕获可能抛出的IOException异常,并打印异常堆栈信息。

      2. 创建数据库连接池配置:

        1. 创建一个泛型对象池配置对象,用于配置连接池的行为。

        2. 设置连接池中允许的最大连接数。

        3. 设置连接池中允许的最大空闲连接数。

        4. 设置连接池中允许的最小空闲连接数。

        5. 设置获取连接的最大等待时间。

      3. 创建数据库连接池:创建一个线程安全的连接池对象connectionPool,使用ConnectionFactory对象和poolConfig配置对象来创建泛型对象池,并将其包装在一个线程安全的对象池中。通过对连接池进行线程安全的包装,可以确保在多线程环境下的连接获取和释放操作的安全性。

      4. 获取数据库连接,使用连接池的borrowObject()方法获取一个数据库连接,并在try代码块中使用该连接进行数据库操作。

        1. 调用createTable()方法,创建表。

        2. 调用insertData()方法,插入数据。

        3. 调用selectData()方法,查询数据。

        4. 调用updateData()方法,更新数据。

        5. 再次调用selectData()方法,查询更新后的数据。

        6. 调用deleteData()方法,删除数据。

        7. 再次调用selectData()方法,查询删除后的数据。

        8. 调用dropTable()方法,删除表。

        9. 捕获并打印任何异常。

    3. 定义其他数据库操作方法。

    代码如下:

    public class Main {
    
        public static void main(String[] args) {
            // Load the database configuration file
            Properties props = new Properties();
            try {
                props.load(Main.class.getClassLoader().getResourceAsStream("db.properties"));
            } catch (IOException e) {
                e.printStackTrace();
            }
    
            // Create the database connection pool configuration
            GenericObjectPoolConfig<Connection> poolConfig = new GenericObjectPoolConfig<>();
            poolConfig.setMaxTotal(Integer.parseInt(props.getProperty("pool.maxTotal")));
            poolConfig.setMaxIdle(Integer.parseInt(props.getProperty("pool.maxIdle")));
            poolConfig.setMinIdle(Integer.parseInt(props.getProperty("pool.minIdle")));
            poolConfig.setMaxWaitMillis(Long.parseLong(props.getProperty("pool.maxWaitMillis")));
    
            // Create the database connection pool
            ObjectPool<Connection> connectionPool = PoolUtils.synchronizedPool(new GenericObjectPool<>(new ConnectionFactory(
                    props.getProperty("db.url"), props.getProperty("db.username"), props.getProperty("db.password")), poolConfig));
    
            // Get a database connection
            try (Connection connection = connectionPool.borrowObject()) {
    
                // Create table
                createTable(connection);
    
                // Insert data
                insertData(connection);
                // Query data
                selectData(connection);
    
                // Update data
                updateData(connection);
                // Query the updated data
                selectData(connection);
    
                // Delete data
                deleteData(connection);
                // Query the data after deletion
    
                selectData(connection);
    
                // Drop table
                dropTable(connection);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        // 定义用于创建表的方法
        // 定义用于插入数据的方法
        // 定义用于更新数据的方法
        // 定义用于删除数据的方法
        // 定义用于查询数据的方法
        // 定义用于删除表的方法
        // 定义一个 ConnectionFactory 类
    }
  3. 定义用于创建表的方法。

    定义一个名为createTable的方法,接收一个Connection对象作为参数。具体步骤如下:

    1. 定义一个私有静态方法createTable(),接收一个Connection对象作为参数,并声明可能抛出SQLException异常。

    2. 使用连接的createStatement()方法创建一个Statement对象,并在try-with-resources语句中使用该对象来执行数据库操作。

    3. 定义一个字符串变量sql,存储创建表的 SQL 语句。

    4. 使用Statement对象的executeUpdate()方法执行sql语句,创建表。

    5. 在控制台输出表创建成功的提示信息。

    代码如下:

        private static void createTable(Connection connection) throws SQLException {
            try (Statement statement = connection.createStatement()) {
                String sql = "CREATE TABLE test_commonpool (id INT,name VARCHAR(20))";
                statement.executeUpdate(sql);
                System.out.println("Table created successfully.");
            }
        }
  4. 定义用于插入数据的方法。

    定义一个名为insertData()的方法,接收一个Connection对象作为参数。具体步骤如下:

    1. 定义一个私有静态方法insertData(),接收一个Connection对象作为参数,并声明可能抛出SQLException异常。

    2. 使用连接的createStatement()方法创建一个Statement对象,并在try-with-resources语句中使用该对象来执行数据库操作。

    3. 定义一个字符串变量sql,存储插入数据的 SQL 语句。

    4. 使用Statement对象的executeUpdate()方法执行sql语句,插入数据。

    5. 在控制台输出数据插入成功的提示信息。

    代码如下:

        private static void insertData(Connection connection) throws SQLException {
            try (Statement statement = connection.createStatement()) {
                String sql = "INSERT INTO test_commonpool (id, name) VALUES (1,'A1'), (2,'A2'), (3,'A3')";
                statement.executeUpdate(sql);
                System.out.println("Data inserted successfully.");
            }
        }
  5. 定义用于更新数据的方法。

    定义一个名为updateData()的方法,接收一个Connection对象作为参数。具体步骤如下:

    1. 定义一个私有静态方法updateData(),接收一个Connection对象作为参数,并声明可能抛出SQLException异常。

    2. 使用连接的createStatement()方法创建一个Statement对象,并在try-with-resources语句中使用该对象来执行数据库操作。

    3. 定义一个字符串变量sql,存储更新数据的 SQL 语句。

    4. 使用Statement对象的executeUpdate()方法执行sql语句,更新数据。

    5. 在控制台输出数据更新成功的提示信息。

    代码如下:

        private static void updateData(Connection connection) throws SQLException {
            try (Statement statement = connection.createStatement()) {
                String sql = "UPDATE test_commonpool SET name = 'A11' WHERE id = 1";
                statement.executeUpdate(sql);
                System.out.println("Data updated successfully.");
            }
        }
  6. 定义用于删除数据的方法。

    定义一个名为deleteData()的方法,接收一个Connection对象作为参数。具体步骤如下:

    1. 定义一个私有静态方法deleteData(),接收一个Connection对象作为参数,并声明可能抛出SQLException异常。

    2. 使用连接的createStatement()方法创建一个Statement对象,并在try-with-resources语句中使用该对象来执行数据库操作。

    3. 定义一个字符串变量sql,存储删除数据的 SQL 语句。

    4. 使用Statement对象的executeUpdate()方法执行sql语句,删除数据。

    5. 在控制台输出数据删除成功的提示信息。

    代码如下:

        private static void deleteData(Connection connection) throws SQLException {
            try (Statement statement = connection.createStatement()) {
                String sql = "DELETE FROM test_commonpool WHERE id = 2";
                statement.executeUpdate(sql);
                System.out.println("Data deleted successfully.");
            }
        }
  7. 定义用于查询数据的方法。

    定义一个名为selectData()的方法,接收一个Connection对象作为参数。具体步骤如下:

    1. 定义一个私有静态方法selectData(),接收一个Connection对象作为参数,并声明可能抛出SQLException异常。

    2. 使用连接的createStatement()方法创建一个Statement对象,并在try-with-resources语句中使用该对象来执行数据库操作。

    3. 定义一个字符串变量sql,存储查询数据的 SQL 语句。

    4. 使用Statement对象的executeQuery()方法执行sql语句,并将结果存储在ResultSet对象中。

    5. 使用resultSet.next()方法判断是否还有下一行数据,并进入循环。

    6. 使用resultSet.getInt()方法获取当前行的整型数据,该方法的参数为数据的列名。

    7. 使用resultSet.getString()方法获取当前行的字符串数据,该方法的参数为数据的列名。

    8. 在控制台输出当前行的数据。

    代码如下:

        private static void selectData(Connection connection) throws SQLException {
            try (Statement statement = connection.createStatement()) {
                String sql = "SELECT * FROM test_commonpool";
                ResultSet resultSet = statement.executeQuery(sql);
                while (resultSet.next()) {
                    int id = resultSet.getInt("id");
                    String name = resultSet.getString("name");
                    System.out.println("id: " + id + ", name: " + name);
                }
            }
        }
  8. 定义用于删除表的方法。

    定义一个名为dropTable()的方法,接收一个Connection对象作为参数。具体步骤如下:

    1. 定义一个私有静态方法dropTable(),接收一个Connection对象作为参数,并声明可能抛出SQLException异常。

    2. 使用连接的createStatement()方法创建一个Statement对象,并在try-with-resources语句中使用该对象来执行数据库操作。

    3. 定义一个字符串变量sql,存储删除表的 SQL 语句。

    4. 使用Statement对象的executeUpdate()方法执行sql语句,删除表。

    5. 在控制台输出表删除成功的提示信息。

    代码如下:

        private static void dropTable(Connection connection) throws SQLException {
            try (Statement statement = connection.createStatement()) {
                String sql = "DROP TABLE test_commonpool";
                statement.executeUpdate(sql);
                System.out.println("Table dropped successfully.");
            }
        }
  9. 定义一个ConnectionFactory类。

    定义一个名为ConnectionFactory的静态内部类,继承了BasePooledObjectFactory类,并实现了创建和管理连接对象的方法。具体步骤如下:

    说明

    @Override是一个注解,表示下面的方法是重写父类中的方法。

    1. 定义一个名为ConnectionFactory的静态内部类,继承了org.apache.commons.pool2.BasePooledObjectFactory<Connection>类,用于创建和管理连接对象的工厂类。

    2. 定义一个私有的不可变字符串变量,存储数据库的 URL。

    3. 定义一个私有的不可变字符串变量,存储连接数据库的用户名。

    4. 定义一个私有的不可变字符串变量,存储连接数据库的密码。

    5. 定义ConnectionFactory类的构造函数,用于初始化类的成员变量urlusernamepassword。构造函数接收三个参数,分别是数据库的 URL、连接数据库的用户名和密码,并将这些参数的值分别赋给对应的成员变量。这样,在创建ConnectionFactory对象时,可以通过构造函数传入数据库相关的信息。

    6. 重写了BasePooledObjectFactory类中的create()方法,用于创建一个新的连接对象。

    7. 使用DriverManager类的getConnection()方法创建并返回一个连接对象。

    8. 重写了BasePooledObjectFactory类中的destroyObject()方法,用于销毁连接对象。

    9. 调用连接对象的close()方法关闭连接。

    10. 重写了BasePooledObjectFactory类中的validateObject()方法,用于验证连接对象的有效性。

    11. 调用连接对象的isValid()方法检查连接是否有效,设置超时时间为 5000 毫秒。

    12. 重写了BasePooledObjectFactory类中的wrap()方法,用于将连接对象包装成PooledObject对象。

    13. 使用DefaultPooledObject类的构造函数创建一个PooledObject对象,并将连接对象作为参数传入。

    代码如下:

    static class ConnectionFactory extends org.apache.commons.pool2.BasePooledObjectFactory<Connection> {
            private final String url;
            private final String username;
            private final String password;
    
            public ConnectionFactory(String url, String username, String password) {
                this.url = url;
                this.username = username;
                this.password = password;
            }
    
            @Override
            public Connection create() throws Exception {
                return DriverManager.getConnection(url, username, password);
            }
    
            @Override
            public void destroyObject(org.apache.commons.pool2.PooledObject<Connection> p) throws Exception {
                p.getObject().close();
            }
    
            @Override
            public boolean validateObject(org.apache.commons.pool2.PooledObject<Connection> p) {
                try {
                    return p.getObject().isValid(5000);
                } catch (SQLException e) {
                    return false;
                }
            }
    
            @Override
            public PooledObject<Connection> wrap(Connection connection) {
                return new DefaultPooledObject<>(connection);
            }
        }

完整的代码展示

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example</groupId>
    <artifactId>commonpool-mysql-client</artifactId>
    <version>1.0-SNAPSHOT</version>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>8</source>
                    <target>8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <dependencies>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.40</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
            <version>2.7.0</version>
        </dependency>
    </dependencies>
</project>

db.properties

Database Configuration
db.url=jdbc:mysql://$host:$port/$database_name?useSSL=false
db.username=$user_name
db.password=$password

Connection Pool Configuration
pool.maxTotal=10
pool.maxIdle=5
pool.minIdle=2
pool.maxWaitMillis=5000

Main.java

package com.example;

import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

import org.apache.commons.pool2.ObjectPool;
import org.apache.commons.pool2.PoolUtils;
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.apache.commons.pool2.impl.DefaultPooledObject;

public class Main {

    public static void main(String[] args) {
        // Load the database configuration file
        Properties props = new Properties();
        try {
            props.load(Main.class.getClassLoader().getResourceAsStream("db.properties"));
        } catch (IOException e) {
            e.printStackTrace();
        }

        // Create the database connection pool configuration
        GenericObjectPoolConfig<Connection> poolConfig = new GenericObjectPoolConfig<>();
        poolConfig.setMaxTotal(Integer.parseInt(props.getProperty("pool.maxTotal")));
        poolConfig.setMaxIdle(Integer.parseInt(props.getProperty("pool.maxIdle")));
        poolConfig.setMinIdle(Integer.parseInt(props.getProperty("pool.minIdle")));
        poolConfig.setMaxWaitMillis(Long.parseLong(props.getProperty("pool.maxWaitMillis")));

        // Create the database connection pool
        ObjectPool<Connection> connectionPool = PoolUtils.synchronizedPool(new GenericObjectPool<>(new ConnectionFactory(
                props.getProperty("db.url"), props.getProperty("db.username"), props.getProperty("db.password")), poolConfig));

        // Get a database connection
        try (Connection connection = connectionPool.borrowObject()) {
            
            // Create table
            createTable(connection);

            // Insert data
            insertData(connection);
            // Query data
            selectData(connection);

            // Update data
            updateData(connection);
            // Query the updated data
            selectData(connection);

            // Delete data
            deleteData(connection);
            // Query the data after deletion
            selectData(connection);

            // Drop table
            dropTable(connection);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static void createTable(Connection connection) throws SQLException {
        try (Statement statement = connection.createStatement()) {
            String sql = "CREATE TABLE test_commonpool (id INT,name VARCHAR(20))";
            statement.executeUpdate(sql);
            System.out.println("Table created successfully.");
        }
    }

    private static void insertData(Connection connection) throws SQLException {
        try (Statement statement = connection.createStatement()) {
            String sql = "INSERT INTO test_commonpool (id, name) VALUES (1,'A1'), (2,'A2'), (3,'A3')";
            statement.executeUpdate(sql);
            System.out.println("Data inserted successfully.");
        }
    }

    private static void updateData(Connection connection) throws SQLException {
        try (Statement statement = connection.createStatement()) {
            String sql = "UPDATE test_commonpool SET name = 'A11' WHERE id = 1";
            statement.executeUpdate(sql);
            System.out.println("Data updated successfully.");
        }
    }

    private static void deleteData(Connection connection) throws SQLException {
        try (Statement statement = connection.createStatement()) {
            String sql = "DELETE FROM test_commonpool WHERE id = 2";
            statement.executeUpdate(sql);
            System.out.println("Data deleted successfully.");
        }
    }

    private static void selectData(Connection connection) throws SQLException {
        try (Statement statement = connection.createStatement()) {
            String sql = "SELECT * FROM test_commonpool";
            ResultSet resultSet = statement.executeQuery(sql);
            while (resultSet.next()) {
                int id = resultSet.getInt("id");
                String name = resultSet.getString("name");
                System.out.println("id: " + id + ", name: " + name);
            }
        }
    }

    private static void dropTable(Connection connection) throws SQLException {
        try (Statement statement = connection.createStatement()) {
            String sql = "DROP TABLE test_commonpool";
            statement.executeUpdate(sql);
            System.out.println("Table dropped successfully.");
        }
    }

    static class ConnectionFactory extends org.apache.commons.pool2.BasePooledObjectFactory<Connection> {
        private final String url;
        private final String username;
        private final String password;

        public ConnectionFactory(String url, String username, String password) {
            this.url = url;
            this.username = username;
            this.password = password;
        }

        @Override
        public Connection create() throws Exception {
            return DriverManager.getConnection(url, username, password);
        }

        @Override
        public void destroyObject(org.apache.commons.pool2.PooledObject<Connection> p) throws Exception {
            p.getObject().close();
        }

        @Override
        public boolean validateObject(org.apache.commons.pool2.PooledObject<Connection> p) {
            try {
                return p.getObject().isValid(5000);
            } catch (SQLException e) {
                return false;
            }
        }

        @Override
        public PooledObject<Connection> wrap(Connection connection) {
            return new DefaultPooledObject<>(connection);
        }
    }
}

相关文档

更多 MySQL Connector/J 的信息,请参见 Overview of MySQL Connector/J