☰
Oracle 19c JDBC连接实战:驱动选型、URL配置与连接池调优
2026/10/9 6:23:00 网站建设 项目流程

去年年底帮朋友看一个老项目升级,数据库从 11g 迁移到 19c,应用层用的还是几年前封装的 JDBC 工具类。结果第一轮联调,测试环境直接抛了一堆异常,从ORA-12514到Unsupported major.minor version,再到ORA-28040,一晚上全碰了一遍。JDBC 连接 Oracle 19c 这件事,表面上看是个老掉牙的基础操作,但这几年 Oracle 的版本节奏变化很快,驱动、URL、权限模型都跟着变了,如果还拿十年前的习惯去写,踩坑几乎是必然的。

这篇文章就把我在多个项目里连接 Oracle 19c 时沉淀下来的完整方案和踩坑记录整理出来。包括驱动怎么选、URL 怎么写最稳、连接池参数怎么调、常见的 ORA 报错怎么排查,每一块我都会给出可以直接抄作业的配置和代码,顺便解释一下背后的原因。适合刚接手 Oracle 19c 项目的 Java 开发,也适合那些从 11g/12c 升级过来的老项目团队做参考。

1. 连接前的三个关键认知

动手写代码之前,我强烈建议先把三件事搞清楚。这三件事决定了你后面能不能顺利连上,以及项目上线后会不会出幺蛾子。

1.1 驱动选型:ojdbc8 还是 ojdbc11

很多人下意识觉得“数据库是 19c,那驱动也拿 19.x 的 ojdbc 就好了”,这个方向没错,但你得再往下分一层:Oracle 官方从 19c 开始,对驱动 jar 的命名做了调整,不再像以前那样一个ojdbc14.jar走天下,而是按 JDK 兼容性拆成了多个版本。

我列一下实际使用中最常见的两个:

驱动 jar兼容 JDK说明
ojdbc8.jarJDK 8绝大多数 Java 8 老项目首选,JDBC 4.2 规范
ojdbc11.jarJDK 11+对应 21c 及以后版本,但连接 19c 数据库完全没问题,JDK 17 项目建议用它

如果你的项目跑在 JDK 8 上,就用ojdbc8。如果是 JDK 11 或 17,优先ojdbc11。这里有个易错点:ojdbc11这个命名容易让人误以为“只支持 JDK 11”,实际上它支持 JDK 11 及以上,包括 17、21,所以 JDK 17 的项目不要回头去找什么ojdbc17,没有那个东西。

还有一个更老的ojdbc7.jar,只兼容 JDK 7,除非你是那种实在没法升级的老系统,否则直接忽略。Oracle 19c 对应的驱动版本号一般以19.x开头,比如19.3.0.0、19.14.0.0,这点在 Maven 坐标里能看到。

1.2 连接 URL:SID 和 Service Name 别再搞混

JDBC 连 Oracle 的 URL 有两种主流写法:

# 旧式 SID 写法,18c 之前常见 jdbc:oracle:thin:@192.168.10.20:1521:orcl # 新式 Service Name 写法,官方推荐 jdbc:oracle:thin:@//192.168.10.20:1521/ORCLPDB1

注意SID写法是@host:port:sid,一个冒号;而Service Name写法是@//host:port/service_name,两条斜杠加一个斜杠。很多从 11g 迁过来的项目,代码里还是旧写法,连到 19c 上就报ORA-12505。根本原因是 19c 默认安装的是容器数据库架构(CDB/PDB),业务账号通常建在 PDB 里,而你用 SID 去连,SID 对应的是 CDB 的实例名,PDB 并不是一个独立的 SID。

所以我的习惯是:19c 一律用 Service Name 写法。如果你不确定 PDB 的 service name,登录数据库执行:

SELECT value FROM v$parameter WHERE name = 'service_names';

或者直接问 DBA 要连接字符串。你自己本地写代码联调时,也可以用简单写法。

1.3 账号密码和权限模型

19c 的默认安全策略比 11g 严了不少。你拿到一个业务账号,先确认它建在哪个容器里。如果应用要连ORCLPDB1,账号必须是在这个 PDB 里创建的,或者至少有访问权限。用 CDB 的公共账号跨 PDB 去连,有时候能连上,但查询业务表时各种ORA-00942,排查起来很折腾,不如一开始就理清楚。

