Oracle Express Edition 是 Oracle Enterprise Edition 的免费版本,其较小的体积使得测试各种 Oracle 功能非常方便。
根据 Oracle 文档 ,Express Edition 最多可以使用一个 CPU 和 1 GB RAM,但实际上还有其他并不总是很明显的限制。
数据库连接处理异常
以下测试试图模拟低延迟事务环境,因此连接的租用时间非常短:
private void simulateLowLatencyTransactions(
DataSource dataSource, int waitMillis)
throws SQLException {
for (int i = 0; i < callCount; i++) {
try {
try (Connection connection =
dataSource.getConnection()) {
//Let's assume we are running a
//short-lived transaction
sleep(waitMillis);
}
} catch (SQLException e) {
LOGGER.error("Exception on iteration " + i, e);
}
}
}
此测试工作正常,直到将等待时间降低到某个阈值以上,在这种情况下,数据库偶尔会开始抛出以下异常:
private void simulateLowLatencyTransactions(
DataSource dataSource, int waitMillis)
throws SQLException {
for (int i = 0; i < callCount; i++) {
try {
try (Connection connection =
dataSource.getConnection()) {
//Let's assume we are running a
//short-lived transaction
sleep(waitMillis);
}
} catch (SQLException e) {
LOGGER.error("Exception on iteration " + i, e);
}
}
}
尽管代码是单线程的,但 Oracle 开始抱怨连接请求侦听器无法找到处理传入请求的进程处理程序。
如果您喜欢阅读这篇文章,您可能想订阅 我的时事通讯 并获得 我的书 的折扣。
这个假设可以通过将 进程 和 会话 参数提高到更高的值来证明:
private void simulateLowLatencyTransactions(
DataSource dataSource, int waitMillis)
throws SQLException {
for (int i = 0; i < callCount; i++) {
try {
try (Connection connection =
dataSource.getConnection()) {
//Let's assume we are running a
//short-lived transaction
sleep(waitMillis);
}
} catch (SQLException e) {
LOGGER.error("Exception on iteration " + i, e);
}
}
}
使用这些新设置,代码运行良好并且没有发出异常。虽然增加 进程 和 会话 限制可以解决问题,但此解决方案只是一种变通方法,它只是提高了连接阈值,而不是解决根本原因。
IBM 故障排除说明 给出了一种可能的解释,表明连接关闭事件可能不会立即通知连接侦听器。这可能会导致连接侦听器错误地断言实际连接计数并假定已达到最大进程数。
在 Oracle 11g 企业版上,此问题不可复制。
修复
细心的读者在查看异常堆栈跟踪时会注意到这个问题。 OracleDataSource 不提供任何东西,这导致驱动程序和服务器端的大量连接建立开销。
如果您喜欢这篇文章,我敢打赌您也会喜欢 我的书 。
使用连接池解决了这个问题,因为连接被重用而不是按需建立。连接池显着减少了连接获取时间,这也导致更低的事务延迟和更好的吞吐量。
本文是我为我的 High-Performance Java Persistence 一书 所做的研究的一部分。如果您喜欢阅读它,您也可以 订阅关注我的进度 。