一次Spring项目“开发环境 Oracle 访问巨慢”问题的排查与解决

2026-02-02 204点热度 0人点赞 0条评论

一、问题背景

最近在本地调试一个老项目时,发现一个非常奇怪的现象:

  • 同一套 Oracle 数据库
  • 线上环境访问正常、执行很快
  • 本地开发环境访问却非常慢
  • 换到另一个 Spring Boot 项目 访问同一库,速度又是正常的

也就是说:
问题只出现在这一个老项目的本地环境中,同库、同网络条件,别的项目没问题。

这类问题最容易让人误判到 “网络”、“数据库本身”、“SQL 写得烂”等方向。
但既然同样的 SQL、同一个库、在其他项目里是快的,那基本可以锁定是 “项目自身的配置或技术栈造成的性能问题”

下面按照时间线,记录一下我是如何一步步定位并解决这个问题的。


二、初步假设与排查方向

根据现象,我一开始做了几个假设:

  1. SQL 自身有问题?

    • 用慢的项目和快的项目,分别执行同一条 SQL。
    • 在数据库里直接执行(例如 SQL Developer / PL/SQL Developer 等)。
    • 结论:SQL 在数据库侧执行很快,换到另一个项目里执行也很快 → 可以排除 SQL 本身问题。
  2. 数据库连接配置错误?

    • 驱动版本是否一致?
    • URL / 用户名 / 密码 是否一致?
    • 实际检查后发现,两个项目连接的是 同一套数据库,同一用户,驱动版本也兼容 → 基本可排除。
  3. 网络问题?

    • 开发机器到数据库服务器的网络延迟、丢包情况等。
    • 如果是网络问题,那所有项目都会慢,而不是只慢一个项目。
    • 实测其他项目访问同库正常 → 网络问题基本可以排除。

排除以上几类问题后,矛头就指向“项目内部对数据源、连接池的配置方式”


三、对比两个项目的配置

为了找差异,我特地对比了:

  • 这个“访问很慢”的传统 Spring MVC 项目(非 Spring Boot)
  • 一个访问同一数据库、性能正常的 Spring Boot 项目

1. 慢项目的数据源配置(XML)

在这个老项目中,数据源是通过 Spring XML 配置的,大致类似:

 

<bean id="dataSource"
      class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName">
        <value>${jdbc.driverClassName}</value>
    </property>
    <property name="url">
        <value>${jdbc.url}</value>
    </property>
    <property name="username">
        <value>${jdbc.username}</value>
    </property>
    <property name="password">
        <value>${jdbc.password}</value>
    </property>
</bean>

注意这里的实现类是:

class="org.springframework.jdbc.datasource.DriverManagerDataSource"

2. 同库正常的 Spring Boot 项目的数据源配置(YAML)

Spring Boot 项目则是类似下面这样的配置(以 Druid 为例):

spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driverClassName: oracle.jdbc.driver.OracleDriver
    druid:
      url: jdbc:oracle:thin:@xxx.xxx.xxx.xxx:1521:orcl
      username: xxx
      password: xxx
      initialSize: 5
      minIdle: 10
      maxActive: 20
      maxWait: 60000
      validationQuery: SELECT 1 FROM DUAL
      testWhileIdle: true
      testOnBorrow: false
      testOnReturn: false

可以看到,Spring Boot 项目使用的是 Druid 连接池,而老项目使用的是 DriverManagerDataSource


四、关键差异:DriverManagerDataSource vs 连接池

查了一下 Spring 文档,确认了一个关键点:

1. DriverManagerDataSource 的特性

  • 不是连接池实现
  • 每次从 dataSource.getConnection() 获取连接时,都会创建一个新的物理连接
  • 用完连接后关闭,下次再用又重新建连接
  • 优点:简单直观
  • 缺点:频繁建立/断开数据库连接,极大增加延迟和资源开销

在网络延迟较小、访问频率不高的场景下,这个缺点不太明显。
但在开发环境(比如到远端数据库,VPN/公网等)下,每次建连的网络、认证开销都被放大,就会表现为每次 SQL 执行都很慢

2. Druid / HikariCP 等连接池的特性

以 Druid 为例:

  • 启动时根据配置创建一定数量的数据库连接(初始连接池)
  • 连接在池中重复复用,不必每次都新建
  • 支持空闲连接检测、失效重连等机制
  • 对网络延迟和数据库建立连接的开销非常友好

所以,这就是为什么:

  • 同样的 Oracle 数据库
  • Spring Boot + Druid 的项目访问很快
  • 使用 DriverManagerDataSource 的老项目访问却很慢

根本原因:老项目本地环境没有使用连接池,每次请求都重新建 Oracle 连接。


五、解决思路:给老项目也上连接池

既然问题定位在数据源实现上,那么解决方案就很清晰了:

把 DriverManagerDataSource 换成一个真正的连接池实现,比如 Druid。

这里以 Druid 为例进行改造(不涉及任何具体项目名、IP 或库名)。

1. 添加 Druid 依赖(Maven)

在 pom.xml 中加入:

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.2.20</version>
</dependency>

版本号可以按自己项目实际情况选择,但建议选一个相对新的稳定版本。