另外,19c 默认对SYSTEM密码过期策略、用户锁定策略都更严格。如果应用账号连续失败几次被锁了,代码里只会看到ORA-28000 the account is locked,这不是连接代码的问题,是账号策略的问题。

2. 最小可用的连接代码与依赖配置

理论说再多,不如先跑通一个最简单的连接。这一节给你一套完整的最小代码,从 Maven 依赖到 JDBC 连接,你直接复制就能跑。

2.1 Maven 依赖坐标

如果你用 Maven 管理项目,在pom.xml里加上:

<dependency> <groupId>com.oracle.database.jdbc</groupId> <artifactId>ojdbc8</artifactId> <version>19.14.0.0</version> </dependency>

如果项目走的是 Spring Boot 2.x 或者旧一点的结构,这个坐标完全够用。JDK 17 的项目把ojdbc8换成ojdbc11就行:

<dependency> <groupId>com.oracle.database.jdbc</groupId> <artifactId>ojdbc11</artifactId> <version>21.5.0.0</version> </dependency>

有个细节:如果你没配公司私服,直接访问 Maven 中央仓库下载这些坐标没问题,Oracle 官方的驱动坐标从 19c 开始已经同步推送到中央仓库了,不用再手动去 Oracle 官网下载 jar 放进本地 lib,省了很多事。不过如果团队里有老项目还是用 lib 方式管理 jar 包,那手动下载时注意选择ojdbc8.jar而不是那些名字带-g的调试版,带-g的包包含额外调试信息,体积更大,生产环境没必要用。

2.2 写一个最简单的连接测试类

直接看代码:

package demo; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.Statement; public class Oracle19cConnectDemo { // 用 Service Name,不要用 SID 写法 private static final String URL = "jdbc:oracle:thin:@//192.168.10.20:1521/ORCLPDB1"; private static final String USER = "app_user"; private static final String PASSWORD = "your_password"; public static void main(String[] args) { // 这行其实可省,因为 DriverManager 会自动加载 META-INF 里的驱动 // 但保留让你更明确地知道用的是哪个驱动 try { Class.forName("oracle.jdbc.driver.OracleDriver"); } catch (ClassNotFoundException e) { System.err.println("找不到驱动类,请确认 ojdbc jar 是否在 classpath 中"); e.printStackTrace(); return; } try (Connection conn = DriverManager.getConnection(URL, USER, PASSWORD); Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery("SELECT '连接成功' AS INFO, 1 AS V FROM dual")) { if (rs.next()) { System.out.println(rs.getString("INFO")); System.out.println("数据库产品版本: " + conn.getMetaData().getDatabaseProductVersion()); System.out.println("驱动版本: " + conn.getMetaData().getDriverVersion()); } } catch (Exception e) { e.printStackTrace(); } } }

dual是 Oracle 特有的单行单列表,用来做这种不带真实表名的简单查询特别方便。这段代码能跑通,说明你的驱动、URL、账号三要素都没问题。

2.3 为什么推荐 try-with-resources

上面代码里用的是 Java 7 之后的try-with-resources写法,Connection、Statement、ResultSet都会自动关闭。这比老代码里的finally里手动conn.close()更安全。

我之前接手过一个老项目,他们的封装工具类里close()写得乱七八糟,有的地方resultSet.close()之后又去connection.close(),异常路径下连接一直不释放,最后连接池被打满。如果你还在写手动的try-catch-finally关资源,我真心建议趁这次迁移改掉。尤其是 Oracle,连接是很贵的资源,释放不及时,DB 端会积累一堆INACTIVE会话,DBA 查过来第一眼就怀疑是应用连池没配好。

3. 连接池配置与参数调优实战

JDBC 直连只适合做测试和工具类,真实项目必须走连接池。目前 Java 生态里我用得最多的是 HikariCP 和 Druid,这里结合 Oracle 19c 把关键参数拆开讲。

3.1 HikariCP 连接 Oracle 19c 的推荐配置

如果你用的是 Spring Boot 2.x 及以上,默认连接池就是 HikariCP。在application.yml里可以这样调:

spring: datasource: url: jdbc:oracle:thin:@//192.168.10.20:1521/ORCLPDB1 username: app_user password: your_password driver-class-name: oracle.jdbc.OracleDriver hikari: minimum-idle: 5 maximum-pool-size: 15 connection-timeout: 30000 idle-timeout: 600000 max-lifetime: 1800000 connection-test-query: SELECT 1 FROM DUAL

如果是纯 Java 项目手动创建 HikariDataSource,代码类似:

HikariConfig config = new HikariConfig(); config.setJdbcUrl("jdbc:oracle:thin:@//192.168.10.20:1521/ORCLPDB1"); config.setUsername("app_user"); config.setPassword("your_password"); config.setDriverClassName("oracle.jdbc.OracleDriver"); config.setMaximumPoolSize(15); config.setMinimumIdle(5); config.setConnectionTimeout(30000); config.setIdleTimeout(600000); config.setMaxLifetime(1800000); config.setConnectionTestQuery("SELECT 1 FROM DUAL"); HikariDataSource dataSource = new HikariDataSource(config);

这里有几个参数值得你细品。max-lifetime默认值是 1800000 毫秒(30分钟),但 Oracle 的会话可能被数据库侧的 profile 限制为更短的 idle 时间,如果你的idle-timeout比数据库的空闲超时还大,连接池认为连接还活着,实际上已经被数据库杀了,这就埋下了一个“用的时候突然报连接关闭”的隐患。所以我个人的经验是:连接池的max-lifetime要小于数据库会话空闲回收时间,通常 30 分钟问题不大,但如果 DBA 那边静态参数改过,你就得同步调。

3.2 连接池参数背后的逻辑

为什么maximum-pool-size不能拍脑袋随便填?

Oracle 的进程/会话资源是有限度的。一个 19c 实例,默认processes参数可能只支持几百个进程。如果每个微服务实例都配maximum-pool-size: 100,三个服务一启动,直接把数据库进程数占满,其他业务全部卡死。常见的容量估算方式是这样的:

最大活跃请求数 = 服务实例数 × 单实例最大并发请求数 数据库承受能力 = 数据库后台进程 + 每个连接一个会话进程 + DBA/运维预留进程

你不需要把这个公式背下来,核心思想是:连接池大小 = (业务并发峰值 × 平均每个请求持有连接的时间) / 数据库可用会话数。大部分中小型系统,单实例 10-20 就够了。配 5 个太低,会导致请求排队;配 100 个,错觉是“性能好”,实际上数据库和网络层都背着隐形的连接开销。

connection-timeout这个参数也容易让新手踩坑。它是指从连接池借一个连接的超时时间,不是 TCP 建连超时。如果数据库真的挂了,你指望 HikariCP 在 30 秒内报错,但实际上 TCP 层可能已经在排队了,所以连接池层面通常还会配合一个oracle.net.CONNECT_TIMEOUT的 URL 属性来限制网络建连超时。这个后面在 URL 扩展参数里讲。

3.3 Druid 连接池的 Oracle 专项配置

国内很多老项目用的是 Druid。Druid 连 Oracle 时,除了基础配置,还推荐开testWhileIdle和timeBetweenEvictionRunsMillis:

spring: datasource: druid: driver-class-name: oracle.jdbc.OracleDriver url: jdbc:oracle:thin:@//192.168.10.20:1521/ORCLPDB1 username: app_user password: your_password initial-size: 5 min-idle: 5 max-active: 20 validation-query: SELECT 1 FROM DUAL test-while-idle: true time-between-eviction-runs-millis: 60000 min-evictable-idle-time-millis: 300000

Druid 的test-while-idle开启后,会定期检测空闲连接,但检测也是有代价的,如果池子小,time-between-eviction-runs-millis设成 60 秒足够。别把time-between-eviction-runs-millis设到没谱的 10 秒,那样数据库会被一堆探活 SQL 骚扰,尤其是SELECT 1 FROM DUAL在高峰期高频执行,DBA 看 AWR 报告会疯掉。

我遇到过最典型的一个案例:某系统从 11g 迁到 19c 后,Druid 连接池每隔几秒就报一次GetConnectionTimeoutException,排查到最后发现是连接在池子里被数据库侧提前回收了,而 Druid 的min-evictable-idle-time-millis设得比数据库的空闲限制还长,探活 SQL 又只在申请连接时才执行,导致池子以为连接没事,实际已经断了。解决办法就是把探活频率提高,或者缩短min-evictable-idle-time-millis。

4. 核心环节实现:从 URL 扩展到批量操作

前面还只是把“连上”跑通,实际项目里你会发现连上只是开始。这一节说说我在 Oracle 19c 上遇到的最有代表性的几个核心环节:URL 的扩展参数、批量写入优化、以及分页查询的典型写法。这几个点对系统体验的影响,往往比连接本身还大。

4.1 URL 扩展参数:一分钟定位连接超时

很多项目的 JDBC URL 就是裸的jdbc:oracle:thin:@//host:port/service,一旦数据库负载高或者网络抖动,应用层可能出现长达几十秒的卡顿,因为 TCP 默认超时时间很长。Oracle JDBC 驱动支持在 URL 后面拼接特定参数:

jdbc:oracle:thin:@//192.168.10.20:1521/ORCLPDB1?oracle.net.CONNECT_TIMEOUT=5000&oracle.jdbc.ReadTimeout=30000

参数说明:

参数作用建议值
oracle.net.CONNECT_TIMEOUTTCP 建连超时,毫秒5000-10000
oracle.jdbc.ReadTimeout读取 Socket 超时,毫秒30000-60000
oracle.jdbc.defaultRowPrefetch预取行数默认 10,分页查询可以调大

这个思路和 HikariCP 的connectionTimeout不冲突,前者控制的是“从连接池借连接”,后者控制的是“数据库 TCP 建连”。两个都配上才稳妥。

有朋友问过我:oracle.jdbc.ReadTimeout能不能设很大,避免大查询被中途掐断?我劝你换个思路。如果 SQL 本身要跑几分钟,就算 socket 不超时,应用线程也挂死在那里,连接池会被占满。更合理的做法是去优化 SQL 执行计划,让单次查询控制在秒级,ReadTimeout 只是兜底,不是救命稻草。

4.2 批量写入优化:调整 BatchSize

Oracle 的 JDBC 驱动和 MySQL 的rewriteBatchedStatements行为不太一样,MySQL 只要在 URL 上加个参数就能把批量 SQL 重写成多值插入,Oracle 没有这个开关。但 Oracle 也有自己的批量优化参数。

举个例子,假设你要向一张订单表插入一万条数据,普通的写法是循环preparedStatement.executeUpdate(),性能惨不忍睹。改成addBatch()后,如果不做任何参数调整,默认每次网络往返处理一批,批大小由内部参数控制。Oracle JDBC 支持在连接属性里设置:

Properties props = new Properties(); props.put("user", "app_user"); props.put("password", "your_password"); // 连接级批量阈值,默认 10 props.put("oracle.jdbc.defaultBatchValue", "100"); Connection conn = DriverManager.getConnection(url, props); PreparedStatement ps = conn.prepareStatement("INSERT INTO T_ORDER(ID, AMOUNT, CREATE_TIME) VALUES (?, ?, ?)"); for (int i = 0; i < 10000; i++) { ps.setLong(1, i); ps.setBigDecimal(2, new BigDecimal("100.50")); ps.setTimestamp(3, new Timestamp(System.currentTimeMillis())); ps.addBatch(); if (i % 100 == 0) { ps.executeBatch(); ps.clearBatch(); } } ps.executeBatch();

这里的oracle.jdbc.defaultBatchValue设置为 100,意思是驱动攒够 100 条后再走一次网络批量发送。你可以对比测试,相比默认配置,一万条数据插入时间通常能缩短一半以上。

需要提醒的是:addBatch()的 burst 频率不是越高越好。JDBC 批处理的花费主要在解析 SQL、绑定参数、网络传输、数据库执行。如果 batch 太大,单次批量执行的时间太长,事务要等很久才能提交,锁的范围也会变大。我用下来的经验是 50 到 200 比较合适,小表 100,大表 50,具体还是结合行长度和网络延迟来调。

4.3 分页查询:ROWNUM 和 FETCH FIRST 的取舍

说到 JDBC 操作 Oracle,分页是绕不开的。老项目里最常见的写法是基于ROWNUM的三层嵌套:

SELECT * FROM ( SELECT TMP.*, ROWNUM RN FROM ( SELECT ID, NAME FROM T_USER ORDER BY ID ) TMP WHERE ROWNUM <= ? ) WHERE RN > ?

这种写法在很多系统里跑得好好的,但也有个问题:随着页码越翻越深,ROWNUM要扫描并丢弃的记录越多。Oracle 12c 之后引入了行限制子句,19c 自然是支持的,可以写得非常简洁:

SELECT ID, NAME FROM T_USER ORDER BY ID OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY;

看上去很美,但我要泼一盆冷水:这个语法在底层实现上和ROWNUM并没有本质区别,如果表本身没有合适索引,深度翻页照样慢。真正治本的方法是做“键集分页”,也就是记住上一页最后一条记录的排序键,然后WHERE ID > ?加FETCH NEXT 10 ROWS ONLY。

如果你的项目是给后台管理系统用的,数据量在百万以内,用OFFSET FETCH完全没问题,代码可读性好太多。如果是千万级以上的大表,建议别偷懒,老老实实用排序键 + 游标式分页,这也是 JDBC 连接 Oracle 时最常见的性能优化方向之一。

5. 连接池与 SQL 层的常见坑点排查

实际运行系统时,报错往往不是连接建立那一下,而是用着用着突然出问题。所以专门写一节排查记录,方便你以后对照自查。

5.1 数据库端连接数暴涨怎么处理

典型场景:应用连的是 PDB,连接池大小没变,但数据库的会话数一直在涨,甚至把processes打满。首先看是不是连接池泄露。Druid 和 HikariCP 都提供监控接口,HikariCP 可以通过 health check 注册指标,Druid 有自带的监控页面。排查思路是:

  1. 先查数据库的 v$session,按 machine 和 username 分组,看是不是某一台应用服务器的连接数异常。
  2. 再到应用侧看连接池当时的 active 数量是否匹配。如果 DB 侧多出来的连接全部是INACTIVE,多半是应用侧没有正常归还连接,或者连接池的idleTimeout太长导致连接一直不释放。
  3. 顺手看last_call_et,如果某些 session 有个很大的值,说明可能有慢 SQL 卡住,把连接长期占用,导致池子被迫新建更多连接。

如果你用 HikariCP,可以在application.yml里开启leak-detection-threshold,这个参数用来检测连接泄露:

spring: datasource: hikari: leak-detection-threshold: 30000

超过 30 秒未归还的连接会被打印出来,非常好用。

5.2 Oracle 监听无法启动与 JDBC 报错的关系

有时候 JDBC 报IO Error: The Network Adapter could not establish the connection,根本原因是 Oracle 监听服务挂了。很多从 11g 迁移上来的运维团队会遇到甲方环境不熟、监听日志路径不对、端口占用哪些问题。我只说一个和 JDBC 相关的点:监听服务和 19c 的 PDB 注册关系。

19c 安装后,如果 PDB 是在监听启动之后才创建的,监听可能没有自动注册这个 PDB 的 service name。这时候你在应用侧用 PDB 的 service name 去连,报错往往是ORA-12514,但用 SID 去连又可能通。排查方式很简单,用lsnrctl status看监听暴露了哪些 service,如果 PDB 的 service name 不在列表里,就手动执行alter system register强制注册。这个操作 DBA 一般都会,但如果你自己开发环境遇到了,这行命令能救你一次。

还有一个高频坑:19c 默认使用动态端口还是 1521,看你装的时候怎么选。如果选的是非标准端口,JDBC URL 里的端口写错是必然的。我的建议是开发环境的端口统一写成 1521,理由不是 1521 有多好,而是团队成员多,少一个“我明明用的是对的主机为什么连不上”的排查成本。

5.3 时区问题导致时间差 8 小时

Oracle 19c 的TIMESTAMP WITH TIME ZONE类型和 JDBC 驱动之间有时区处理的细节。我碰到过一次特别隐蔽的坑:通过 JDBC 向TIMESTAMP列插入java.time.LocalDateTime,查出来时间一致;但换到TIMESTAMP WITH TIME ZONE列,查出来总是差 8 小时。

原因在于驱动默认使用 JVM 的时区去解释参数的时区。如果应用服务器时区是 Asia/Shanghai,数据库的 dbtimezone 设成了 UTC,那一进一出,时差就出来了。解决办法有两个方向:

  1. 简单粗暴:统一所有环境的 JVM 时区、数据库时区,再加上jdbc:oracle:thin:@//...的oracle.jdbc.timezoneAsRegion参数:
oracle.jdbc.timezoneAsRegion=false
  1. 规范写法:所有时间字段在应用里都用OffsetDateTime或ZonedDateTime,不要一边用LocalDateTime一边期望数据库帮你换算时区。

如果你的系统只在国内跑,而且历史表全是DATE或TIMESTAMP(不带时区),那 90% 的场景可以忽略这个问题。但如果你接了跨境业务,或者需要和不同时区的系统对接,这个坑一定要提前知道。

5.4 JDK 模块化与 ojdbc 的兼容

最后说一个 Java 17 用户特别容易踩的坑。JDK 9 之后推出了模块化系统,旧版的 ojdbc8/ojdbc11 在 Java 17 上运行,启动时可能出现:

java.lang.NoClassDefFoundError: javax/xml/bind/DatatypeConverter

这是因为 JDK 高版本移除了 Java EE 相关的模块。解决方式有两种。一种是最省事的:换用新版驱动,比如 Oracle 19.15.0.0 及之后的 ojdbc11,里面已经适配了 Java 17 的模块限制。另一种是如果你还用老驱动,必须在 JVM 启动参数里补上旧的 JAXB 依赖 jar。我个人强烈建议走第一条路,不要在 2024 年了还跟 JVM 模块较劲。

顺带一提,如果你在 JDK 17 下用 Spring Boot 3.x,那么ojdbc11的兼容性是经过 Spring Boot 官方认可的,直接配没问题。Spring Boot 2.x 用的还是 javax 命名空间,驱动是ojdbc8还是ojdbc11都能跑,但更推荐ojdbc8,因为ojdbc8本身在 Java 8 和 Java 11 上都稳。

6. 常见报错速查表

这一节是纯干货,以后连不上时直接翻。

报错信息可能原因解决方案
ORA-12514: TNS:listener does not currently know of service用了 Service Name 但监听器没注册这个服务,或服务名写错检查 PDB 的 service name,执行alter system register注册
ORA-12505: TNS:listener does not currently know of SID用了 SID 但连接的库是容器库,PDB 不算 SID改用jdbc:oracle:thin:@//host:port/service_name
ORA-28040: No matching authentication protocol客户端驱动太老,19c 数据库的认证协议不兼容升级驱动,至少用 19c 或 21c 的 ojdbc
ORA-01017: invalid username/password; logon denied用户名或密码错误,或账号在错误的 PDB 中核对账号名,确认在目标 PDB 里创建
ORA-28000: the account is locked账号连续试错被锁DBA 执行ALTER USER xxx ACCOUNT UNLOCK
Listener refused the connection with the following error: ORA-12560监听服务没起来,或协议配置错误启动监听,检查sqlnet.ora
Unsupported major.minor version 52.0JDK 版本低于驱动要求升级 JDK 或换低版本驱动
java.sql.SQLException: Io 异常: Got minus one from a read call数据库连接被强制关闭或网络异常检查数据库会话超时、防火墙、socket timeout
ORA-00942: table or view does not exist账号没有该表的权限,或连接的 PDB 不对授权GRANT SELECT ON xxx TO user,或者确认连接到正确的 PDB

这张表里的内容都是我实际遇到过、帮别人排查过的,不是从文档里抄的。特别提醒那条ORA-12514,它出现的频率在 19c 环境里远高于旧版,因为 PDB 架构把“实例”和“服务”拆开了,很多老 DBA 第一次接触也懵。

7. 最后的实操经验分享

写到这里,我把自己这几年的体会再沉淀几句。

第一,不要把 JDBC 连接 Oracle 19c 当成一个“能连上就完事”的任务。连接成功只是起点,真正影响项目下线的往往是连接池参数、时区、批量提交、网络超时这些细节。我见过太多项目“开发环境跑得好好,一上生产就报连接池爆满”,一查都是参数没调或者连接没归还导致的。

第二,排查问题时要有顺序意识。遇到连接异常,先确认驱动和 JDK 版本匹配,再确认 URL 用的是 Service Name,再确认账号建在正确的 PDB,最后才考虑应用代码和连接池。按照这个顺序来,大多数情况下能在十分钟内定位问题。如果一上来就翻代码找 SQL,只会浪费更多时间。

第三,也是最实用的一点:在正式联调前,先把最小的 JDBC 连接测试代码跑通,再用到框架里。这个过程看起来多一步,实际能省很多事。因为你用框架接的时候,报错信息会被 Spring、MyBatis、Druid 层层包装,核心原因容易被藏起来。直接写一个main方法去连,反而最干净。我每次到一个新环境,第一件事就是拿这段测试代码跑一遍,通了再接业务,这个习惯帮我少踩了无数坑。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询