Oracle AI Database Free、容器部署与企业连接治理手册
从 SYSTEM 能登录却找不到表开始
Oracle 新手最常见的困惑是:SYSTEM 明明登录成功,应用却报表不存在。问题往往不在 SQL,而在连接落点。FREE service 进入 CDB root,FREEPDB1 进入默认 PDB;应用用户建在 PDB 中,换一个 service,就像进入了另一座数据库。再叠加 schema 与 user 同名、tablespace quota、listener 注册和 TNS 解析,一个“能登录”的绿灯远远不够。
第一次验收应同时打印 service、container、current user 和对象位置。只有这四个答案一致,后面的 JDBC、迁移、Data Pump 和权限实验才有共同语境。
动手前先确定连接落点
准备一个隔离的开发目录,并确认:
Docker 或 Podman,并确认本机资源足够;Oracle Free 虽有资源限制,但镜像体积和启动耗时都明显高于 SQLite、MySQL、PostgreSQL。预留端口 1521,如果本机已有 Oracle 或公司 VPN 转发,改成 11521:1521 这类宿主端口。一个强密码占位符,例如 YOUR_STRONG_ORACLE_PASSWORD,只放在 .env.example,真实值放本机 .env 或密钥系统。
至少一种客户端:SQLcl、SQL Developer for VS Code、SQL Developer、SQL*Plus、DBeaver、DataGrip 或应用驱动。一个只用于实验的项目目录,例如 your-project/。给环境标明用途、owner 和销毁日期。Free 适合学习、开发和兼容验证;生产部署还要评估支持、补丁、安全和商业授权。
先检查端口:
docker version
docker compose version
lsof -i :1521Windows:
netstat -ano | findstr ":1521"Apple Silicon 或其他 Arm 开发机要分别验证数据库镜像、客户端和团队镜像仓库。Oracle AI Database 26ai Free 提供 Linux Arm RPM,但这不等于每个容器 tag、Instant Client 组合和内部构建链都自动支持 Arm。无法形成可重复基线时,使用远程开发 PDB 比长期依赖模拟层更稳。
认清 Free、XE 与企业实例
Oracle AI Database Free 限制说明列出了 2 个前台处理 CPU core、SGA 与 PGA 合计 2GB 内存、12GB 磁盘用户数据,以及每个逻辑环境只能运行一个 Free 安装等约束;超过数据容量时可观察到 ORA-12954。这些约束使它适合本地验证,却无法模拟企业实例的容量、并发和高可用表现。
旧 XE、23ai Free、26ai Free、Enterprise Edition 与 Autonomous Database 的名称不能互换。它们的镜像、默认服务、补丁支持、资源限制和连接方式都可能不同。项目接入时记录完整数据库 banner、补丁级别、字符集、时区、service name 与驱动版本,迁移判断才有证据。
容器入口使用 container-registry.oracle.com/database/free,首次实验可以拉取 latest,团队基线则固定经过验证的 tag 或内部镜像摘要。Free 安装与连接文档给出的默认 listener 端口是 1521,FREE 指向 CDB$ROOT,FREEPDB1 指向默认 PDB。不要从旧 XE 教程复制 5500、SID、APEX 或 EM Express 假设。
客户端按任务选择:SQLcl 适合现代命令行和脚本,SQL*Plus 适合兼容传统脚本,SQL Developer for VS Code 或传统 SQL Developer 适合交互开发,Instant Client 为 CI 和轻量主机提供客户端库。Java 使用 JDBC Thin;驱动 artifact 与版本必须同时匹配 JDK、框架和目标数据库。
主流部署方式
| 方式 | 定义 | 适用场景 | 不适合 |
|---|---|---|---|
| Oracle AI Database Free 容器 | 从 Oracle Container Registry 拉取 Free 镜像,本机容器运行 | 本地开发、功能验证、CI smoke、短期联调 | 生产、长期共享核心库、超出 Free 限制的数据 |
| RPM / Windows 安装 | 在 Oracle Linux / RHEL / Windows 上安装 Free | 固定开发机、教学环境、需要本机服务 | 快速清理、多版本并存 |
| 共享开发实例 | DBA 或平台团队提供的非生产 Oracle | 多人联调、接近企业网络和权限 | 个人随意 reset、无 owner 的临时库 |
| Oracle Cloud Free / ADB | 云托管开发库或免费试用资源 | 云上联调、外部访问、托管能力体验 | 本机离线开发、无成本意识的长期常开 |
| 企业开发版 / 测试库 | 企业购买或内部授权的非生产库 | 接近生产的版本、补丁、NLS、权限验证 | 未经授权的个人安装和分发 |
选型建议:
个人学习和本地项目验证:Oracle AI Database Free 容器。团队联调:共享开发实例或固定 Compose,但必须有 owner、账号、数据清理和备份边界。企业生产兼容验证:使用与生产同版本、同字符集、同补丁、同连接方式的非生产实例。
Mac / Windows Arm:分别验证数据库包、容器 tag、客户端和内部镜像仓库,不按旧 x86 教程推断。生产:Free 的许可不限定部署环境,但它不能提交 Oracle Support SR,也不发布补丁或安全修复;Free FAQ建议生产使用获得完整支持的 edition 或云服务。DBA、平台、采购与安全团队还要共同确认功能许可与架构。
Docker / Podman 单容器
示例只用于开发:
docker volume create oracle-free-data
docker run -d \
--name oracle-free-dev \
-p 1521:1521 \
-e ORACLE_PWD=YOUR_STRONG_ORACLE_PASSWORD \
-e ORACLE_CHARACTERSET=AL32UTF8 \
-v oracle-free-data:/opt/oracle/oradata \
container-registry.oracle.com/database/free:latest等待 ready:
docker logs -f oracle-free-dev看到 DATABASE IS READY TO USE! 后再连接。Oracle 初始化明显慢于轻量数据库,容器 running 不等于 PDB 可用。
容器内验证:
docker exec -it oracle-free-dev sqlplus system/YOUR_STRONG_ORACLE_PASSWORD@FREEPDB1SQL:
SELECT banner FROM v$version;
SELECT sys_context('USERENV', 'CON_NAME') AS container_name FROM dual;Docker Compose
services:
oracle:
image: container-registry.oracle.com/database/free:latest
container_name: tool-oracle-free-dev
environment:
ORACLE_PWD: "${ORACLE_PWD}"
ORACLE_CHARACTERSET: "AL32UTF8"
ports:
- "11521:1521"
volumes:
- oracle-free-data:/opt/oracle/oradata
healthcheck:
test:
[
"CMD-SHELL",
"echo 'SELECT 1 FROM dual;' | sqlplus -s system/$${ORACLE_PWD}@FREEPDB1 | grep 1 || exit 1"
]
interval: 20s
timeout: 10s
retries: 40
start_period: 120s
volumes:
oracle-free-data:说明:
宿主端口用 11521,避免和本机已有 Oracle 冲突。volume 挂 /opt/oracle/oradata,否则删除容器会丢数据。healthcheck 必须等 PDB ready,而不是只看容器进程。
不要把真实 ORACLE_PWD 写进 Compose 文件。
.env.example:
ORACLE_PWD=YOUR_STRONG_ORACLE_PASSWORD
ORACLE_APP_PASSWORD=YOUR_STRONG_ORACLE_APP_PASSWORD
ORACLE_CHARACTERSET=AL32UTF8ORACLE_CHARACTERSET 只在首次初始化数据文件时生效。复用旧 volume 时再改 .env 不会重建字符集,这一点和密码、PDB、表空间状态一样必须写进团队说明。
从 Free 单实例走向生产架构
Oracle 的生产选型不能从“Free 容器跑通”直接跳到 RAC。先确定 RTO、RPO、允许的提交延迟、读扩展需求、站点数量、数据主权、许可预算和 DBA 能力,再判断哪些故障需要由哪一层处理。
| 架构 | 解决的问题 | 适合 | 关键代价与证据 |
|---|---|---|---|
| 单实例 + Oracle Restart + RMAN | 进程或主机重启、介质恢复和时间点恢复 | RTO 可接受、成本优先的普通业务 | 恢复期间不可用;必须用隔离主机真实 restore / recover 证明时间目标 |
| Oracle RAC / RAC One Node | 多实例访问同一数据库,处理实例或节点故障并支持部分滚动维护 | 需要站点内低 RTO、已有 Clusterware、共享存储和专职 DBA | 共享存储、私网、Cache Fusion、服务配置和许可成本高;RAC 不等于跨站灾备 |
| Data Guard | 主库传输 redo 到物理或逻辑 standby,执行 switchover / failover | 跨故障域灾备、数据保护 | 同步保护增加提交路径延迟,异步存在传输或应用缺口;standby 不是备份 |
| Active Data Guard | standby 在应用 redo 时开放只读并承担查询或备份卸载 | 既要灾备又要只读卸载 | Active Data Guard是单独许可能力,不能因为 Data Guard 可用就默认拥有 |
| GoldenGate | 基于日志的逻辑复制与异构、双活或迁移链路 | 跨版本、异构迁移、细粒度复制 | 冲突处理、DDL 支持、延迟、数据校验和双写语义复杂;不能代替物理备份 |
| Autonomous / Base Database / Exadata 云服务 | 平台承担不同程度的补丁、备份、伸缩和基础设施 | 希望减少自建运维或需要云上弹性 | 服务能力、出网、密钥、地域、费用、退出和厂商依赖要逐项评审 |
Oracle 高可用参考架构把单实例恢复、RAC、Data Guard、Flashback 和备份组合成不同等级,而不是让一个产品包办所有故障。节点故障由 RAC 缩短恢复,站点故障由 Data Guard 承担,逻辑误删由 Flashback 或时间点恢复处理,介质损坏仍依赖 RMAN 和可用 redo。RAC 与 Data Guard 可以组合,但故障域、网络、仲裁、运维和许可成本也会叠加。
Data Guard 验收不能只看 standby 进程存在。至少保存角色、保护模式、传输延迟、应用延迟、归档缺口和 broker 状态:
SELECT database_role, open_mode, protection_mode, switchover_status
FROM v$database;
SELECT name, value, unit
FROM v$dataguard_stats
WHERE name IN ('transport lag', 'apply lag', 'apply finish time');
SELECT thread#, low_sequence#, high_sequence#
FROM v$archive_gap;计划切换要验证应用通过 service 的重连、未提交事务、只读路由和备份作业归属;灾难 failover 则必须按当时保护模式和 lag 判断可能的数据缺口。读请求导向 standby 前,用业务主键做写后读实验并记录最大可见性延迟,避免把异步副本当成强一致查询入口。
客户端工具
| 工具 | 用途 | 注意 |
|---|---|---|
| SQLcl | 现代命令行,适合脚本和日常查询 | 团队锁定并回归脚本兼容的版本 |
| SQL*Plus | 传统命令行,随 Instant Client 等入口可用 | 脚本兼容性强,交互体验旧 |
| SQL Developer for VS Code | VS Code 内开发、查询、对象浏览 | 新团队文档应补充它 |
| SQL Developer | 传统图形客户端 | 同时记录所需 JDK、版本和平台 |
| Instant Client | 轻量客户端库和工具 | CI、容器、客户端机器常用 |
| JDBC Thin | Java 项目主流连接方式 | 验证 service name、wallet、NLS 与 UCP 组合 |
service name、SID、CDB、PDB
现代 Oracle 开发连接最常见的误区,是把 SID 和 service name 混用。Free 容器里常见:
| 名称 | 含义 | 开发连接建议 |
|---|---|---|
FREE | 容器数据库 CDB / 实例相关名称 | 管理和排障时认识即可 |
FREEPDB1 | 默认 pluggable database service | 应用连接优先连它 |
1521 | Listener 端口 | 宿主可映射成 11521 |
优先连接 PDB:
system/YOUR_STRONG_ORACLE_PASSWORD@//localhost:11521/FREEPDB1
jdbc:oracle:thin:@//localhost:11521/FREEPDB1不要把应用直接连 CDB root。应用对象、schema、表空间和权限应落在 PDB 里。
schema=user
Oracle 中 schema 通常和 user 绑定。创建应用 schema,本质是创建用户并授予权限。
ALTER SESSION SET CONTAINER = FREEPDB1;
CREATE USER app_tool_efficiency
IDENTIFIED BY "YOUR_STRONG_ORACLE_APP_PASSWORD"
DEFAULT TABLESPACE users
TEMPORARY TABLESPACE temp
QUOTA 100M ON users;
GRANT CREATE SESSION TO app_tool_efficiency;
GRANT CREATE TABLE TO app_tool_efficiency;
GRANT CREATE SEQUENCE TO app_tool_efficiency;
GRANT CREATE VIEW TO app_tool_efficiency;开发环境也不要让应用长期使用 SYSTEM。更不要在脚本里使用 SYS AS SYSDBA 做日常 DDL。
NLS、字符集和时区
Oracle 的 NLS 和时区问题会跨客户端、驱动、数据库初始化和应用层出现:
SELECT * FROM nls_database_parameters
WHERE parameter IN ('NLS_CHARACTERSET', 'NLS_NCHAR_CHARACTERSET');
SELECT dbtimezone, sessiontimezone FROM dual;团队要固定:
数据库存储字符集。JDBC / 应用时区策略。日期字段使用 TIMESTAMP WITH TIME ZONE、TIMESTAMP 还是应用 UTC。
客户端导入导出时的编码和 NLS_LANG。ORACLE_CHARACTERSET 是否只在首次初始化生效,以及旧 volume 是否需要受控重建。
tablespace 和 quota
Free 版本有总数据限制,开发环境也要让每个 schema 有 quota。不要让用户默认无限占用 USERS。
ALTER USER app_tool_efficiency QUOTA 100M ON users;
SELECT tablespace_name, bytes / 1024 / 1024 AS mb
FROM user_segments;更正式的共享开发实例,应由 DBA 创建独立 tablespace,并给项目设置 quota、清理窗口和 owner。
启动:
docker compose up -d
docker compose ps
docker logs tool-oracle-free-dev --tail 120确认 PDB。日志出现 DATABASE IS READY TO USE! 后再连接,docker ps 的 running 状态本身不能证明 PDB 已经 open:
docker exec -it tool-oracle-free-dev sqlplus system/YOUR_STRONG_ORACLE_PASSWORD@FREEPDB1SQL:
SELECT banner FROM v$version;
SELECT sys_context('USERENV', 'CON_NAME') AS container_name FROM dual;
SELECT name, open_mode FROM v$pdbs;预期 CON_NAME 为 FREEPDB1,并且 v$pdbs 中 FREEPDB1 的 OPEN_MODE 为 READ WRITE。如果看到 CDB$ROOT,说明连接落到了 FREE service 或本地 OS 认证的 root container,不能继续创建应用对象。
创建应用用户:
ALTER SESSION SET CONTAINER = FREEPDB1;
CREATE USER app_tool_efficiency
IDENTIFIED BY "YOUR_STRONG_ORACLE_APP_PASSWORD"
DEFAULT TABLESPACE users
TEMPORARY TABLESPACE temp
QUOTA 100M ON users;
GRANT CREATE SESSION, CREATE TABLE, CREATE SEQUENCE, CREATE VIEW
TO app_tool_efficiency;
GRANT READ, WRITE ON DIRECTORY DATA_PUMP_DIR
TO app_tool_efficiency;用应用用户连接:
docker exec -it tool-oracle-free-dev sqlplus app_tool_efficiency/YOUR_STRONG_ORACLE_APP_PASSWORD@FREEPDB1建表、写入、读取:
CREATE TABLE user_demo (
id NUMBER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
username VARCHAR2(64) NOT NULL,
created_at TIMESTAMP DEFAULT SYSTIMESTAMP NOT NULL
);
INSERT INTO user_demo(username) VALUES ('demo');
COMMIT;
SELECT id, username, created_at FROM user_demo ORDER BY id;确认当前 schema 和服务:
SELECT user AS current_user FROM dual;
SELECT sys_context('USERENV', 'SERVICE_NAME') AS service_name FROM dual;现在故意执行管理员动作:
CREATE USER permission_probe IDENTIFIED BY "NeverUseThisPassword1";应用账号应得到 ORA-01031: insufficient privileges。如果创建成功,账号获得了 CREATE USER、DBA role 或更高权限,应立刻回收并审计授权来源。该实验完成后不会产生对象;若异常创建成功,由管理员执行 DROP USER permission_probe CASCADE 清理。
先导出应用 schema:
docker exec -it tool-oracle-free-dev expdp app_tool_efficiency/YOUR_STRONG_ORACLE_APP_PASSWORD@FREEPDB1 schemas=APP_TOOL_EFFICIENCY directory=DATA_PUMP_DIR dumpfile=app_tool_efficiency.dmp logfile=app_tool_efficiency.log然后由开发库管理员创建隔离的恢复用户,并通过 REMAP_SCHEMA 导入。这样验证的是“dump 能恢复”,不是“目标表已存在所以跳过”:
CREATE USER app_tool_efficiency_restore
IDENTIFIED BY "YOUR_STRONG_ORACLE_RESTORE_PASSWORD"
DEFAULT TABLESPACE users
TEMPORARY TABLESPACE temp
QUOTA 100M ON users;
GRANT CREATE SESSION, CREATE TABLE, CREATE SEQUENCE, CREATE VIEW
TO app_tool_efficiency_restore;docker exec -it tool-oracle-free-dev impdp system/YOUR_STRONG_ORACLE_PASSWORD@FREEPDB1 schemas=APP_TOOL_EFFICIENCY remap_schema=APP_TOOL_EFFICIENCY:APP_TOOL_EFFICIENCY_RESTORE directory=DATA_PUMP_DIR dumpfile=app_tool_efficiency.dmp logfile=app_tool_efficiency-restore.log恢复后验证源 schema 与恢复 schema 的行数和约束,再清理实验对象:
SELECT owner, table_name
FROM all_tables
WHERE owner IN ('APP_TOOL_EFFICIENCY', 'APP_TOOL_EFFICIENCY_RESTORE')
AND table_name = 'USER_DEMO'
ORDER BY owner;
SELECT COUNT(*) AS restored_rows
FROM app_tool_efficiency_restore.user_demo;
DROP USER app_tool_efficiency_restore CASCADE;预期能看到两个 owner 的 USER_DEMO,且恢复表至少包含刚才提交的 demo 行。最后再由应用用户执行 DROP TABLE user_demo PURGE,完成源 schema 清理。Data Pump 验证的是 schema 级逻辑搬迁,不能证明数据文件、控制文件、归档日志和时间点恢复链有效;生产恢复目标还需要 RMAN、归档策略、恢复窗口和灾备演练共同支撑。
把 PDB 身份查询、应用写入、管理员动作拒绝和 REMAP_SCHEMA 恢复放进目标开发机或 CI 的 smoke job。运行证据同时保存镜像 tag / digest、客户端与 JDBC 版本、service name、字符集和时区,后续出现 ORA 错误时才能复原现场。
Java / JDBC Thin
Maven 依赖使用项目按 JDK、框架和数据库版本验证后的驱动:
<dependency>
<groupId>com.oracle.database.jdbc</groupId>
<artifactId>ojdbc11</artifactId>
<version>替换为项目锁定版本</version>
</dependency>选择 ojdbc11 还是 ojdbc17 要由团队 JDK、框架版本和目标数据库共同决定,不能从旧项目复制 jar。升级后至少回归登录、时区、LOB、批处理、连接池回收和钱包连接。
连接串:
spring.datasource.url=jdbc:oracle:thin:@//localhost:11521/FREEPDB1
spring.datasource.username=app_tool_efficiency
spring.datasource.password=YOUR_STRONG_ORACLE_APP_PASSWORD团队共享环境:
spring.datasource.url=jdbc:oracle:thin:@//oracle-dev.example.test:1521/DEVAPP_PDB注意:
优先使用 service name:@//host:port/service_name。不把 SID 写成新项目默认模板。连接池要设置最大连接数、validation query 和 application name / client identifier。
Oracle session 状态较多,连接池回收和初始化 SQL 要谨慎。如果使用 wallet、TCPS、Autonomous Database 或云服务,连接串和凭证治理另写项目文档。使用 TNS alias 时必须写清 TNS_ADMIN 指向哪个受控目录;本地开发优先 EZConnect,团队共享再固化 tnsnames.ora。
迁移工具
| 工具 | 适用 | 注意 |
|---|---|---|
| Flyway | Java / 多语言 SQL migration | Oracle DDL、schema、edition 和权限要验证 |
| Liquibase | 企业变更管理 | rollback、对象权限、大小写和 quoted identifier 要确认 |
| SQLcl 脚本 | 简单初始化和日常脚本 | 适合工具层,长期演进仍要 migration |
| Data Pump | schema 级逻辑导入导出 | 不是完整物理备份替代 |
初始化脚本只负责创建 user / schema、基础权限和最小对象。后续结构演进进入 migration,不允许 SQL Developer 人工改表绕过代码评审。
核心机制与排障入口
CDB / PDB
Oracle 多租户架构里,应用通常落在 PDB。排查时先确认当前容器:
SELECT sys_context('USERENV', 'CON_NAME') FROM dual;
SHOW CON_NAME;如果你在 CDB root 创建了对象或用户,应用连接到 PDB 时会看不到。新手最容易在 SYSTEM@FREE 和 SYSTEM@FREEPDB1 之间来回踩坑。
listener 和 service
常见 ORA-12514 / ORA-12505 / ORA-12541 / ORA-12154 都和 listener、service name、SID、TNS alias、端口或 PDB open 状态有关。
容器内:
docker exec -it tool-oracle-free-dev lsnrctl statusSQL:
SELECT name, open_mode FROM v$pdbs;
SELECT sys_context('USERENV', 'SERVICE_NAME') FROM dual;判断顺序:
ORA-12514:listener 不知道目标 service,先查 FREEPDB1 是否注册、PDB 是否 open。ORA-12505:连接串用了 SID 口径但 listener 不知道该 SID,优先改成 service name URL。ORA-12541:端口或 listener 不通,查宿主端口、容器端口、防火墙和 VPN。
ORA-12154:客户端解析不到连接标识,查 TNS_ADMIN、tnsnames.ora、EZConnect 写法和 wallet 目录。
user、role、privilege
Oracle 的权限不要粗暴给 DBA:
SELECT * FROM user_role_privs;
SELECT * FROM user_sys_privs;
SELECT * FROM user_tab_privs;应用账号通常只需要连接、建对象、读写目标对象。共享实例里要区分 runtime、migration、readonly。
UNDO、redo 和表空间
开发环境也会遇到 undo、redo、tablespace、temp 不足:
SELECT tablespace_name, status, contents FROM dba_tablespaces;
SELECT username, tablespace_name, max_bytes FROM dba_ts_quotas;如果没有 DBA 权限,至少让 owner 提供表空间和 quota 的排查入口,不要让开发者猜。
实例内存、数据块、redo、undo 与 SCN
Oracle database 是数据文件、控制文件和 redo log 等持久对象,instance 则是 SGA 与后台进程。Buffer Cache 缓存数据块,Shared Pool 保存解析结果等共享结构;事务修改数据块时产生 redo 以支持崩溃恢复,同时把旧值写入 undo 以支持回滚和一致性读。SCN 给变化建立逻辑顺序,查询据此构造一致视图。
因此几类症状能反推不同路径:redo 写入变慢会拖长提交;undo 太小或长查询需要的旧版本被覆盖,可能出现 ORA-01555;Buffer Cache 命中差只是现象之一,不能脱离物理读、SQL 计划和工作集盲目加内存;长事务还会同时增加 undo、redo、锁持有时间与恢复成本。
SELECT current_scn FROM v$database;
SELECT name, value
FROM v$sysstat
WHERE name IN ('session logical reads', 'physical reads', 'redo size', 'user commits');
SELECT begin_time, undoblks, txncount, maxquerylen
FROM v$undostat
ORDER BY begin_time DESC FETCH FIRST 12 ROWS ONLY;普通应用账号不应为了看这些视图获得 DBA role。由观测账号获得经过评审的目录视图权限,或让 DBA 导出所需指标;这也让“谁能看全库活动”进入审计边界。
索引、优化器与行锁实验
Oracle 常见 B-tree 索引按 key 定位 rowid,优化器结合对象统计信息、谓词选择性、连接顺序和代价选择执行计划。慢 SQL 先确认 SQL ID、实际行数、等待事件和计划,再判断是统计信息失真、索引缺失、绑定变量分布、IO、CPU 还是锁等待。只看一份 EXPLAIN PLAN 不能代替运行时证据。
两个 SQL*Plus 应用账号会话可以复现行锁。先建立不依赖前面清理结果的探针:
CREATE TABLE lock_probe (
id NUMBER PRIMARY KEY,
marker VARCHAR2(32) NOT NULL
);
INSERT INTO lock_probe(id, marker) VALUES (1, 'ready');
COMMIT;会话 A:
UPDATE lock_probe SET marker = 'writer-a' WHERE id = 1;
-- 不提交,保持会话打开。会话 B 设置等待上限后更新同一行:
ALTER SESSION SET DML_LOCK_TIMEOUT = 5;
UPDATE lock_probe SET marker = 'writer-b' WHERE id = 1;预期 B 等待后返回 ORA-30006。DBA 观察会话可查询:
SELECT sid, serial#, event, blocking_session, seconds_in_wait
FROM v$session
WHERE blocking_session IS NOT NULL;会话 A 执行 ROLLBACK 后,B 再次更新并 COMMIT 应成功。若没有阻塞,先确认两个会话落在同一个 service、PDB、schema 和记录;实验结束执行 DROP TABLE lock_probe PURGE。证据链应能解释“未提交事务持有 TX 锁 -> 第二个会话等待 -> 超时 -> rollback 释放”,而不是把所有等待都归因于数据库性能不足。
查看容器日志:
docker logs tool-oracle-free-dev --tail 120进入 SQL*Plus:
docker exec -it tool-oracle-free-dev sqlplus system/YOUR_STRONG_ORACLE_PASSWORD@FREEPDB1SQLcl 连接:
sql app_tool_efficiency/YOUR_STRONG_ORACLE_APP_PASSWORD@//localhost:11521/FREEPDB1查看版本:
SELECT banner FROM v$version;查看当前容器和 schema:
SELECT sys_context('USERENV', 'CON_NAME') AS con_name,
sys_context('USERENV', 'SERVICE_NAME') AS service_name,
user AS current_user
FROM dual;查看对象:
SELECT object_name, object_type
FROM user_objects
ORDER BY object_type, object_name;导出 schema:
expdp app_tool_efficiency/YOUR_STRONG_ORACLE_APP_PASSWORD@//localhost:11521/FREEPDB1 schemas=APP_TOOL_EFFICIENCY directory=DATA_PUMP_DIR dumpfile=app_tool_efficiency.dmp logfile=app_tool_efficiency.log停止开发库:
docker compose down只有确认是本地开发数据,才允许删除 volume:
docker compose down -v容器 running 但连不上
原因:
数据库还在初始化。PDB 还没 open。宿主端口映射错。
连接的是 CDB service,而不是 PDB service。
判断:
docker logs tool-oracle-free-dev --tail 120
docker exec -it tool-oracle-free-dev lsnrctl status处理:
等日志出现 DATABASE IS READY TO USE!。用 FREEPDB1 service 连接应用。宿主端口和 JDBC URL 保持一致。
ORA-01017
ORA-01017: invalid username/password 常见原因:
用户建在 CDB root,应用连的是 PDB。密码含特殊字符,shell 转义错。旧 volume 保留旧密码。
用户被锁或密码过期。
排查:
SELECT username, account_status
FROM dba_users
WHERE username IN ('SYSTEM', 'APP_TOOL_EFFICIENCY');处理:
先确认 CON_NAME。修改密码用 SQL,而不是只改 .env。应用账号统一大写或明确 quoted identifier 规则。
ORA-12514 / ORA-12505 / ORA-12541 / ORA-12154
ORA-12514 通常是 listener 不知道目标 service;ORA-12505 多见于把 SID 老写法复制到 service name 场景;ORA-12541 通常是没有 listener 或端口不通;ORA-12154 则是客户端解析不到连接标识。
排查:
docker exec -it tool-oracle-free-dev lsnrctl statusSQL:
SELECT name, open_mode FROM v$pdbs;处理:
连接字符串使用 @//localhost:11521/FREEPDB1。确认 PDB open。确认端口映射。
使用 TNS alias 时检查 TNS_ADMIN 和 tnsnames.ora,本地开发优先改回 EZConnect 验证。
旧 volume 保留旧状态
ORACLE_PWD 只在初始化阶段可靠。已有 /opt/oracle/oradata 会保留旧数据库、旧用户、旧密码和旧表空间。
处理:
本地个人开发库可受控 docker compose down -v。共享开发库必须由 owner 通过 SQL 修改密码、清理 schema 或重建。字符集、密码、PDB、表空间和旧测试数据都来自首次初始化,不能把“改 .env”当成“改数据库”。
表空间不足
现象:
插入或建索引失败。Free 达到 12GB user data 限制。用户 quota 不足。
排查:
SELECT tablespace_name, bytes / 1024 / 1024 AS mb
FROM user_segments;
SELECT username, tablespace_name, bytes, max_bytes
FROM dba_ts_quotas
WHERE username = 'APP_TOOL_EFFICIENCY';处理:
本地样例库清理测试数据。调整 quota 或独立 tablespace。超出 Free 限制时升级到企业测试库或云开发库。
JDBC 连接串混用 SID
老教程常写:
jdbc:oracle:thin:@localhost:1521:ORCL新项目优先:
jdbc:oracle:thin:@//localhost:11521/FREEPDB1如果团队生产使用 TNS alias、wallet、TCPS 或 RAC service,项目文档要单独写,不要把本地 Free 的连接串直接复制过去。
Oracle 开发环境最容易泄漏的是强账号和导出文件:
SYSTEM / SYS 密码、ORACLE_PWD、JDBC properties、wallet、tnsnames、SQL Developer 连接配置不能进仓库。应用使用 app_tool_efficiency,不使用 SYSTEM。迁移账号、运行账号、只读账号分开。
Data Pump .dmp、.log、SQL 导出和客户端截图可能含真实数据。Oracle Cloud wallet、ADB zip、private key 和 OCI config 必须走密钥治理。SQL Developer / VS Code 连接历史不能保存生产密码。
TNS_ADMIN、sqlnet.ora、tnsnames.ora 和 wallet 目录必须区分本地、共享开发、测试和生产,不能混用同一份配置。
.gitignore 建议:
.env
db/oracle/dump/*.dmp
db/oracle/dump/*.log
db/oracle/export/*.sql
db/oracle/wallet/**
tnsnames.ora
sqlnet.ora目录模板
compose.yaml
.env.example
db/
oracle/
init/
001_user.sql
002_schema.sql
migration/
verify/
verify.sql
dump/
docs/
dependency-setup.md
scripts/
oracle-up.sh
oracle-verify.sh
oracle-export.sh
oracle-reset-dev.sh命名规范
| 对象 | 示例 | 规则 |
|---|---|---|
| service | FREEPDB1、DEVAPP_PDB | 应用连 PDB service |
| schema/user | APP_TOOL_EFFICIENCY | 项目唯一,避免和个人名绑定 |
| tablespace | TS_TOOL_EFFICIENCY | 共享实例独立 tablespace |
| dump | app_tool_efficiency_<RUN_ID>.dmp | 带 schema 和运行批次 |
| wallet | wallet-devapp-dev | 环境和用途明确 |
共享开发实例治理
共享 Oracle 开发库至少要有:
owner 和 DBA 联系人。service name、端口、连接方式和客户端版本。每个项目的 schema/user、tablespace、quota。
runtime / migration / readonly 账号。Data Pump 导出目录和清理周期。危险操作审批:DROP USER CASCADE、大批量 DELETE、表空间扩容、导入覆盖。
Free / 企业授权边界和云资源费用 owner。
容量、成本、升级与退出
容量至少拆成 datafile、temp、undo、online / archived redo、Fast Recovery Area、Data Pump、RMAN 备份和 standby 副本。Free 的 12GB 是用户数据硬边界,企业环境还要看数据增长、峰值 session、SGA / PGA、redo 产生率、归档保留、备份窗口、恢复吞吐和站点间带宽。
SELECT m.tablespace_name,
m.used_space * t.block_size / 1024 / 1024 AS used_mb,
m.tablespace_size * t.block_size / 1024 / 1024 AS size_mb
FROM dba_tablespace_usage_metrics m
JOIN dba_tablespaces t
ON t.tablespace_name = m.tablespace_name;
SELECT name, space_limit / 1024 / 1024 AS limit_mb,
space_used / 1024 / 1024 AS used_mb
FROM v$recovery_file_dest;RAC 增加节点、私网、共享存储、Clusterware 和许可成本;Data Guard 增加备用计算、存储、传输和演练成本;Active Data Guard、GoldenGate 与部分高级能力还要单独核对许可。云环境持续审查计算规格、存储自动扩展、备份保留、跨地域流量、出网、闲置 PDB 和支持级别。owner 应按评审周期保存增长率、峰值会话、P95 / P99 延迟、redo / archive 速率、备份与恢复时长、Data Guard lag 和故障演练结果。
升级前固定完整 banner、RU、COMPATIBLE、JDBC / Instant Client、NLS、时区、wallet 和备份目录,在恢复副本上回归 LOB、批处理、migration、执行计划、Data Pump、RMAN 与切换。回退不能等同于替换容器 tag:数据字典、兼容参数和数据文件已经变化后,旧软件未必能打开。退出路径应保留升级前经验证的 RMAN 备份、必要的归档 redo、可用旧环境、应用切回 service 的步骤,以及数据修复的前滚方案。RMAN 时间点恢复依赖可用备份与 redo;Data Pump dump 和一次导入成功不能代替整库恢复链。
| 深水区 | 现象 | 判断入口 | 配置 / 命令 / 取舍 |
|---|---|---|---|
| Free 被当成受支持生产版 | 容器长期接真实业务,却没有安全修复和厂商支持 | 查 edition、补丁来源、风险 owner | 生产优先选择获得完整支持的 edition 或云服务;例外需书面接受安全、容量和恢复风险 |
| 容器初始化慢 | running 但连接失败 | docker logs | 等 DATABASE IS READY TO USE! |
| 旧 volume 保留旧密码 | 改 .env 后密码不变 | volume、dba_users | 本地可删 volume;共享库用 SQL 改 |
| service name 写错 | ORA-12514 | lsnrctl status、v$pdbs | 应用连 FREEPDB1 或团队 PDB service |
| SID 老写法误导 | ORA-12505 | JDBC URL、listener services | 新项目用 @//host:port/service |
| TNS 解析失败 | ORA-12154 | TNS_ADMIN、tnsnames.ora、wallet | 本地先用 EZConnect,团队共享再固化 TNS |
| PDB 未 open | CDB 能连,应用库不可用 | SELECT name, open_mode FROM v$pdbs | 等初始化或让 DBA open PDB |
| ORA-01017 | 用户密码错误 | dba_users、CON_NAME | 确认用户在 PDB,处理 shell 转义 |
| ORA-12541 | 端口不通 | lsof、docker ps、listener | 修端口映射和防火墙 |
| schema 和 user 混淆 | 建表在错误 schema | USER_OBJECTS、ALL_OBJECTS | 应用独立 user/schema |
| SYSTEM 滥用 | 应用连接 SYSTEM | secret scan、sessions | 应用账号最小授权 |
| tablespace quota 不足 | 建表或插入失败 | dba_ts_quotas、user_segments | 设置 quota,清理测试数据 |
| Free 12GB 限制 | ORA-12954 或写入失败 | Free FAQ、空间查询 | 升级企业测试库或云开发库 |
| NLS/字符集不一致 | 中文、emoji、排序异常 | nls_database_parameters | 建库前确认,导入导出指定编码 |
| 时区错乱 | 时间差 8 小时 | dbtimezone、sessiontimezone | 应用统一 UTC 或明确时区类型 |
| JDBC 版本不匹配 | 本地能连,CI 报驱动错误 | 依赖树、JDK、ojdbc 版本 | 按 JDK 和数据库版本锁定驱动 |
| Data Pump 路径误解 | dump 找不到 | directory object、容器路径 | 区分 DB server 路径和宿主路径 |
| Data Pump 未恢复验证 | 有 dump 但还原失败 | 新 schema/PDB 试导入 | 每个模板保留 impdp smoke |
| 导出含敏感数据 | .dmp 被提交或转发 | git status、制品扫描 | dump 进受控目录并脱敏 |
| 连接池打满 | session 暴涨 | v$session | 限制 pool max,设置 client identifier |
| Arm 支持误判 | Mac 上镜像不可用或很慢 | 数据库包、镜像 manifest、客户端架构 | 使用已验证的 Arm 组合或远程实例 |
| 把单实例恢复当成高可用 | 开发容器通过后直接推导生产可靠性 | RTO / RPO、故障域、切换证据 | RAC、Data Guard、GoldenGate、RMAN 和 Exadata 需要各自的架构评审与演练 |
Oracle 的深水区,核心是“连接到哪里、以谁的身份、落在哪个 PDB、占哪个表空间、导出的是什么数据”。这几件事没写清,团队很快会在 ORA 错误、权限、导出文件和共享实例污染里消耗大量时间。
团队交付门槛
一个 Oracle 开发环境达到可共享状态时,应留下这些可复核证据:
资产记录区分 26ai Free、旧 XE、Enterprise 与云服务,保存完整 banner、补丁级别、镜像 digest、客户端和 JDBC 版本;Free 的 2 CPU、2GB RAM、12GB user data 约束进入容量告警。连接记录包含 host、port、service name、PDB、schema/user、字符集和时区;查询结果证明应用落在目标 PDB,而不是 CDB$ROOT。
/opt/oracle/oradata 已持久化,日志 ready 与 PDB READ WRITE 查询共同组成健康检查;修改 .env 不会被误认为修改了旧 volume 中的数据库密码或字符集。runtime、migration、readonly 与管理员身份分离,应用不使用 SYSTEM / SYS,管理员动作反向实验稳定返回 ORA-01031。每个项目有独立 schema/user、tablespace、quota、连接池上限和清理周期;12GB 容量逼近时有迁移目标,不靠临时删日志续命。
JDBC 连接使用 service name,并回归 NLS、时区、LOB、批处理、session 初始化和连接池回收;wallet、TNS_ADMIN、tnsnames.ora 与环境一一对应。Data Pump dump 存在受控目录,经过 REMAP_SCHEMA 恢复和业务查询;RMAN、归档日志、RTO / RPO 与 Data Guard 等生产恢复能力另有真实演练证据。
密码、wallet、私钥、dump、导出 SQL 和客户端连接配置接受 secret 与敏感数据扫描;云资源和受支持生产 edition 还有费用、授权、补丁与销毁 owner。
Oracle 不是“难装”,而是企业边界多。把开发环境里的 service、PDB、schema、tablespace、权限、客户端和导出治理写清楚,后面的联调、迁移和生产对齐才不会每次都从 ORA 错误开始。
