ThinkPHP踩坑记录之数据库篇

虽然这么多年来ThinkPHP框架已经更新到大版本8了,越来越接近Laravel框架了,但是ThinkPHP 8框架还是有很多坑,我在工作中遇到不少,在此记录一下,以警醒后来人。

第1个坑,使用Db门面的inserA()批量插入数据到Oracle报错

因为ThinkPHP生成的批量插入SQL语句不符合Oracle语法。

避开这个坑的一个方法是,使用循环语句一条条地插入数据到Oracle,不要使用inserA()批量插入数据。

第2个坑,使用Think ORM操作Oracle 11g报错:SQLSTATE[HY000]: General error: 972 OCIStmtExecute: ORA-00972: identifier is too long

Oracle 11g的标识符的名字的长度不能超过30字节,标识符包括表名、视图名、序列名或触发器名。Oracle后续版本把标识符的名字的长度上限提高到了128字节。

ThinkPHP ORM 在处理 Oracle 时,有一个内部规范化逻辑(在 think-orm/src/db/connector/Oracle.phpBuilder 类中),会把表名/字段名转为小写+ 下划线风格(snake_case),以兼容 Oracle 的大小写不敏感特性。但当表名本身就包含大写或下划线时,这种转换会产生超长的蛇形名称,例如,把VIEW_JW_SPECIALTYDIRECTION转换为v_i_e_w__j_w__s_p_e_c_i_a_l_t_y_d_i_r_e_c_t_i_o_n,从而触发 Oracle 的长度限制。

Windows系统PHP8.4安装oci8扩展的方法

在 Windows 系统上为 PHP 8.4 安装 Oracle 扩展(主要是 OCI8,因为它功能最完整、社区支持最好,适合生产环境连接 Oracle 数据库,包括 11g),过程比 Linux 简单得多:不需要编译,直接下载预编译好的 DLL 文件 + 配置PATH环境变量 + 修改 php.ini 即可。

注意,PDO_OCI 扩展在 Windows 上也支持,但功能较弱(不支持某些高级绑定、LOB 流式等),生产环境强烈推荐 OCI8扩展。以下以 OCI8 扩展为例。

下载 Oracle Instant Client(必须)

Instant Client 是 Oracle 的免费客户端库,OCI8 DLL 需要它才能运行。

1 下载Instant Client

访问 Oracle 官网下载页https://www.oracle.com/database/technologies/instant-client/winx64-64-downloads.html,选择 最新版本(推荐 23.x 或 21.x/19.x,兼容 Oracle 11g)。

下载 Basic 或 Basic Light ZIP 包(例如instantclient-basic-windows.x64-23.26.1.0.0.zip)。

可选下载 SDK 包,如果需要编译其他东西,但预编译 DLL 不需要下载 SDK 包。

2 解压到目录

例如

C:\oracle\instantclient_23_0

注意,路径不要有空格、中文,推荐放在 C 盘根目录或 Programs 下。

3 添加环境变量(非常重要,否则运行时找不到库)

右键“此电脑” → 属性 → 高级系统设置 → 环境变量。在“系统变量”中找到 Path(或新建),点击编辑 → 新建 → 添加:

C:\oracle\instantclient_23_0

点击确定保存。

重启电脑 或重启命令提示符/PowerShell,让 PATH 生效。

4 安装 Visual C++ Redistributable

下载最新版 Microsoft Visual C++ Redistributable(x64):

https://aka.ms/vs/17/release/vc_redist.x64.exe

安装后重启电脑。

下载预编译的 OCI8 DLL

Windows 上不推荐用 pecl install oci8(因为 Windows 没有编译环境),直接用 PECL 官网提供的 DLL。

1 访问 PECL OCI8 页面

https://pecl.php.net/package/oci8

点击最新稳定版(如 3.4.1 或更高,2025-2026 年最新版支持 PHP 8.3/8.4)。

2 在页面向下滚动,找到 DLL 的下载链接

