C3P0详解及调优

基于Java 实现测试 C3P0 在 Oracle 数据库上的性能和参数,并动态监控各项参数指标。

一. C3P0常用参数

参数名称解释优化建议
initialPoolSize初始化时创建的连接数。影响应用启动时的连接准备速度。根据启动初期负载设置,建议与 minPoolSize 相同,如 5
minPoolSize连接池中的最小连接数。低于该值时会补充新连接。设置为常规最低负载下的并发连接数,如 5
maxPoolSize最大连接数,限制同时连接的数量。根据数据库性能和硬件资源限制,推荐 CPU 核心数 * 2 或更高。
maxIdleTime连接的最大空闲时间,超时的连接会被关闭。设置为 300 秒,避免无用连接占用资源。
acquireIncrement每次需要新连接时一次性创建的连接数。设置为 5,避免频繁创建单个连接带来的性能开销。
checkoutTimeout获取连接时的最大等待时间,超过该时间则抛出异常。设置为 3000 毫秒,防止客户端长时间阻塞。
idleConnectionTestPeriod闲置连接测试周期,周期性测试连接是否有效。推荐设置为 60 秒,确保空闲连接不会因网络问题变为无效连接。
testConnectionOnCheckin当连接返回池时是否测试其有效性开启为 true,提高连接池的可靠性。
testConnectionOnCheckout从池取连接时是否测试连接的有效性建议关闭为 false,以提升性能。如果需要提高稳定性,则可以设置为true
acquireRetryAttempts获取连接失败时重试的次数设置为 3。
acquireRetryDelay获取连接失败后重试的间隔时间设置为 1000 毫秒。
maxStatements缓存的 SQL 语句的总数根据实际情况设置,例如 100。
maxStatementsPerConnection每个连接的最大缓存 SQL 语句数设置为 20,结合 maxStatements 合理分配。
numHelperThreadsC3P0 使用的辅助线程数默认 3,可以根据 CPU 核数适当提高,例如 6。

二. Java 测试代码

Maven 依赖
<dependencies>
    <dependency>
        <groupId>com.mchange</groupId>
        <artifactId>c3p0</artifactId>
        <version>0.9.5.5</version>
    </dependency>
    <dependency>
        <groupId>com.oracle.database.jdbc</groupId>
        <artifactId>ojdbc8</artifactId>
        <version>19.14.0.0</version>
    </dependency>
</dependencies>

具体实现代码
import com.mchange.v2.c3p0.ComboPooledDataSource;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class C3P0PerformanceTest {

    // 配置数据库信息
    private static final String ORACLE_URL = "jdbc:oracle:thin:@oracle_host:1521:dbname";
    private static final String ORACLE_USER = "user";
    private static final String ORACLE_PASSWORD = "password";

    // 数据源
    private static ComboPooledDataSource dataSource;

    public static void main(String[] args) {
        try {
            // 初始化数据源
            dataSource = new ComboPooledDataSource();
            dataSource.setDriverClass("oracle.jdbc.OracleDriver");
            dataSource.setJdbcUrl(ORACLE_URL);
            dataSource.setUser(ORACLE_USER);
            dataSource.setPassword(ORACLE_PASSWORD);

	        // 性能相关的核心参数
	        dataSource.setInitialPoolSize(10);    // 初始连接池大小
	        dataSource.setMinPoolSize(5);         // 最小连接池大小
	        dataSource.setMaxPoolSize(50);        // 最大连接池大小
	        dataSource.setAcquireIncrement(5);   // 每次需要新连接时增加的连接数
	        dataSource.setMaxIdleTime(300);      // 连接最大空闲时间(秒)
	        dataSource.setIdleConnectionTestPeriod(60); // 检查空闲连接的时间间隔(秒)
	
	        // 高级参数配置
	        dataSource.setTestConnectionOnCheckin(true);  // 在连接返回池时检查是否有效
	        dataSource.setTestConnectionOnCheckout(false); // 禁用取出连接时的检查以提高性能
	        dataSource.setAcquireRetryAttempts(3);       // 获取连接失败时的重试次数
	        dataSource.setAcquireRetryDelay(1000);       // 重试间隔时间(毫秒)
	        dataSource.setMaxStatements(100);           // PreparedStatement 缓存大小
	        dataSource.setMaxStatementsPerConnection(20); // 每个连接的最大缓存语句数
        	dataSource.setNumHelperThreads(6);           // 帮助线程池大小,处理慢任务


            // 启动性能测试线程池
            ExecutorService executor = Executors.newFixedThreadPool(10);
            for (int i = 0; i < 100; i++) {
                executor.submit(() -> executeQuery("SELECT COUNT(*) FROM YOUR_TABLE"));
            }

            // 启动动态监控
            startMonitoring(dataSource);

            // 等待线程完成任务后关闭
            executor.shutdown();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 执行查询操作
    private static void executeQuery(String query) {
        try (Connection connection = dataSource.getConnection();
             PreparedStatement ps = connection.prepareStatement(query)) {
            ResultSet rs = ps.executeQuery();
            if (rs.next()) {
                System.out.println("Result: " + rs.getInt(1));
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    // 动态监控连接池参数
    private static void startMonitoring(ComboPooledDataSource dataSource) {
        Timer timer = new Timer(true);
        timer.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                try {
                    System.out.println("==== C3P0 Monitoring ====");
                    System.out.println("Num Connections: " + dataSource.getNumConnectionsDefaultUser());
                    System.out.println("Num Idle Connections: " + dataSource.getNumIdleConnectionsDefaultUser());
                    System.out.println("Num Busy Connections: " + dataSource.getNumBusyConnectionsDefaultUser());
                    System.out.println("Total Connections: " + dataSource.getNumConnections());
			        System.out.println("Busy Connections: " + dataSource.getNumBusyConnections());
			        System.out.println("Idle Connections: " + dataSource.getNumIdleConnections());
			        System.out.println("Unclosed Orphaned Connections: " + dataSource.getNumUnclosedOrphanedConnections());
			        System.out.println("Statements Cached: " + dataSource.getNumStatementsCached());
                    System.out.println("=========================");
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }, 0, 5000); // 每 5 秒监控一次
    }
}

三. 运行结果

==== C3P0 Monitoring ====
Num Connections: 15
Num Idle Connections: 12
Num Busy Connections: 3
Total Connections: 15
Busy Connections: 3
Idle Connections: 12
Unclosed Orphaned Connections: 0
Statements Cached: 30
=========================
Result: 1200

四. 优化建议

基础负载
  • 小型应用:minPoolSize=5, maxPoolSize=20
  • 大型应用:根据并发量和数据库性能动态调整,例如 minPoolSize=20, maxPoolSize=200
动态监控

结合监控日志和运行结果,实时调整配置:

  • 如果 Num Idle Connections 长期过多,降低 minPoolSize
  • 如果 Num Busy Connections 经常接近 maxPoolSize,需要增加连接池上限或优化数据库查询。
错误处理
  • 配置合理的 checkoutTimeout,避免死锁。
  • 使用 testConnectionOnCheckoutidleConnectionTestPeriod 检测无效连接。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值