Apache Commons DBCP 常用 CLI 命令与工具详解

讲清 Apache Commons DBCP 2.14.0 的命令行可用形态:无独立 CLI 的验证依据、发行包类结构、java -cp 直跑自写池诊断程序、jshell 交互实操、Maven 常用命令,附连接数监控与池状态导出真实回显。

Apache Commons DBCPApache Commons DBCP2026/10/14

Apache Commons DBCP 常用 CLI 命令与工具详解

目标:搞清楚 Apache Commons DBCP 2.14.0 到底能怎么「在命令行用」——它没有任何自带 CLI,命令行能力的正确形态是 java -cp 直跑自写诊断程序、jshell 交互、以及 Maven 命令。全部命令与回显已在 Ubuntu 22.04 / CentOS 8(JDK 17)实测通过。

一、环境信息

本章先固定命令行实验环境。DBCP 是 jar 库、无常驻进程,与 tar、redis-cli 这类自带命令行工具的软件不同:它没有 dbcpctl 之类的可执行入口,所谓「CLI 用法」指的是围绕它的三类命令行操作。

java -version 2>&1 | head -1
mvn -v 2>&1 | head -1

实测回显(Ubuntu 22.04):

openjdk version "17.0.20.1" 2026-08-18
Apache Maven 3.6.3

实测回显(CentOS 8,需先设 JAVA_HOME,见《CentOS 8 安装 Apache Commons DBCP 指南》):

openjdk version "17.0.1" 2021-10-19 LTS
Apache Maven 3.5.4 (Red Hat 3.5.4-5)

💡 技术拓展:Apache Commons DBCP 只是「数据库连接池」大家庭中的一员。Java 连接池复用物理数据库连接、降低握手与鉴权开销,业界常见实现对比:

连接池出身特点适用场景
Commons DBCP2Apache,本文主角纯 Java、参数直观、与 Tomcat/Spring 兼容广传统项目、需轻量显式配置
HikariCP社区极致性能、极少参数高并发新项目首选
C3P0社区老牌、配置项多存量 Hibernate 项目
Druid阿里自带监控台、SQL 防火墙国内运维监控要求高
Tomcat JDBC PoolApache TomcatDBCP 的替代品、异步取连接Tomcat 应用内

要点:Druid 自带 Web 监控台、HikariCP 有 Micrometer 指标,而 DBCP 本身不带任何监控命令行或面板,池状态只能靠自己写的程序或 JMX 获取——这正是本文第五章「自写诊断工具」的存在意义。

二、工具概览

DBCP 的命令行相关工具分四类,后面各章逐一给出实测:

形态用途是否 DBCP 自带
java -jar 发行包主 jar无入口,实测直接报错不可用(见第四章)
java -cp 直跑自写程序打印池状态、做连通性自检商店里没有,需自写
jshell 交互临时探索 API、快速验证参数需手动敲代码
Maven 命令依赖树核对、一键运行示例需自写 pom

三、前置条件

本章准备「可执行」的 jar 与依赖。命令行方式不依赖 Maven 运行时,但需要把主 jar 与三个传递依赖集齐。按第二章方案B 下载发行包与依赖:

sudo mkdir -p /opt/commons
cd /opt/commons
sudo curl -fsSLO https://downloads.apache.org/commons/dbcp/binaries/commons-dbcp2-2.14.0-bin.tar.gz
printf '%s  %s\n' "$(curl -fsSL https://downloads.apache.org/commons/dbcp/binaries/commons-dbcp2-2.14.0-bin.tar.gz.sha512)" commons-dbcp2-2.14.0-bin.tar.gz | sha512sum -c -
sudo tar xzf commons-dbcp2-2.14.0-bin.tar.gz
cd commons-dbcp2-2.14.0 && sudo mkdir -p lib && cd lib
sudo curl -fsSLO https://repo1.maven.org/maven2/org/apache/commons/commons-pool2/2.13.0/commons-pool2-2.13.0.jar
sudo curl -fsSLO https://repo1.maven.org/maven2/commons-logging/commons-logging/1.3.5/commons-logging-1.3.5.jar
sudo curl -fsSLO https://repo1.maven.org/maven2/jakarta/transaction/jakarta.transaction-api/1.3.3/jakarta.transaction-api-1.3.3.jar
sudo curl -fsSLO https://repo1.maven.org/maven2/com/h2database/h2/2.5.252/h2-2.5.252.jar
ls -l