选择 PHP 8.4 TS(Thread Safe,如果你的 PHP 是 Thread Safe 版)或 NTS(Non-Thread Safe)。

如何判断你的 PHP 是 TS 还是 NTS?参见Windows系统Thread Safe版本和Non Thread Safe版本的PHP的区别

下载对应的 ZIP(如php_oci8-3.4.1-8.4-ts-vs17-x64.zip,注意如果你的PHP是x86版本的,那么应该下载php_oci8-3.4.1-8.4-ts-vs17-x86.zip)。

3 复制oci DLL文件到PHP扩展目录

解压 ZIP 文件,得到 php_oci8.dll(或 php_oci8_12c.dll、php_oci8_19c.dll 等,根据 Instant Client 版本命名)。

复制这个 DLL 到你的 PHP 扩展目录,例如C:\php\ext\(即你的 PHP 安装路径下的 ext 文件夹)。

配置 php.ini

找到 php.ini 文件(通常在 PHP 安装目录,如 C:\php\php.ini)。 用记事本或 VS Code 打开,找到 [ExtensionList] 或搜索 “extension=”。根据你下载的 DLL 名添加一行:

extension=php_oci8_19

保存 php.ini。

重启 Web 服务器:

  • IIS:重启 IIS(iisreset)。
  • Apache/XAMPP/WAMP:重启服务。
  • 关闭所有命令提示符窗口,重新打开。

验证oci扩展是否安装成功

1 打开一个CMD窗口,运行:

php -m | findstr oci8

应该输出 oci8(无警告)。

2 创建php测试脚本 test_oci.php:

<?php
$conn = oci_connect('system', '你的密码', '127.0.0.1:1521/orcl');  // 替换为你的连接字符串,如 SID 或服务名
if (!$conn) {
    $e = oci_error();
    echo "连接失败: " . $e['message'];
} else {
    echo "OCI8 连接成功!\n";
    oci_close($conn);
}

打开一个CMD窗口,运行:

php test_oci.php

或通过浏览器访问(如果用 Web 服务器)。

常见问题及解决方法

1 无法加载 php_oci8.dll(The specified module could not be found)

解决方法是,确认 Instant Client 的 Path 已添加到系统环境变量,且重启电脑。

2 DLL 版本与PHP版本必须匹配

解决方法是,Instant Client 19c+ 用 php_oci8_19c.dll 或 php_oci8.dll。

3 DLL 加载失败缺少 VC++ Redist

解决方法是,重新安装 Visual C++ Redistributable x64。

4 Warning: PHP Startup: Unable to load dynamic library ‘php_oci8_19’ (tried: ext\php_oci8_19 (%1 不是有效的 Win32 应用程序。), ext\php_php_oci8_19.dll (找不到指定的模块。)) in Unknown on line 0

这个错误的原因是,dll位数(x86或x64)与PHP的位数(x86或x64)不匹配。根据“不是有效的 Win32 应用程序”这个报错信息,解决方法是,下载x64版本的dll重新安装一下。

Ubuntu24系统PHP8.3安装并启用PDO_OCI扩展的方法

PDO_OCI 和 OCI8 是两个平行、独立的 Oracle 数据库驱动,都直接基于 Oracle Instant Client 的 OCI C API 实现,互不依赖,可以单独或同时使用。

如果你当前项目是基于 PDO 的现代应用,优先考虑 PDO_OCI(安装方式比 OCI8 简单一些);如果需要更强大的 Oracle 原生功能,再装 OCI8。

在 Ubuntu 24.04(Noble Numbat)上,PHP 8.3 的 PDO_OCI 扩展 没有预编译的 apt 包(php8.3-pdo-oci 或类似不存在),官方 Ubuntu 仓库和 Ondřej Surý PPA 都不提供它。

PDO_OCI 扩展需要从 PHP 源码中编译(或通过 pecl install pdo_oci,但 pecl 版本在 PHP 8.3+ 上已过时或不推荐),并且必须依赖 Oracle Instant Client(与 OCI8 相同)。