2. 修改 Spring XML 中的数据源配置

将原来的:

<bean id="dataSource"
      class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName">
        <value>${jdbc.driverClassName}</value>
    </property>
    <property name="url">
        <value>${jdbc.url}</value>
    </property>
    <property name="username">
        <value>${jdbc.username}</value>
    </property>
    <property name="password">
        <value>${jdbc.password}</value>
    </property>
</bean>

替换为 Druid 连接池配置,例如:

<!-- Druid 数据库连接池 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
      init-method="init" destroy-method="close">
    <property name="driverClassName" value="${jdbc.driverClassName}"/>
    <property name="url" value="${jdbc.url}"/>
    <property name="username" value="${jdbc.username}"/>
    <property name="password" value="${jdbc.password}"/>

    <!-- 初始连接数 -->
    <property name="initialSize" value="${jdbc.initialSize:5}"/>
    <!-- 最小连接池数量 -->
    <property name="minIdle" value="${jdbc.minIdle:5}"/>
    <!-- 最大连接池数量 -->
    <property name="maxActive" value="${jdbc.maxActive:20}"/>
    <!-- 获取连接时的最大等待时间(毫秒) -->
    <property name="maxWait" value="${jdbc.maxWait:60000}"/>

    <!-- 下面几个可以写死在 XML,也可以抽到配置文件 -->
    <!-- 多久检测一次需要关闭的空闲连接(毫秒) -->
    <property name="timeBetweenEvictionRunsMillis" value="60000"/>
    <!-- 连接在池中最小生存时间(毫秒) -->
    <property name="minEvictableIdleTimeMillis" value="300000"/>

    <!-- 验证连接是否有效 -->
    <property name="validationQuery" value="SELECT 1 FROM DUAL"/>
    <property name="testWhileIdle" value="true"/>
    <property name="testOnBorrow" value="false"/>
    <property name="testOnReturn" value="false"/>
</bean>

这里有几点说明:

  • init-method="init" 和 destroy-method="close" 是 Druid 推荐的生命周期方法。
  • 连接池大小根据自己机器和数据库承载能力调整。
  • validationQuery 用的是 Oracle 常用的检测语句:SELECT 1 FROM DUAL

3. 在 properties 中添加连接池相关配置(可选)

如果希望连接池参数可配,可以在 jdbc.properties(或类似配置文件)中添加:

jdbc.driverClassName=oracle.jdbc.driver.OracleDriver
jdbc.url=jdbc:oracle:thin:@xxx.xxx.xxx.xxx:1521:orcl
jdbc.username=xxx
jdbc.password=xxx

# Druid 连接池配置
jdbc.initialSize=5
jdbc.minIdle=5
jdbc.maxActive=20
jdbc.maxWait=60000

再结合上面的 XML 就能动态读取这些值。


六、修改后的效果验证

完成以上修改后,我做了几步验证:

  1. 重新加载 Maven 依赖,重启应用
  2. 执行之前那些明显感觉“卡”的操作,比如某些列表查询、分页查询等
  3. 同时对比:
    • 修改前:一次查询需要等好几秒甚至十几秒
    • 修改后:几乎是秒回,体验和 Spring Boot 项目完全一致

再打开数据库侧的监控也能看到:

  • 连接数在一个合理区间内波动,而不是频繁创建、关闭连接
  • QPS、响应时间等指标回归正常

到此可以确认:
问题确实是由本地环境使用 DriverManagerDataSource 而非连接池造成的。


七、经验与总结

最后总结一下这次排查的几个关键点,供以后遇到类似问题时参考:

  1. 遇到“同库、同 SQL,某个项目慢,另一个项目快”的情况,优先怀疑:

    • 数据源实现
    • 连接池配置
    • 事务、超时设置等
  2. DriverManagerDataSource 只适合:

    • 测试、demo、小工具
    • 不适合作为生产或日常开发环境的数据源实现(特别是远程数据库)
  3. 对于老项目(非 Spring Boot)

    • 不要忘了手动配置连接池
    • 常见选择有:Druid、HikariCP、C3P0 等(现在推荐 Druid / HikariCP)
  4. 排查步骤可以遵循:

    • 先排除 SQL 本身、数据库本身的问题
    • 再对比不同项目的配置:驱动版本、URL、数据源类型、连接池参数
    • 注意观察数据源类名:DriverManagerDataSource 基本就意味着“没有连接池”
  5. 不要被“正式环境没问题”误导

    • 正式环境通常网络好、机器好、数据库更近,问题可能被掩盖
    • 开发环境往往更容易暴露这类连接建立开销问题

通过这次排查,也再次印证了一个老生常谈的原则:

性能问题,配置同样重要;
不仅要看 SQL 和代码,更要看运行环境和中间层(连接池、线程池等)的配置。


如果你以后也遇到:
“本地访问 Oracle(或其他数据库)巨慢,但同库的其他项目却很快”的情况,
不妨第一时间检查一下:

  • 你的 DataSource 是不是 DriverManagerDataSource
  • 项目里是不是压根没用连接池?

往往,这就是问题的根源。

admin

这个人很懒,什么都没留下

文章评论

您需要 登录 之后才可以评论