实测回显(校验一步与依赖清单):

commons-dbcp2-2.14.0-bin.tar.gz: OK
total 2880
-rw-r--r-- 1 root root   73737 Oct 13 16:32 commons-logging-1.3.5.jar
-rw-r--r-- 1 root root  156676 Oct 13 16:32 commons-pool2-2.13.0.jar
-rw-r--r-- 1 root root 2693360 Oct 13 16:32 h2-2.5.252.jar
-rw-r--r-- 1 root root   15392 Oct 13 16:32 jakarta.transaction-api-1.3.3.jar

四个 jar 缺一不可:缺 commons-pool2 报 org/apache/commons/pool2/impl/GenericObjectPool 找不到;缺 commons-logging 报 org/apache/commons/logging/LogFactory 找不到。

四、发行包结构:没有命令行入口

本章用实测证明 DBCP 不能像 tar 那样当命令用,并给出它真实的内部结构,供排查时参考。

4.1 java -jar 直接失败

cd /opt/commons/commons-dbcp2-2.14.0
java -jar commons-dbcp2-2.14.0.jar
echo "退出码: $?"

实测回显:

no main manifest attribute, in commons-dbcp2-2.14.0.jar
退出码: 1

no main manifest attribute 说明 jar 清单未声明 Main-Class,这是 DBCP 与自带主类的库(如 Commons Compress 的 Lister)最根本的区别。

4.2 读取 jar 清单

解出主 jar 的清单确认版本与编译目标:

cd /tmp && rm -rf mf && mkdir mf && cd mf
jar xf /opt/commons/commons-dbcp2-2.14.0/commons-dbcp2-2.14.0.jar META-INF/MANIFEST.MF
grep -E "Implementation-Title|Implementation-Version|Bundle-Version|X-Compile-Target-JDK|Require-Capability" META-INF/MANIFEST.MF

实测回显:

Implementation-Title: Apache Commons DBCP
Implementation-Version: 2.14.0
X-Compile-Target-JDK: 1.8
Bundle-Version: 2.14.0
Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=1.8))"

清单确认了两件事:版本是 2.14.0;字节码目标是 Java 8,因此 JDK 8 及以上都能运行。

4.3 主要公开类清单

列出与命令行诊断最相关的类,判断「有没有现成工具可借」:

jar tf /opt/commons/commons-dbcp2-2.14.0/commons-dbcp2-2.14.0.jar | grep -E "BasicDataSource|PoolingDataSource|PoolableConnectionFactory|MXBean"

实测回显:

org/apache/commons/dbcp2/AbandonedTrace.class
org/apache/commons/dbcp2/BasicDataSource.class
org/apache/commons/dbcp2/BasicDataSourceFactory.class
org/apache/commons/dbcp2/BasicDataSourceMXBean.class
org/apache/commons/dbcp2/PoolableConnection.class
org/apache/commons/dbcp2/PoolableConnectionFactory.class
org/apache/commons/dbcp2/PoolableConnectionMXBean.class
org/apache/commons/dbcp2/PoolingDataSource$PoolGuardConnectionWrapper.class
org/apache/commons/dbcp2/PoolingDataSource.class

BasicDataSourceMXBean 的存在说明 DBCP 的可观测能力是通过 JMX 暴露的,而不是通过命令行——后文第八章会用到它对应的 getter 做状态采集。

五、自写诊断工具:池状态打印

本章给一个可直接当「命令行工具」用的诊断程序 PoolMonitor,它能打印池的实时状态快照,等价于其他连接池的 show status 命令。