下面是在 Ubuntu 24.04 + PHP 8.3 上开启 PDO_OCI 的推荐、可行步骤。

先决条件(必须先完成)

安装 Oracle Instant Client,具体如何安装参见Ubuntu24系统PHP8.3安装oci8扩展(针对Oracle Database 23ai Free数据库)的方法

开启 PDO_OCI 的两种主要方式

方式一:、通过 pecl install pdo_oci(推荐先尝试,PHP 8.3+ 支持)

sudo pecl install pdo_oci

安装过程中会提示:

Please provide the prefix of Oracle installation:

输入你的 Instant Client 路径,例如:

instantclient,/opt/oracle/instantclient_23_26

如果成功,pecl 会自动安装并提示添加 extension=pdo_oci.so 到 php.ini。

启用扩展:

echo "extension=pdo_oci.so" | sudo tee /etc/php/8.3/mods-available/pdo_oci.ini
sudo phpenmod pdo_oci

重启服务(CLI 不需重启,但建议):

sudo systemctl restart php8.3-fpm   # 如果用 FPM
sudo systemctl restart apache2

验证pdo_oci扩展是否成功启用:

php -m | grep -i oci

在输出中应该看到 pdo_oci。

方式二、从 PHP 源码手动编译(如果 pecl 失败,成功率更高)

1 下载 PHP 8.3 源码(要与你当前PHP版本匹配,例如 8.3.6):

wget https://www.php.net/distributions/php-8.3.6.tar.gz
tar -xzf php-8.3.6.tar.gz
cd php-8.3.6/ext/pdo_oci

2 准备编译:

phpize

3 配置(关键:指定 Instant Client 路径):

./configure --with-pdo-oci=instantclient,/opt/oracle/instantclient_23_26

如果提示缺少头文件,确保 Instant Client 的 SDK 已解压(包含 include/ 目录)。

如果报错 oci.h not found:检查路径是否正确,或把 Instant Client 的 include 路径加到环境变量:

export CFLAGS="-I/opt/oracle/instantclient_23_4/sdk/include"
./configure --with-pdo-oci=instantclient,/opt/oracle/instantclient_23_4

4 编译并安装:

make
sudo make install

5 启用扩展:

echo "extension=pdo_oci.so" | sudo tee /etc/php/8.3/mods-available/pdo_oci.ini
sudo phpenmod pdo_oci
sudo systemctl restart php8.3-fpm apache2

6 验证pdo_oci扩展是否成功启用:

php -m | grep -i oci

在输出中应该看到 pdo_oci。

编写测试脚本测试PDO_OCI扩展是否可用

创建测试脚本 test_pdo_oci.php:

<?php
try {
    $dsn = 'oci:dbname=//127.0.0.1:1521/FREEPDB1;charset=AL32UTF8';
    $pdo = new PDO($dsn, 'system', '你的密码');
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    
    $stmt = $pdo->query('SELECT name, open_mode FROM v$pdbs');
    while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
        print_r($row);
    }
    
    echo "PDO_OCI 连接成功!\n";
} catch (PDOException $e) {
    echo "连接失败: " . $e->getMessage();
}

运行:

php test_pdo_oci.php

如果输出 PDB 状态信息,说明成功。

常见问题和注意事项

  • pecl install pdo_oci 报错:如果提示 “channel not found” 或版本过时,直接用方式 2 手动编译。
  • libaio / libnnz / libclntsh 等库找不到:回到 Instant Client 环境变量设置 + ldconfig + 符号链接。
  • PHP 版本不匹配:确保 phpize 来自 php8.3(phpize –version 应显示 8.3)。
  • 生产环境:PDO_OCI 功能比 OCI8 弱(不支持某些高级绑定、LOB 流等),建议只用于简单 CRUD。如果项目允许,优先 OCI8。

