首批通过分布式安全可靠测评,为关键业务系统打造
更新时间:2026-07-28
本文旨在介绍如何在 OceanBase 中规范地配置 Java 应用与数据库间的连接,包括 JDBC 连接参数和 Druid 连接池的使用。
该指导适用于 OceanBase 数据库 V2.x、V3.x 和 V4.x 版本。
为确保应用程序与 OceanBase 数据库之间的连接既稳定又高效,并确保安全性,您可以了解以下关键概念和原理:
JDBC(Java Database Connectivity)
JDBC 是一种用于 Java 应用程序与数据库交互的 API(应用程序接口),提供一组标准的接口,允许 Java 程序执行 SQL 语句、获取查询结果及处理数据库事务。
连接池
连接池(Connection Pool)是一种管理数据库连接的技术。它维持了一个预先创建的数据库连接集,应用程序在需要时可从中获取连接,并在使用完成后将连接返还,借此重用连接并减少连接的创建与销毁开销。应用程序启动时会创建多个数据库连接并保存在内存中;当需要数据库连接时,从连接池中获取一个空闲连接,使用完毕后归还给连接池。这种机制显著减少了连接数据库的时间,提高了应用程序的性能和资源利用率。常见的连接池实现包括 Druid、DBCP、C3P0 等。
连接探活
定期检测数据库连接的有效性,以防止应用程序使用失效连接,从而提高系统稳定性。可通过配置 testWhileIdle、testOnBorrow 和 testOnReturn 来实现连接的探活机制。
了解以上关键概念后,请继续阅读本文,掌握将应用程序与数据库驱动相连接的具体配置项,这些配置是确保系统稳定性和性能的关键所在。
在进行应用程序与 OceanBase 数据库交互时,合适的驱动配置能极大提高系统的稳定性与性能。以下是一些主要的配置项:
连接超时设置:设置客户端连接数据库的等待时间,例如配置 connectTimeout 和 socketTimeout。同时,要实施快速失败重试机制,确保在连接失败时能迅速重试,并设定连接间隔时间,以减少网络阻塞和系统负载。
日志记录:在程序运行期间,应记录连接数据库的 OceanBase 错误码及连接信息(如 IP、PORT、用户名),以便 DBA 快速诊断和解决问题。
版本兼容性:确保客户端库(如 .so 或 .jar 包)与数据库服务器版本兼容,以保证各组件间的正确协作。
切换数据库方法:推荐使用 Connection.setCatalog(dbname) 接口,而非 SQL 命令 use <dbname>,以提高代码的可读性和维护性。
Session 状态变量设置:通过 JDBC 接口(如 setAutoCommit、setReadOnly、setTransactionIsolation)来设置 Session 状态变量,以减少 SQL 使用频率,降低数据库交互次数并提升性能。
事务处理:在执行单个事务(无论是单条 SQL 还是多条 SQL)之前,重新获取数据库连接(getConnection),事务执行完毕后,关闭连接(closeConnection)。确保每个事务独立处理,以防止连接复用导致的状态污染,确保数据的一致性和隔离性。
通过合理配置以上项,您将能够显著提升 OceanBase 数据库与应用程序之间的交互效率和稳定性。在后续章节中,我们将深入探讨一些具体的配置参数和示例,帮助您实现最佳的系统架构。
本节将详细介绍在配置 JDBC 连接数据库时的重要参数。用户可以将这些参数配置到连接池的 ConnectionProperties 中,也可以直接写入 JdbcUrl 中。为了统一管理,推荐在连接池中进行配置。
JDBC 连接示例如下所示,您可以通过具体的 URL 进行数据库连接:
conn = jdbc:mysql://x.x.x.x(ip):xx(port)/xxxx(dbname)?rewriteBatchedStatements=true&allowMultiQueries=true&useLocalSessionState=true&useUnicode=true&characterEncoding=utf-8&socketTimeout=3000000&connectTimeout=60000
接下来,我们将详细解析 JDBC 连接示例 中各个参数配置的含义及其作用,以帮助您更好地理解和使用。
jdbc:mysql://x.x.x.x(ip):xx(port)/xxxx(dbname)
rewriteBatchedStatements=true
这个参数用于优化批量更新操作。当启用此选项时,JDBC 驱动程序会将批处理语句重写成一次性 SQL 语句,从而减少与数据库的交互次数,提高性能。
allowMultiQueries=true
该参数允许在单个 Statement 语句中执行多个 SQL 查询。虽然这可以提高执行效率,但也可能导致 SQL 注入风险,应谨慎使用。在处理用户输入时务必进行严格的验证和清理。
useLocalSessionState=true
当启用该选项时,MySQL JDBC 驱动程序将使用本地会话状态,这样在发送状态变化时不会立即与数据库同步,优化了一些操作的执行速度。
useUnicode=true
启用此选项后,JDBC 驱动程序将使用 Unicode 字符集进行字符串的输入和输出,确保可以正确处理非 ASCII 字符,如中文或其他语言的字符。
characterEncoding=utf-8
指定数据库连接使用的字符编码为 UTF-8。这是一个通用的字符集,可以支持多种语言的字符,避免在数据传输过程中出现乱码的情况。
socketTimeout=3000000
这个参数设置了超时时间(以毫秒为单位)。如果在指定时间内没有进行任何数据传输,连接将会被自动关闭。
connectTimeout=60000
该参数定义了客户端与数据库服务器建立连接时的超时时间(同样以毫秒为单位)。如果在这个时间内无法成功连接,则会抛出异常。
接下来,我们将详细解析 JDBC 连接示例中的各个参数配置。
在 JDBC 连接示例中,可以配置以下参数:
| 参数 | 说明 | 推荐值 |
|---|---|---|
socketTimeout |
网络读超时时间 | 5000ms |
connectTimeout |
连接建立超时时间 | 500ms |
socketTimeout ,并根据应用特点进行调整。如果不设置,系统将使用默认超时时间 0ms,即永不超时。connectTimeout,并根据应用特点进行调整。如果不设置,系统将使用默认连接建立超时时间 30000ms。ob_query_timeout 和 ob_trx_timeout 控制 SQL 超时时间。在 JDBC 连接示例中,可以配置以下参数:
| 参数 | 说明 | 推荐值 |
|---|---|---|
useLocalSessionState |
指示是否使用本地 Session 状态变量。OceanBase JDBC V2.4.15 及之后版本支持该参数,默认值为 true,可以修改为 false 或 true。在使用 MySQL JDBC 连接 OceanBase 时也可以设置此参数。 |
true |
useLocalSessionState 设置为 true,使用本地的 Session 状态变量以减少应用与数据库之间的交互,从而提升交易性能。OceanBase JDBC V2.4.15 及之后版本支持该参数,默认值为 true,可以修改为 false 或 true。在使用 MySQL JDBC 连接 OceanBase 时也可以设置此参数。autocommit、read_only 和 transaction isolation。| 参数 | SQL 语句 | JDBC 接口 |
|---|---|---|
| 自动提交模式 | set autocommit=0 |
setAutoCommit(false) |
| 事务的隔离级别 | set tx_isolation='read-committed' |
setTransactionIsolation(2) |
| 只读事务 | set tx_read_only=0 |
setReadOnly(false) |
在云和分布式数据库环境中,应用服务器与数据库服务器之间的网络链路较长,因此网络延迟对交易性能至关重要。为此,高效的应用编码应尽量采用批量执行方法,减少与数据库的多次交互。
下面列出了一些重要的 JDBC 参数设置,这些参数不仅影响批量执行的行为,同时也关系到应用程序与数据库之间的交互效率:
| 配置属性 | 默认值 | 说明 |
|---|---|---|
allowMultiQueries |
FALSE | 确定一条语句中是否可以通过 “;” 分割多个请求。Batch 执行不依赖此属性,而是依赖 rewriteBatchedStatements。 注意:若 JDBC 版本小于等于 1.1.9,allowMultiQueries 必须开启以便使用 “;” 分割更新语句;若大于等于 2.2.6,则开启与否均无影响。 |
rewriteBatchedStatements |
FALSE | 确定在 Batch 执行中是否重写 INSERT 语句。对于 PreparedStatement,多个 VALUES 将合并;对于 Statement,会使用分号拼接多个 INSERT 语句。 |
useServerPrepStmts |
FALSE | 确定是否使用服务端的 Prepared 语句,仅对 PreparedStatement 有效。TRUE 表示使用服务端的 Prepared 语句,需在 OBServer 端开启 _ob_enable_prepared_statement,并使用二进制协议通信;FALSE 表示使用客户端的 Prepared 语句,使用文本协议。 |
cachePrepStmts |
FALSE/TRUE | 确定 JDBC 驱动是否缓存 Prepared 语句。缓存内容在客户端与服务端有所不同。注意:OceanBase JDBC 1.x 默认为 FALSE,而 2.x 默认为 TRUE。 |
prepStmtCacheSize |
25/250 | 如果开启了 cachePrepStmts,则决定可以缓存多少条 prepared statements。注意:OceanBase JDBC 1.x 默认为 25,2.x 默认为 250。 |
prepStmtCacheSqlLimit |
256/2048 | 如果开启了 cachePrepStmts,则决定可以缓存的最大 SQL 大小。注意:OceanBase JDBC 1.x 默认为 256,2.x 默认为 2048。 |
maxBatchTotalParamsNum |
30000 | 当使用 executeBatch,决定最大可以拼接多少个参数。注意:仅在 OceanBase JDBC 2.2.7 及以后版本有效。 |
无论您选择使用 Statement 还是 PreparedStatement,均可实现 Batch 执行。接下来,我们将分别展示如何使用这两种对象进行批量执行,以实践上述配置对性能的提升。
首先,我们通过 PreparedStatement 开始实现批量执行。以下是一个示例代码,展示了如何在一个事务中插入多条记录:
conn = DriverManager.getConnection(obUrl);
conn.setAutoCommit(false);
String SQL = "INSERT INTO TEST1 (C1, C2) VALUES (?, ?)";
PreparedStatement pstmt = conn.prepareStatement(SQL);
int rowCount = 5, batchCount = 10;
for (int k = 1; k <= batchCount; k++) {
for (int i = 1; i <= rowCount; i++) {
pstmt.setInt(1, (k * 100 + i));
pstmt.setString(2, "test value");
pstmt.addBatch();
}
int[] count = pstmt.executeBatch();
pstmt.clearBatch();
}
conn.commit();
pstmt.close();
在使用 PreparedStatement 时,Batch 执行的行为会有所不同,具体如下:
| useServerPrepStmts | INSERT | UPDATE | 备注 |
|---|---|---|---|
| TRUE | 多条 INSERT 语句的 VALUES 会以多个 ? 拼接在同一 INSERT 语句中,例如:INSERT INTO TEST1 VALUES (?, ?, ... , ?) | 多条单独的 UPDATE 语句,其中的变量用 ? 替代 | 场景1 |
| FALSE | 多条 INSERT 语句的 VALUES 会以具体值的形式拼接在同一 INSERT 语句中,例如:INSERT INTO TEST1 VALUES (1), (2), ... , (10) | 多条单独的 UPDATE 语句用 “分号” 拼接在一起 | 场景2 |
我们也可以通过 Statement 对象实现批量执行。以下是一个代码示例,展示了如何使用 Statement 来插入多条记录:
conn = DriverManager.getConnection(obUrl);
conn.setAutoCommit(false);
Statement stmt = conn.createStatement();
String SQL1 = "INSERT INTO test1 (c1, c2) VALUES (1, 'test11')";
stmt.addBatch(SQL1);
String SQL2 = "INSERT INTO test1 (c1, c2) VALUES (2, 'test12')";
stmt.addBatch(SQL2);
String SQL3 = "INSERT INTO test1 (c1, c2) VALUES (3, 'test13')";
stmt.addBatch(SQL3);
int[] count = stmt.executeBatch();
stmt.clearBatch();
conn.commit();
与 PreparedStatement 相比,使用 Statement 对象的批量执行行为如下所示:
| useServerPrepStmts | INSERT | UPDATE | 备注 |
|---|---|---|---|
| TRUE | 多条单独的 INSERT 语句用 “分号” 拼接在一起 | 多条单独的 UPDATE 语句用 “分号” 拼接在一起 | 场景3 |
| FALSE | 多条单独的 INSERT 语句用 “分号” 拼接在一起 | 多条单独的 UPDATE 语句用 “分号” 拼接在一起 | 场景4 |
在前面的讨论中,我们提到了 Statement 对象在批量插入和更新中的基本用法。接下来的部分将更深入地探讨在不同场景中如何选择合适的配置,以充分利用批量执行的性能。
在场景 1 和场景 2 中,可以更有效地利用批量执行性能,建议使用以下配置:
场景 1:
JDBC 对象:
PreparedStatement 对象
服务端参数:
_ob_enable_prepared_statement=TRUE
JDBC 配置属性:
rewriteBatchedStatements=TRUE
useServerPrepStmts=TRUE
cachePrepStmts=TRUE
prepStmtCacheSize=<根据实际情况>
prepStmtCacheSqlLimit=<根据实际情况>
maxBatchTotalParamsNum=<根据实际情况>
场景 2:
JDBC 对象:
PreparedStatement 对象
JDBC 配置属性:
rewriteBatchedStatements=TRUE
useServerPrepStmts=FALSE
接下来,我们将讨论在场景 2、场景 3 和场景 4 中进行批量更新的建议配置。使用文本协议通信可以有效利用多条 UPDATE 语句的批处理功能,因此应采用以下配置:
场景 2:
JDBC 对象:
PreparedStatement 对象
服务端参数:
ob_enable_batched_multi_statement=TRUE
_enable_static_typing_engine=TRUE(OceanBase V3.2 需要)
服务端变量:
_enable_dist_data_access_service=1(OceanBase 3.2 需要)
JDBC 配置属性:
rewriteBatchedStatements=TRUE
useServerPrepStmts=FALSE
allowMultiQueries=TRUE(避免 JDBC 驱动不同版本之间的行为差异)
场景 3 和 4:
另外,在场景 3 和场景 4 中,我们建议采用以下配置以支持批量更新:
JDBC 对象:
Statement 对象
服务端参数:
ob_enable_batched_multi_statement=TRUE
_enable_static_typing_engine=TRUE(OceanBase 3.2 需要)
服务端变量:
_enable_dist_data_access_service=1(OceanBase 3.2 需要)
JDBC 配置属性:
rewriteBatchedStatements=TRUE
allowMultiQueries=TRUE(避免 JDBC 驱动不同版本之间的行为差异)
通过明确每种场景下的配置推荐,我们可以更有效地利用 JDBC 的批量执行性能,提升数据操作的效率。
在 OceanBase 数据库中,以下配置项与批量执行相关:
| 参数 | 默认值 | 范围 | 生效方式 | 含义 |
|---|---|---|---|---|
ob_enable_batched_multi_statement |
FALSE | 租户 | 动态 | 控制是否启用批量处理多条语句。当启用此参数时,OceanBase 在 Batch 执行场景中,会将格式一致的多条 UPDATE 语句视为一条语句解析,并根据相应的参数和数据分布生成批量物理计划。 |
_ob_enable_prepared_statement |
TRUE | 集群 | 动态 | 指示是否可以使用服务器端的 Prepared 语句。 |
_enable_static_typing_engine |
TRUE | 集群 | 动态 | 指定是否使用新的 SQL 引擎。新老 SQL 引擎对 Batch UPDATE 的处理有所不同;旧引擎只支持包含所有主键的 Batch UPDATE,而新引擎(需在 OceanBase 3.2 及更高版本中)支持不包含所有主键的 Batch UPDATE。 |
| 参数 | 默认值 | 级别 | 含义 |
|---|---|---|---|
_enable_dist_data_access_service |
TRUE | session/global | 控制 SQL 用 DAS 执行。在 OceanBase 3.2 版本之后,为获得 Batch UPDATE 的优化功能,此变量必须启用。 |
从操作语句看,OceanBase 对 INSERT、UPDATE 和 DELETE 的 Batch 执行处理存在差异:
首先,在处理 INSERT 时,有几个关键场景值得关注:
场景 1: OceanBase 服务器接收到一次 INSERT 的 COM_STMT_PREPARE 请求(request_type=5)和一次 COM_STMT_EXECUTE 请求(request_type=6)。此种优化带来的好处包括:
PreparedStatement 减少了编译时间。executeBatch,并合理设置 cachePrepStmts 等参数,将减少 prepare 请求(request_type=5)的次数,仅需执行 execute 请求(request_type=6)。场景 2: 另一方面,若 OceanBase 服务端收到一次 INSERT 的 COM_QUERY 请求(request_type=2),带来的优化效果是:
场景 3/4: 服务器接收到多个以 “;” 连接的 INSERT 语句请求,并按顺序执行,同样实现了:
在处理 UPDATE 时,情况有所不同。首先,在未启用 ob_enable_batched_multi_statement 时,场景 1/2/3/4 的 Batch UPDATE 在 OceanBase 服务器端将依次执行,未实现特别优化。然而,启用 ob_enable_batched_multi_statement 后,针对场景 2/3/4 的 Batch UPDATE,OceanBase 会将格式一致的多条 UPDATE 语句视为一条进行解析。生成的批量物理计划能显著提升执行效率。需要特别注意的是:
_enable_dist_data_access_service 变量并启动新 SQL 引擎。在 OceanBase V3.x 版本中对 Batch DELETE 的处理为依次执行,而 OceanBase V4.x 对 DELETE 语句进行了优化。
检查 Batch 执行的有效性,最常用的方法是通过 gv$sql_audit。以下是不同场景的示例:
场景 1 的 Batch INSERT 生效时:
query_sql: insert into test_multi_queries (c1, c2) values (?, ?)
request_type: 5
ps_stmt_id: 1
query_sql: insert into test_multi_queries (c1, c2) values (?, ?),(?, ?),(?, ?)
request_type: 5
ps_stmt_id: 2
request_type: 6
场景 2 的 Batch INSERT 生效时:
query_sql: insert into test_multi_queries (c1, c2) values (1, 'PreparedStatement; rewriteBatchedStatements=true&allowMultiQueries=true&useLocalSessionState=true'),(2, ...),(3, ...)
场景 2 的 Batch UPDATE 生效时:
query_sql: update test2 set c2='batch update1' where c1=1; update test2 set c2='batch update2' where c1=2; ...
ret_code: 0
is_batched_multi_stmt: 1
注意: 若 ret_code=-5787,表明 Batch UPDATE 未成功,需要根据上述说明查找原因。
调用 executeBatch 后,会返回一个整型数组 int[],对于 Batch INSERT 和 Batch UPDATE:
在结果集返回时,OceanBase 支持三种方式:静态结果集、流式结果集和游标结果集。
对于不同类型结果集的特性,我们可以总结如下:
| 结果集类型 | 查询方式 | 数据读取方式 | 优点 | 缺点 |
|---|---|---|---|---|
| 静态结果集 | 普通查询 | 一次读取到所有的结果 | 应用代码简单,数据量较小时执行速度最快。 | 数据量较大时可能引发 OOM(Out Of Memory,内存不足)问题。 |
| 流式结果集 | 流式查询 | 不一次性读取全部的数据,而是一行一行从 Socket 中读取数据。 | 数据量较大时不会引发 OOM问题。 | 执行期间占用数据库时间更长,导致网络拥塞的可能性较大。部分游标相关的方法无法使用,例如 islast、absolute 等方法。 |
| 游标结果集 | 游标查询 | 一次可以读取多行数据,经过多次读取后可以获得全部结果。 | 数据量较大时不会引发 OOM问题。相比流式查询,对数据库单次占用时间较短。 | 执行速度较慢,资源消耗较大,响应时间更长。 |
针对不同类型结果集,我们可以如下配置:
| 结果集类型 | 配置方法 | 配置说明 |
|---|---|---|
| 静态结果集 | URL配置 | 无需特殊配置。 |
| Java程序 | 无需特殊配置。 | |
| 流式结果集 | URL配置 | 无需特殊配置。 |
| Java程序 | 需使用 PrepareStatement,并设置 fetchSize 为 Integer.MIN_VALUE。示例: PreparedStatement st1 = conn.prepareStatement(querySql1); st1.setFetchSize(Integer.MIN_VALUE); |
|
| 游标结果集 | URL配置 | 设置 useCursorFetch=true 和 useServerPrepStmts=true。 |
| Java程序 | 设置 fetchSize>0,如 PreparedStatement st1 = conn.prepareStatement(querySql1); st1.setFetchSize(100); |
JDBC 参数 useCursorFetch:
| 参数 | 说明 | 推荐值 |
|---|---|---|
| useCursorFetch | 是否允许数据库建立游标并根据 FetchSize 大小分发数据。 | true |
注意: 设置 useCursorFetch=true 将自动启用 useServerPrepStmts=true。
根据结果集大小选择相应的处理方式:
ResultSet.TYPE_SCROLL_INSENSITIVE 会使用全量结果集。useCursorFetch=true 时,useServerPrepStmts 被强制设置为 true;如需批量更新,请配置独立数据源(因更新批量优化依赖 useServerPrepStmts=false)。isLast()、absolute() 等方法。net_write_timeout 控制,默认 60s)。可通过 JDBC URL 设置 netTimeoutForStreamingResults 来避免超时,默认值为 600s。execute 后的第一个响应可能较慢。PreparedStatement st1 = conn.prepareStatement(querySql1);
st1.setFetchSize(100);
PreparedStatement st1 = conn.prepareStatement(querySql1);
st1.setFetchSize(Integer.MIN_VALUE);
为了确保数据库连接的高效管理,以下是一些重要的连接池参数:
| 参数名称 | 含义 | Druid参数 | DBCP参数 | C3P0参数 |
|---|---|---|---|---|
| 初始化连接数 | 连接池启动时创建的初始连接数量 | initialSize(0) | initialSize(0) | initialPoolSize(3) |
| 最小连接数 | 连接池保持的最小可用连接数量 | minIdle(0) | minIdle(0) | minPoolSize(3) |
| 最大连接数 | 连接池可用的最大连接数量,超出时会抛出连接池已满异常 | maxActive(8) | maxActive(8) | maxActive(8) |
| 连接空闲超时时间 | 连接在空闲状态下的最长时间,超过此时间将被断开。MySQL 默认 8 小时,云环境建议设置为 12 分钟 | minEvictableIdleTimeMillis(30min) | minEvictableIdleTimeMillis(30min)(需设置 timeBetweenEvictionRunsMillis 大于 0) |
maxIdleTime(0表示不超时) |
| 获取连接超时时间 | 连接池满时获取连接的最长等待时间(毫秒),设置过长会影响应用响应时间 | maxWait(-1 表示不超时) | maxWaitMillis(-1表示不超时) | checkoutTimeout (0表示不超时) |
| 长时间不释放连接超时 | 超时未归还的连接将被销毁,避免连接泄露,但可能影响事务时限 | removeAbandonedTimeoutMillis(300s) | removeAbandonedTimeout(300s) | 无 |
为了获得最佳的性能,建议:
testOnBorrow 等机制定期校验连接的有效性,确保在超时时间内未使用的连接被主动断开。对于 Java 程序,建议使用 Druid 连接池,版本要求为 V1.2.8 及以上。
maxActive: 100
initialSize: 5
maxWait: 10000
minIdle: 5
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
maxEvictableIdleTimeMillis: 1800000
validationQuery: select 1;
testWhileIdle: true
testOnBorrow: true
testOnReturn: false
removeAbandoned: false
removeAbandonedTimeout: 180
以下是参数说明的整理表格:
| 参数 | 说明 |
|---|---|
| maxActive | 最大连接数。 |
| initialSize | 初始创建的连接数。 |
| maxWait | 获取连接时最长可以等待的时间,单位为毫秒。 |
| minIdle | 最少可以保留的空闲连接数,建议与 initialSize 一致。当空闲连接总数小于该值时,除非连接的空闲时间大于最大存活时间(maxEvictableIdleTimeMillis),否则不主动 destroy 空闲连接。 |
| timeBetweenEvictionRunsMillis | 配置间隔多久启动一次 DestroyThread,对连接池内连接进行一次检测,单位是毫秒。 |
| minEvictableIdleTimeMillis | 一个空闲连接在连接池中最小的存活时间,单位为毫秒。 |
| maxEvictableIdleTimeMillis | 一个空闲连接在连接池中最大的存活时间,单位为毫秒。 |
| validationQuery | 用来检测连接是否有效的 SQL。如果 validationQuery 为 null,则下面的三个 test 选项均无效。 |
| testWhileIdle | 建议设置为 true。如果空闲时间 > timeBetweenEvictionRunsMillis,执行 validationQuery;否则直接复用连接。 |
| testOnBorrow | 建议设置为 true。设置为 true 时,从连接池复用一个连接时会执行 validationQuery 检测连接有效性。 |
| testOnReturn | 建议设置为 false。归还连接到连接池时不执行 validationQuery 检测连接有效性。 |
| removeAbandoned | 建议设置为 false。设置为 true 时,执行连接泄漏检查。 |
| removeAbandonedTimeout | 如果 borrowed 连接在 idle 状态并且借出时间超过 removeAbandonedTimeout,则强制归还连接。执行 SQL 频率较低的长连接,也会被认为存在泄漏而收回,导致交易失败。 |
添加 Maven 依赖:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.8</version>
</dependency>
配置样例:
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
<!-- 基本属性 url、user、password -->
<property name="url" value="${jdbc_url}" />
<property name="username" value="${jdbc_user}" />
<property name="password" value="${jdbc_password}" />
<!-- 连接池基本配置 -->
<property name="initialSize" value="20" />
<property name="minIdle" value="10" />
<property name="maxActive" value="100" />
<property name="maxWait" value="1000" />
<property name="timeBetweenEvictionRunsMillis" value="60000" />
<property name="minEvictableIdleTimeMillis" value="300000" />
<property name="testOnBorrow" value="true" />
<property name="testOnReturn" value="false" />
<property name="testWhileIdle" value="true" />
<property name="validationQuery" value="select 1 from dual" />
<property name="keepAlive" value="true" />
<!-- 各种配置可根据业务需求适当调整 -->
</bean>
添加依赖:
<dependencies>
<dependency>
<groupId>com.alipay.oceanbase</groupId>
<artifactId>oceanbase-client</artifactId>
<version>3.2.3</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.7.0</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>
<version>2.7.0</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.7.0</version>
</dependency>
</dependencies>
配置文件示例(dbcp.properties):
driverClassName=com.alipay.oceanbase.jdbc.Driver
url=jdbc:oceanbase://10.100.xxx.xxx:18817/test?useSSL=false&useServerPrepStmts=true&serverTimezone=UTC
username=$user_name
password=******
initialSize=30
maxTotal=30
maxIdle=10
minIdle=5
maxWaitMillis=1000
removeAbandonedOnMaintenance=true
removeAbandonedOnBorrow=true
removeAbandonedTimeout=1
添加依赖:
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5</version>
</dependency>
示例代码:
import com.mchange.v2.c3p0.ComboPooledDataSource;
import java.beans.PropertyVetoException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class C3P0PoolTest {
private static ComboPooledDataSource dataSource = new ComboPooledDataSource("oboracle");
public void init() throws PropertyVetoException {
dataSource.setDriverClass("com.oceanbase.jdbc.Driver");
dataSource.setJdbcUrl("jdbc:oceanbase://10.100.xxx.xxx:30035/test?useSSL=false");
dataSource.setUser("test@tt3");
dataSource.setPassword("test");
dataSource.setInitialPoolSize(3);
dataSource.setMaxPoolSize(10);
dataSource.setMinPoolSize(3);
dataSource.setAcquireIncrement(3);
}
public void testInsert() throws SQLException, PropertyVetoException {
init();
try (Connection connection = dataSource.getConnection()) {
connection.setAutoCommit(false);
connection.prepareStatement("create table t1(c1 binary_double)").execute();
try (PreparedStatement ps = connection.prepareStatement("insert into t1 values('2.0')")) {
ps.execute();
}
try (ResultSet resultSet = connection.createStatement().executeQuery("select * from t1")) {
while (resultSet.next()) {
int count = resultSet.getMetaData().getColumnCount();
for (int i = 1; i <= count; i++) {
System.out.println(resultSet.getMetaData().getColumnName(i) + ":" + resultSet.getString(i));
}
}
}
}
}
}
配置文件示例:
<Resource name="jdbc"
auth="Container"
type="javax.sql.DataSource"
maxActive="100"
maxIdle="30"
maxWait="10000"
username="root"
password=""
driverClassName="com.oceanbase.jdbc.Driver"
url="jdbc:oceanbase://10.100.xxx.xxx:18815/test?characterEncoding=UTF-8" />
在项目的 web.xml 中进行配置:
<resource-ref>
<res-ref-name>jdbc</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
添加依赖:
<dependency>
<groupId>proxool</groupId>
<artifactId>proxool-cglib</artifactId>
<version>0.9.1</version>
</dependency>
<dependency>
<groupId>proxool</groupId>
<artifactId>proxool</artifactId>
<version>0.9.1_20141120</version>
</dependency>
配置文件示例:
jdbc-1.proxool.alias=test
jdbc-1.proxool.driver-class=com.oceanbase.jdbc.Driver
jdbc-1.proxool.driver-url=jdbc:oceanbase://10.100.xxx.xxx:30035/test
jdbc-1.user=test@tt3
jdbc-1.password=test
jdbc-1.proxool.maximum-connection-count=8
jdbc-1.proxool.minimum-connection-count=5
jdbc-1.proxool.prototype-count=4
jdbc-1.proxool.verbose=true
jdbc-1.proxool.statistics=10s,1m,1d
jdbc-1.proxool.statistics-log-level=error
添加依赖:
<dependency>
<groupId>com.alipay.oceanbase</groupId>
<artifactId>oceanbase-client</artifactId>
<version>3.2.3</version>
</dependency>
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>3.3.1</version>
</dependency>
配置文件示例(jdbc.properties):
jdbcUrl=jdbc:oceanbase://10.100.xxx.xxx:18817/test?useSSL=false&useServerPrepStmts=true&serverTimezone=UTC
username=$user_name
password=******
dataSource.cachePrepStmts=true
dataSource.prepStmtCacheSize=250
dataSource.prepStmtCacheSqlLimit=2048
dataSource.useServerPrepStmts=true
dataSource.useLocalSessionState=true
dataSource.rewriteBatchedStatements=true
dataSource.cacheResultSetMetadata=true
dataSource.cacheServerConfiguration=true
dataSource.elideSetAutoCommits=true
dataSource.maintainTimeStats=false
在数据库应用性能优化的过程中,JDBC 参数设置至关重要:
超时配置:
socketTimeout,并根据应用特点进行调整。若不设置,默认超时时间为 0ms,即永不超时。connectTimeout,并根据应用特点进行调整。若不设置,默认连接建立超时时间为 30000ms。ob_query_timeout 和 ob_trx_timeout 来控制。Session 变量:
useLocalSessionState=true,通过 JDBC 接口配置 autocommit、readonly、isolation 等 Session 变量。这能避免通过 SQL 语句访问数据库获取 Session 状态,从而提高交易性能。批量操作:
allowMultiQueries=true,支持使用分号(;)将多个 SQL 拼接为一个请求,从而减少应用与数据库之间的交互,提高性能。对于批量插入操作,推荐设置 rewriteBatchedStatements=true 和 useServerPrepStmts=false,并使用 addBatch + executeBatch 方式。大结果集处理:
useCursorFetch=true 和 useServerPrepStms=true,在 Java 程序中用 setFetchSize(>0) 设置游标结果集,或用 setFetchSize(Integer.MIN_VALUE) 切换为流式结果集。在进行连接池配置时,应考虑以下几点:
testWhileIdle=true 以在连接空闲时验证有效性,testOnBorrow=true 在借用时验证,testOnReturn=false 在归还时不进行检测。如果网络环境不稳定,则建议将 testOnBorrow 设置为 true。在应用程序配置中,我们需要更加关注以下方面:
连接超时设置:
日志记录:
版本兼容性:
切换数据库:
use <dbname> 语句,而是应通过 Connection.setCatalog(dbname) 方法设置当前数据库,以提高代码的可读性和可维护性。Session 状态变量:
ReadOnly 等 Session 状态时,建议使用 JDBC 接口(如 setReadOnly 或 setTransactionIsolation),以确保代码的一致性和安全。事务处理:
getConnection)。在事务执行完毕后,务必关闭连接(通过 closeConnection)。每个事务的处理步骤应为:
getConnection:获取数据库连接。closeConnection:关闭数据库连接。