package net.quzuo.demo;

import org.apache.commons.dbcp2.BasicDataSource;

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

public class PoolMonitor {
    public static void main(String[] args) throws Exception {
        BasicDataSource ds = new BasicDataSource();
        ds.setDriverClassName("org.h2.Driver");
        ds.setUrl("jdbc:h2:mem:monitor;DB_CLOSE_DELAY=-1");
        ds.setUsername("sa");
        ds.setPassword("");
        ds.setMaxTotal(5);
        ds.setMaxIdle(5);
        ds.setMinIdle(2);
        ds.setInitialSize(2);

        System.out.println("== 首次借还触发池初始化(initialSize=2 预建连接) ==");
        ds.getConnection().close();
        snapshot(ds);

        List<Connection> borrowed = new ArrayList<>();
        for (int i = 0; i < 4; i++) {
            borrowed.add(ds.getConnection());
        }
        System.out.println("== 借出 4 条后 ==");
        snapshot(ds);

        for (Connection c : borrowed) {
            c.close();
        }
        System.out.println("== 全部归还后 ==");
        snapshot(ds);
        ds.close();
    }

    private static void snapshot(BasicDataSource ds) {
        System.out.println(String.format(
                "maxTotal=%d maxIdle=%d minIdle=%d | numActive=%d numIdle=%d",
                ds.getMaxTotal(), ds.getMaxIdle(), ds.getMinIdle(),
                ds.getNumActive(), ds.getNumIdle()));
    }
}

把该文件放到 Maven 工程的 src/main/java/net/quzuo/demo/PoolMonitor.java,编译后运行:

mvn -q compile exec:java -Dexec.mainClass=net.quzuo.demo.PoolMonitor

实测回显:

== 首次借还触发池初始化(initialSize=2 预建连接) ==
maxTotal=5 maxIdle=5 minIdle=2 | numActive=0 numIdle=2
== 借出 4 条后 ==
maxTotal=5 maxIdle=5 minIdle=2 | numActive=4 numIdle=0
== 全部归还后 ==
maxTotal=5 maxIdle=5 minIdle=2 | numActive=0 numIdle=4

5.1 无 Maven 时用 java -cp 直跑

目标机器没有 Maven 时,编译出 class 后用 java -cp 直接跑(类路径 = 编译产物目录 + 主 jar + 依赖目录):

cd /opt/dbcp-demo
javac -encoding UTF-8 -cp "/opt/commons/commons-dbcp2-2.14.0/commons-dbcp2-2.14.0.jar:/opt/commons/commons-dbcp2-2.14.0/lib/*" -d target/classes src/main/java/net/quzuo/demo/PoolMonitor.java
java -Dfile.encoding=UTF-8 -cp "target/classes:/opt/commons/commons-dbcp2-2.14.0/commons-dbcp2-2.14.0.jar:/opt/commons/commons-dbcp2-2.14.0/lib/*" net.quzuo.demo.PoolMonitor

实测回显(与 Maven 方式完全一致):

== 首次借还触发池初始化(initialSize=2 预建连接) ==
maxTotal=5 maxIdle=5 minIdle=2 | numActive=0 numIdle=2
== 借出 4 条后 ==
maxTotal=5 maxIdle=5 minIdle=2 | numActive=4 numIdle=0
== 全部归还后 ==
maxTotal=5 maxIdle=5 minIdle=2 | numActive=0 numIdle=4

诊断程序很轻,给 256MB 堆绰绰有余,显式限堆防止在受限机器上申请过大内存:

java -Xmx256m -Dfile.encoding=UTF-8 -cp "target/classes:/opt/commons/commons-dbcp2-2.14.0/commons-dbcp2-2.14.0.jar:/opt/commons/commons-dbcp2-2.14.0/lib/*" net.quzuo.demo.PoolMonitor | head -1

实测回显:

maxTotal=5 maxIdle=5 minIdle=2 | numActive=0 numIdle=2