最佳实践

  • 企业级 / 复杂项目(涉及 PL/SQL、包、游标、大字段、分页优化):几乎 100% 用 OCI8。
  • 简单读写(只是查询/插入几张表):PDO_OCI 也能用,但稳定性不如 OCI8。如果你的项目已经用了 PDO 统一抽象层,且只做简单操作,可以试 PDO_OCI。
  • Oracle 官方和 PHP 社区也推荐 OCI8 作为 “premier interface” 用于 Oracle + PHP。

Ubuntu24系统PHP8.3安装oci8扩展(针对Oracle Database 23ai Free数据库)的方法

针对 Oracle Database 23ai Free(这是一个多租户架构的数据库,使用 Pluggable Database 或 PDB),PHP 最合适的 Oracle 扩展是 OCI8(Oracle Call Interface 8)。这是 Oracle 官方推荐的扩展,它提供高性能、全面的 Oracle 数据库交互功能,包括对 23ai 的完整支持(如 AI 向量搜索、JSON 等新特性)。

虽然 PDO_OCI(PDO 的 Oracle 驱动)也是一个选项,但它功能较 OCI8 有限(例如不支持 LOB 流式处理或某些高级绑定),且维护较少。OCI8 是首选,尤其在生产环境中。对于 PHP 8.3.6 和 Oracle 23ai Free,OCI8 3.4+ 版本完全兼容。

安装 OCI8 扩展的步骤

OCI8 依赖 Oracle Instant Client(客户端库)。对于 Oracle 23ai,推荐使用 Instant Client 23.x(最新版如 Version 23.26.1.0.0 (Requires glibc 2.28) 或更高,以确保最佳兼容性)。

以下是详细步骤(需要 root 权限,确保备份系统):

1 安装依赖包

sudo apt update
sudo apt install -y php8.3-dev php-pear libaio1 unzip build-essential

如果报错说“找不到libaio1”,解决方法参见Ubuntu24系统PHP8.3安装oci8扩展后启用报错:/usr/lib/php20230831/oci8.so (libaio.so.1 cannot open shared object file No such file or directory)的解决方法

2 下载 Oracle Instant Client

访问 Oracle 官网 Instant Client 下载页oracle.com/database/technologies/instant-client/downloads.html。

下载 Linux x86-64 的 Basic PackageSDK Package(如oracle-instantclient-basic-23.26.1.0.0-1.el10.x86_64.rpm和oracle-instantclient-devel-23.26.1.0.0-1.el10.x86_64.rpm)。如果 RPM 不便,用 ZIP 版(如instantclient-basic-linux.x64-23.26.1.0.0.zip 和 instantclient-sdk-linux.x64-23.26.1.0.0.zip)。

对于 ZIP 版,解压到如 /opt/oracle/instantclient_23_26/:

sudo mkdir -p /opt/oracle
cd /opt/oracle
sudo unzip /path/to/instantclient-basic-linux.x64-23.26.1.0.0.zip
sudo unzip /path/to/instantclient-sdk-linux.x64-23.26.1.0.0.zip

3 设置环境变量

编辑 /etc/profile.d/oracle.sh(新建如果不存在):

sudo nano /etc/profile.d/oracle.sh

添加:

export ORACLE_HOME=/opt/oracle/instantclient_23_26
export LD_LIBRARY_PATH=$ORACLE_HOME:$LD_LIBRARY_PATH
export PATH=$ORACLE_HOME:$PATH

使环境变量和Oracle Instant Client相关共享库立即生效、可用:

source /etc/profile.d/oracle.sh
sudo ldconfig

注意,如果有其他终端窗口开着,需要先登出系统再登录才能使上述使环境变量和Oracle Instant Client相关共享库生效、可用。

4 安装 OCI8 扩展

使用 pecl 安装(指定 Instant Client 版本):

sudo pecl install oci8

当提示 “instantclient,/path/to/client/lib” 时,输入instantclient,/opt/oracle/instantclient_23_26

如果提示 PHP 版本错误,确保 pecl 使用 PHP 8.3:sudo pear config-set php_bin /usr/bin/php8.3

5 配置 PHP

添加oci8扩展到 php.ini(CLI 和 FPM/Apache,根据你的 PHP 使用方式):

echo "extension=oci8.so" | sudo tee /etc/php/8.3/mods-available/oci8.ini
sudo phpenmod oci8

如果用 Apache,重启:

sudo systemctl restart apache2

如果用 PHP-FPM,重启:

sudo systemctl restart php8.3-fpm

验证oci8扩展是否启用成功:

php -m | grep oci8

在输出中应看到 oci8。

PHP 测试脚本(test_oracle_connection.php)

以下是一个简单脚本,使用 OCI8 扩展连接 Oracle 23ai Free数据库。保存为 .php 文件,在命令行运行 php test_oracle_connection.php 或通过 Web 服务器访问:

<?php
// 连接参数(调整为你的实际值)
$username = 'system';
$password = '密码';
$connection_string = '127.0.0.1:1521/FREEPDB1';  // EZCONNECT 格式:主机:端口/服务名

// 尝试连接
$conn = oci_connect($username, $password, $connection_string, 'AL32UTF8');  // 指定字符集,避免中文乱码

if (!$conn) {
    $error = oci_error();
    echo "连接失败: " . htmlentities($error['message'], ENT_QUOTES);
    exit;
}

// 连接成功,执行一个简单查询测试
$stmt = oci_parse($conn, 'SELECT name, open_mode FROM v$pdbs');
oci_execute($stmt);

echo "连接成功!PDB 状态:\n";
while ($row = oci_fetch_array($stmt, OCI_ASSOC + OCI_RETURN_NULLS)) {
    echo $row['NAME'] . " - " . $row['OPEN_MODE'] . "\n";
}

// 关闭连接
oci_free_statement($stmt);
oci_close($conn);

注意,脚本中用了 EZCONNECT 格式(无需 tnsnames.ora)。

如果脚本运行成功,会显示 “连接成功!PDB 状态:” 后跟 PDB 列表(如 FREEPDB1 – READ WRITE)。

兼容性说明

PHP 的 OCI8 扩展完全兼容 Oracle 11g(包括 11g Release 2,即 11.2.x 版本):

  • 很多遗留系统用 PHP 7/8 + OCI8 连接 Oracle 11g 运行多年。
  • Laravel + yajra/laravel-oci8 包也支持连接 11g。
  • 官方教程(如 Oracle 的 PHP + 11g 示例)直接使用 OCI8。

潜在小问题(极少见):

  • 如果你的 Oracle 11g 是非常早的 11.1(非 11.2),兼容性稍差,但 11.2 是主流版本,完全没问题。
  • 某些非常新的 OCI8 特性(如 oci_set_call_timeout,需要客户端 18c+)在 11g 上不可用,但基本 CRUD 操作、绑定、LOB、存储过程等全部正常。
  • 字符集:建议用 AL32UTF8,避免老的 WE8MSWIN1252 导致乱码。

测试兼容性的简单 PHP 脚本:

<?php
$conn = oci_connect('system', '你的密码', '127.0.0.1:1521/orcl');  // 替换为你的连接字符串,如 SID 或服务名

if (!$conn) {
    $e = oci_error();
    echo "连接失败: " . htmlentities($e['message'], ENT_QUOTES);
} else {
    echo "成功连接到 Oracle 11g!\n";
    
    $s = oci_parse($conn, 'SELECT * FROM v$version');
    oci_execute($s);
    
    while ($row = oci_fetch_array($s, OCI_ASSOC)) {
        print_r($row);
    }
    
    oci_close($conn);
}

运行后如果能看到数据库的版本信息(如 “Oracle Database 11g Release 2″),就证明兼容性没问题。

Ubuntu24系统PHP8.3安装oci8扩展后启用报错:/usr/lib/php20230831/oci8.so (libaio.so.1 cannot open shared object file No such file or directory)的解决方法

PHP Warning: PHP Startup: Unable to load dynamic library 'oci8.so' (... libaio.so.1: cannot open shared object file: No such file or directory ...)