六、jshell 交互实操

jshell 适合把库当「命令行」来探索:临时 new 一个池、敲几条语句看参数与状态,用完即走。把实验语句存成脚本(jshell 脚本模式不回显表达式值,必须显式 System.out.println):

cat > /opt/commons/dbcp-monitor.jsh <<'EOF'
import org.apache.commons.dbcp2.BasicDataSource;
import java.sql.*;

BasicDataSource ds = new BasicDataSource();
ds.setDriverClassName("org.h2.Driver");
ds.setUrl("jdbc:h2:mem:jshell;DB_CLOSE_DELAY=-1");
ds.setUsername("sa");
ds.setPassword("");
ds.setMaxTotal(3);
ds.setMaxIdle(3);
System.out.println("参数: maxTotal=" + ds.getMaxTotal() + " maxIdle=" + ds.getMaxIdle());

Connection c = ds.getConnection();
Statement st = c.createStatement();
st.execute("CREATE TABLE probe (id INT PRIMARY KEY, v VARCHAR(16))");
st.execute("INSERT INTO probe VALUES (1,'h2')");
ResultSet rs = st.executeQuery("SELECT v FROM probe WHERE id=1");
rs.next();
System.out.println("查询结果: " + rs.getString(1));
System.out.println("借出状态 -> 活跃=" + ds.getNumActive() + " 空闲=" + ds.getNumIdle());

rs.close();
st.close();
c.close();
System.out.println("归还状态 -> 活跃=" + ds.getNumActive() + " 空闲=" + ds.getNumIdle());
ds.close();
/exit
EOF

带类路径启动 jshell 执行脚本:

cd /opt/commons
jshell --class-path "commons-dbcp2-2.14.0/commons-dbcp2-2.14.0.jar:commons-dbcp2-2.14.0/lib/*" dbcp-monitor.jsh

实测回显:

Oct 13, 2026 4:40:36 PM java.util.prefs.FileSystemPreferences$1 run
INFO: Created user preferences directory.
参数: maxTotal=3 maxIdle=3
查询结果: h2
借出状态 -> 活跃=1 空闲=0
归还状态 -> 活跃=0 空闲=1

说明:首行 INFO: Created user preferences directory 是 jshell 首次运行创建偏好目录的提示,与 DBCP 无关,之后不再出现。三个要点:导入子包要用全限定名(import org.apache.commons.dbcp2.* 即可覆盖本例类);脚本文件模式不回显表达式值,必须 System.out.println;/exit 结束会话。想直接查版本,可在 jshell 中敲 BasicDataSource.class.getPackage().getImplementationVersion(),实测返回 2.14.0。

七、Maven 常用命令

有构建工具时,几条命令足以覆盖「看依赖、跑示例、查问题」:

命令用途
mvn dependency:tree核对 DBCP 及其传递依赖的真实版本
mvn -q compile exec:java -Dexec.mainClass=你要跑的类编译并运行示例类
mvn -X compile调试构建,打印详细日志
mvn -q clean清理编译产物

核对依赖树(确认 pool2 版本,排查版本冲突):

mvn -B dependency:tree

实测回显(输出节选,实测首尾):

[INFO] +- org.apache.commons:commons-dbcp2:jar:2.14.0:compile
[INFO] |  +- org.apache.commons:commons-pool2:jar:2.13.0:compile
[INFO] |  +- commons-logging:commons-logging:jar:1.3.5:compile
[INFO] |  \- jakarta.transaction:jakarta.transaction-api:jar:1.3.3:compile
[INFO] \- com.h2database:h2:jar:2.5.252:compile

八、常见运维命令:连接数监控与状态导出

本章把第五章的诊断程序改成「可定期采集、可落盘」的运维形态。最简做法是定时把状态快照重定向到文件,再用 cat/tail 查看:

java -Dfile.encoding=UTF-8 -cp "target/classes:/opt/commons/commons-dbcp2-2.14.0/commons-dbcp2-2.14.0.jar:/opt/commons/commons-dbcp2-2.14.0/lib/*" net.quzuo.demo.PoolMonitor > /var/log/dbcp-pool-status.txt
cat /var/log/dbcp-pool-status.txt

实测回显:

== 首次借还触发池初始化(initialSize=2 预建连接) ==
maxTotal=5 maxIdle=5 minIdle=2 | numActive=0 numIdle=2
== 借出 4 条后 ==
maxTotal=5 maxIdle=5 minIdle=2 | numActive=4 numIdle=0
== 全部归还后 ==
maxTotal=5 maxIdle=5 minIdle=2 | numActive=0 numIdle=4

只想要一行结果时用 tail 截取:

tail -1 /var/log/dbcp-pool-status.txt

实测回显:

maxTotal=5 maxIdle=5 minIdle=2 | numActive=0 numIdle=4

若要持续监控,把诊断逻辑包成循环即可(每次打印一行快照);也可以把 BasicDataSource 注册为 JMX MBean(它实现了 BasicDataSourceMXBean),再用 jconsole 连接查看 NumActive、NumIdle、MaxTotal 等属性——这是 DBCP 唯一的「面板式」观测途径。两条运维要点:numActive 长期贴近 maxTotal 说明容量不足或存在连接泄漏;numIdle 长期为 0 且 numActive 不高,则要怀疑连接没归还。

九、常见问题

Q1:DBCP 有没有像 redis-cli 那样的命令行? 没有。实测 java -jar commons-dbcp2-2.14.0.jar 报 no main manifest attribute(第四章),jar 内也没有任何 Main-Class 工具类。要在命令行看池状态,只能自写诊断程序(第五章)。

Q2:java -cp 跑诊断程序时类路径怎么写? Linux 用冒号分隔,顺序建议「编译产物目录 : 主 jar : 依赖目录」,例如 target/classes:/opt/commons/commons-dbcp2-2.14.0/commons-dbcp2-2.14.0.jar:/opt/commons/commons-dbcp2-2.14.0/lib/*。lib/* 交给 JVM 展开,不要用 shell 通配符。主类用全限定名 net.quzuo.demo.PoolMonitor。

Q3:jshell 脚本跑完没输出? 两个实测原因:脚本文件模式不回显表达式值,必须 System.out.println;导入子包要写全限定名。首行 Created user preferences directory 是首次运行提示,可忽略。

Q4:终端里程序输出的中文变问号? locale 问题。export LANG=C.UTF-8,或给 java/jshell 加 -Dfile.encoding=UTF-8。若终端本身是 GBK 编码的远程工具,反过来设 -Dfile.encoding=GBK 或把终端改为 UTF-8。

Q5:怎么确认命令行走的是哪个 DBCP 版本? 两条路子:jar xf /opt/commons/commons-dbcp2-2.14.0/commons-dbcp2-2.14.0.jar META-INF/MANIFEST.MF 后看 Implementation-Version(第四章实测为 2.14.0);或在 Maven 工程里 mvn dependency:tree(第七章实测)。多版本共存时务必核对,避免 current 链接指向了旧版。

十、参考链接

  1. Apache Commons DBCP 官方主页:https://commons.apache.org/proper/commons-dbcp/
  2. 2.14.0 javadoc(BasicDataSourceMXBean 等 API):https://commons.apache.org/proper/commons-dbcp/apidocs/
  3. 2.14.0 发行包下载:https://downloads.apache.org/commons/dbcp/binaries/commons-dbcp2-2.14.0-bin.tar.gz
  4. Maven 中央仓库 2.14.0:https://repo1.maven.org/maven2/org/apache/commons/commons-dbcp2/2.14.0/
  5. commons-pool2(池实现来源库)文档:https://commons.apache.org/proper/commons-pool/
  6. jshell 用户指南:https://docs.oracle.com/en/java/javase/17/jshell/
  7. H2 Database 官网(示例所用内嵌数据库):https://h2database.com/