这个报错说明 OCI8 扩展编译和安装都成功了,但运行时找不到 libaio.so.1 这个共享库。

libaio 是 Oracle Instant Client 和 OCI8 必须依赖的异步 I/O 库(libaio1 包提供),Ubuntu 上默认不一定预装,或者安装后路径/链接有问题。

解决方法是安装 libaio1 包:

sudo apt update
sudo apt install libaio1
正在读取软件包列表... 完成
正在分析软件包的依赖关系树... 完成
正在读取状态信息... 完成
没有可用的软件包 libaio1,但是它被其它的软件包引用了。
这可能意味着这个缺失的软件包可能已被废弃,
或者只能在其他发布源中找到
E: 软件包 libaio1 没有可安装候选

以上报错是因为 Ubuntu 24.04 (Noble Numbat) 引入了 64-bit time_t 迁移(time_t 从 32 位升级到 64 位,以避免 2038 年问题),导致许多库包名后缀改为 t64。

原来的 libaio1 包已被废弃/移除。替换包是 libaio1t64(提供相同的功能,共享库名为 libaio.so.1t64)。

Oracle Instant Client(例如 23.x 版本)的PHP扩展oci8仍然链接到旧的 libaio.so.1(SONAME 未更新),所以即使安装了 libaio1t64,OCI8 加载时还是找不到 libaio.so.1,报错 libaio.so.1: cannot open shared object file。

解决这个问题步骤如下:

1 安装正确的包(libaio1t64):

sudo apt update
sudo apt install libaio1t64

这会安装/usr/lib/x86_64-linux-gnu/libaio.so.1t64文件(或类似路径)。

2 创建符号链接,让系统/Instant Client 能找到旧名字 libaio.so.1

先确认共享库libaio.so的路径(通常在下面位置):

find /usr/lib /lib -name "libaio.so.1t64" 2>/dev/null

输出如下:

/usr/lib/x86_64-linux-gnu/libaio.so.1t64

然后创建软链接:

sudo ln -s /usr/lib/x86_64-linux-gnu/libaio.so.1t64 /usr/lib/x86_64-linux-gnu/libaio.so.1

有些 Oracle Instant Client 可能还找 libaio.so,因此额外保险做法是:

sudo ln -s /usr/lib/x86_64-linux-gnu/libaio.so.1t64 /usr/lib/x86_64-linux-gnu/libaio.so

如果你的 Instant Client 目录下也需要libaio.so.1和libaio.so(极少见,但可尝试),进入你的 Instant Client 目录(如 /opt/oracle/instantclient_23_26):

cd /opt/oracle/instantclient_23_26
sudo ln -s /usr/lib/x86_64-linux-gnu/libaio.so.1t64 libaio.so.1
sudo ln -s /usr/lib/x86_64-linux-gnu/libaio.so.1t64 libaio.so

3 更新动态链接器缓存(让系统立即识别新链接):

sudo ldconfig

4 验证是否解决了上述问题

检查库是否存在:

ldconfig -p | grep libaio

在输出信息中应该看到 libaio.so.1(或 libaio.so.1t64)。

测试 PHP 加载 OCI8扩展:

php -m | grep oci8

如果输出 oci8,表示加载成功!

补充说明

libaio1t64包和libaio1包是二进制兼容的,t64 迁移只改了 time_t 类型,不会破坏 libaio 的 API。

用Navicat连接docer容器里的Oracle,报错 ORA-12514: TNS:listener does not currently know of service requested in connect descriptor的解决方法

我使用以下docker命令启动了一个oracle-database-free-23ai容器:

docker run \
  -d \
  -p 1521:1521 \
  -p 5500:5500 \
  -e ORACLE_PWD=123456t \
  -v ~/docker/data/oradata:/u01/app/oracle/oradata \
--name oracle-free23ai \
  chinafengzhao/oracle-database-free-23ai

我在主机使用Navicat连接这个容器里的Oracle数据库:

Navicat 连接测试失败,报错 “ORA-12514: TNS:listener does not currently know of service requested in connect descriptor”,这是 Oracle 最常见的连接问题之一,意思是监听器(Listener)知道你的主机和端口,但不认识你指定的“服务名称”(Service Name)。

问题根源

1 服务名称填错了:你填的是 ORCL,但 Oracle 23ai Free 的默认服务名(Service Name)是 FREEPDB1(这是默认的 Pluggable Database,即 PDB)。

Oracle 多租户架构(CDB + PDB)中,连接普通用户数据时,几乎总是用 PDB 的服务名,而不是 CDB 的 SID。

CDB 的 SID 是 FREE,但用 SID 连接通常只用于 sys/system 等系统管理用户,且需要额外指定角色。

2 连接类型选错了:你选了“服务名称”(Service Name),但填的值不对。如果改成 SID 模式,也需要调整。

3 用户名不对:你用了 oracle,但 Oracle 23ai Free 默认没有这个用户(或它不是标准管理员用户)。常用的是:sys(需要 AS SYSDBA)、system或pdbadmin(PDB 管理员)

推荐的 Navicat 连接配置

最简单、最常用的方式是连接到 FREEPDB1 PDB。在 Navicat 的“新建连接 (Oracle)”窗口中,修改如下(其他保持不变):

  • 连接名称:随便(比如 Oracle-23ai-Free-FREEPDB1)
  • 连接类型:Basic
  • 主机:127.0.0.1(或 localhost)
  • 端口:1521
  • 服务名称:选 ○ 服务名称(保持这个)
  • 服务名称(填入):FREEPDB1(全部大写或小写都行,通常小写 freepdb1 也接受,但建议大写一致)
  • 用户名:system(推荐先用这个测试) 或 sys
  • 密码:你在 docker run 时设的 -e ORACLE_PWD=xxx 的值(sys 和 system 共用同一个密码)

如果用 sys 用户:在用户名填 sys,然后在“高级”或连接字符串中加 as sysdba(Navicat 支持在用户名后加 / as sysdba,或在连接测试前选角色)。

点击“测试连接”。

备选方案:用 SID 连接 CDBFREE),适合 sys/system 管理

  • 服务名称:改选 ○ SID
  • SID:FREE(大写)

但推荐优先用 Service Name + FREEPDB1,因为大多数应用和开发都在 PDB 里操作。

快速验证步骤(在终端确认服务名和服务是否注册)

1 进入容器:

docker exec -it oracle-free23ai bash -c "source /home/oracle/.bashrc; bash"

2 进入sqlplus:

sqlplus / as sysdba

3 在 SQL> 提示符下运行下面命令确认:

SHOW PDBS;   -- 应该看到 FREEPDB1 READ WRITE

SELECT name, pdb FROM v$services;   -- 查看监听器注册的服务名,通常有 FREE 和 FREEPDB1

SHOW CON_NAME;   -- 当前是 CDB$ROOT

ALTER SESSION SET CONTAINER = FREEPDB1;   -- 切换到 PDB

SHOW CON_NAME;   -- 变成 FREEPDB1

如果看到 FREEPDB1 已 READ WRITE,且 v$services 有 FREEPDB1,说明一切正常。

4 退出后,用上面 Navicat 配置重试。

如果还失败的额外检查

  • 等待时间:首次启动后,有时服务注册需要 1–2 分钟。等 docker logs 完全稳定(看到 DATABASE IS READY TO USE! 后)再连。
  • 防火墙/端口:Ubuntu 上确认 1521 端口没被防火墙挡(sudo ufw allow 1521)。
  • Navicat 版本:确保 Navicat 支持 Oracle 23c/23ai(较新版通常支持)。
  • 连接字符串测试(Navicat 支持直接填 EZCONNECT 字符串):

在“连接字符串”模式下试:127.0.0.1:1521/FREEPDB1

用户:system,密码是你在 docker run 时设的 -e ORACLE_PWD=xxx 的值(sys 和 system 共用同一个密码)