【金仓数据库征文】Oracle到金仓:同义词、Schema与权限模型迁移实录

发布时间:2026/7/27 6:20:31
【金仓数据库征文】Oracle到金仓:同义词、Schema与权限模型迁移实录 文章目录每日一句正能量1. 背景与问题2. 环境与数据2.1 脱敏环境2.2 迁移前必须采集的对象清单3. 复现过程3.1 同义词创建成功但访问仍然报权限不足3.2 公共同义词造成租户对象误命中3.3 角色授权对存储过程失效3.4 只复制 Oracle 权限导致越权4. 方案实施4.1 第一步建立迁移分类4.2 第二步设计账号、Schema 与角色4.3 第三步创建 Schema 并固定所有者4.4 第四步加载 Schema 与对象权限4.5 第五步重建受控同义词4.6 第六步建立权限矩阵4.7 第七步自动生成差异与验证脚本4.7.1 对象解析验证4.7.2 正向授权验证4.7.3 反向越权验证4.8 第八步数据一致性校验4.9 第九步灰度切换5. 结果对比5.1 改造前后对比5.2 示例验证结果5.3 性能影响6. 风险与复盘6.1 主要风险6.2 回退方案6.3 项目复盘附录 A权限基线核对清单每日一句正能量最难得的情谊莫过于你在向我奔赴而我亦在等你。双向的奔赴才不消耗彼此。单方面的追赶或等待都算不上真正的相遇。1. 背景与问题某多租户业务平台采用“一个租户一个业务 Schema公共能力集中在共享 Schema”的 Oracle 架构。应用连接账号并不直接拥有全部业务表而是通过角色、私有同义词、公共同义词和跨 Schema 授权访问对象。经过多年演进数据库中形成了三类典型依赖应用 SQL 不带 Schema 前缀例如SELECT * FROM orders实际依赖当前用户下的私有同义词公共同义词把SYS_DICT.CODE_ITEM暴露为全库可解析的CODE_ITEM存储过程以定义者权限运行但部分底层表权限仅通过角色间接获得。这类系统迁移最容易出现一种“表面成功”表、索引、视图和程序包都已导入SQL 也能编译但上线后出现对象找不到、权限不足、误命中同名对象甚至跨租户读写。根因不是数据没迁完而是 Oracle 的对象解析链路、Schema 概念、同义词可见性和授权路径没有被完整建模。同义词本身只是对象别名不替代基对象授权。Oracle 和金仓数据库的官方资料都强调用户通过同义词访问对象时最终仍受基对象权限约束。金仓数据库使用角色统一管理用户与用户组能力Schema 还具有USAGE、CREATE等权限维度。因此迁移不能只生成CREATE SYNONYM还必须同步处理 Schema 使用权、对象权限、角色继承和默认角色。本次迁移把问题拆成四个目标解析一致原 SQL 中未限定名称在目标端命中正确对象权限等价业务账号保留必要能力但不复制历史冗余权限租户隔离租户 A 不能读写租户 B公共对象按只读或受控执行开放可回退权限变更、对象切换和数据增量都能够撤销或补偿。2. 环境与数据2.1 脱敏环境项目Oracle 源端金仓目标端数据库用途多租户订单与结算迁移目标库业务 SchemaTENANT_A、TENANT_B同名 Schema公共 SchemaSYS_DICT、SHARED_RPT同名 Schema应用账号APP_A_RW、APP_B_RW、REPORT_RO对应登录角色对象规模表 680、视图 126、程序对象 94按清单迁移同义词私有 312、公共 47逐项分类处理角色业务角色 18、运维角色 6重构为职责角色2.2 迁移前必须采集的对象清单仅导出ALL_SYNONYMS不够还要把同义词目标、基对象类型、授权来源、依赖 SQL 和租户归属关联起来。建议形成如下字段字段含义synonym_owner同义词所有者PUBLIC需单独标记synonym_name同义词名称target_owner基对象 Schematarget_name基对象名称target_type表、视图、序列、过程、包等db_link是否指向远端数据库grantee最终访问主体grant_path直接授权、角色授权或角色嵌套tenant_scope租户独享、共享只读、平台管理sql_countSQL 或程序对象引用次数migration_action显式限定、私有同义词、兼容视图或淘汰Oracle 侧清单脚本-- 1. 同义词及目标对象SELECTs.ownerASsynonym_owner,s.synonym_name,s.table_ownerAStarget_owner,s.table_nameAStarget_name,s.db_link,o.object_typeAStarget_type,o.statusFROMdba_synonyms sLEFTJOINdba_objects oONo.owners.table_ownerANDo.object_names.table_nameORDERBYs.owner,s.synonym_name;-- 2. 对象授权SELECTowner,table_name,grantee,privilege,grantable,hierarchyFROMdba_tab_privsWHEREownerIN(TENANT_A,TENANT_B,SYS_DICT,SHARED_RPT)ORDERBYowner,table_name,grantee,privilege;-- 3. 系统权限与角色成员关系SELECTgrantee,privilege,admin_optionFROMdba_sys_privsWHEREgranteeIN(APP_A_RW,APP_B_RW,REPORT_RO);SELECTgrantee,granted_role,admin_option,default_roleFROMdba_role_privsWHEREgranteeIN(APP_A_RW,APP_B_RW,REPORT_RO);-- 4. Schema 间依赖SELECTowner,name,type,referenced_owner,referenced_name,referenced_typeFROMdba_dependenciesWHEREownerIN(TENANT_A,TENANT_B,SYS_DICT,SHARED_RPT)ANDreferenced_ownerownerORDERBYowner,name;还应扫描应用代码中的未限定对象名。数据库依赖视图只能看到已编译对象无法覆盖 MyBatis XML、动态 SQL、脚本任务和报表模板。# 示例扫描 SQL 中可能未带 Schema 的核心对象grep-RniE\b(FROM|JOIN|UPDATE|INTO)[[:space:]](ORDERS|CUSTOMER|CODE_ITEM)\b\./application-sourceunqualified_object_refs.txt3. 复现过程3.1 同义词创建成功但访问仍然报权限不足Oracle 中CREATESYNONYM APP_A_RW.ORDERSFORTENANT_A.ORDERS;GRANTSELECT,INSERT,UPDATEONTENANT_A.ORDERSTOAPP_A_RW;如果迁移时只在目标端执行CREATESYNONYM APP_A_RW.ORDERSFORTENANT_A.ORDERS;应用执行SELECT * FROM orders可能能够解析到同义词却因为没有基对象权限而失败。若目标端还要求访问主体具备对应 Schema 的使用权则只授表权限仍不完整。目标端应同时验证GRANTUSAGEONSCHEMATENANT_ATOAPP_A_RW;GRANTSELECT,INSERT,UPDATEONTABLETENANT_A.ORDERSTOAPP_A_RW;这说明迁移单位不能是“单个同义词”而应是登录角色 当前 Schema/搜索路径 同义词 Schema 权限 基对象权限 角色继承。3.2 公共同义词造成租户对象误命中Oracle 历史环境中存在CREATEPUBLICSYNONYM CUSTOMERFORTENANT_A.CUSTOMER;后来租户 B 也创建了TENANT_B.CUSTOMER但部分报表 SQL 仍写成SELECTcustomer_id,customer_nameFROMcustomer;不同账号、当前 Schema 和私有同义词状态可能导致解析结果不一致。迁移后若照搬公共同义词租户 B 报表甚至可能命中租户 A 的对象。处理原则是公共同义词不是默认兼容方案而是高风险遗留项。对租户数据表应优先改为显式TENANT_B.CUSTOMER或者在每个租户应用账号下创建受控私有同义词。公共同义词只保留给确实全库共享、命名稳定且权限边界清晰的对象。3.3 角色授权对存储过程失效应用账号通过角色获得表权限普通 SQL 可执行但某些定义者权限过程在编译或运行时失败。原因是程序对象的权限检查与交互式 SQL 不完全相同迁移时不能假定“账号通过角色能查表过程也一定能查”。验证样例-- 角色拥有表权限GRANTSELECTONTENANT_A.SETTLEMENT_RULETOROLE_SETTLEMENT_RW;GRANTROLE_SETTLEMENT_RWTOPROC_OWNER;-- 过程引用跨 Schema 表CREATEORREPLACEFUNCTIONPROC_OWNER.GET_RULE_COUNT()RETURNINTEGERASv_countINTEGER;BEGINSELECTCOUNT(*)INTOv_countFROMTENANT_A.SETTLEMENT_RULE;RETURNv_count;END;/若目标版本或兼容模式要求过程所有者拥有直接对象权限则必须补充GRANTSELECTONTENANT_A.SETTLEMENT_RULETOPROC_OWNER;因此程序对象迁移要建立“直接授权白名单”不能把所有跨 Schema 访问都押在角色继承上。3.4 只复制 Oracle 权限导致越权源库历史上曾为排障临时授予GRANTSELECTANYTABLETOREPORT_RO;如果迁移工具原样复制系统权限报表账号就能读取所有租户表违反最小权限原则。迁移不是“权限克隆”而是借机进行职责重构将ANY类系统权限拆成具体 Schema 和对象授权把运维权限、数据修复权限和应用运行权限彻底分离。4. 方案实施4.1 第一步建立迁移分类对全部同义词和跨 Schema 引用按四类处理。类别判定条件迁移策略A显式限定应用可改造核心 SQL 稳定改为schema.object逐步移除同义词B兼容同义词老旧应用无法短期改 SQL创建私有同义词并显式授基对象权限C共享访问层多租户只读公共数据建共享视图或报表 Schema统一只读授权D淘汰/专项公共同义词冲突、DBLINK、废弃对象删除、替换或转入跨库专项这一步的关键不是追求最少改动而是先消除名称解析的不确定性。只要同一个未限定名称可能在不同账号下命中不同对象就必须列为高风险。4.2 第二步设计账号、Schema 与角色建议把“能登录的账号”和“承载权限的职责角色”分开-- 登录账号/角色CREATEROLE APP_A_RW LOGIN PASSWORD***;CREATEROLE APP_B_RW LOGIN PASSWORD***;CREATEROLE REPORT_RO LOGIN PASSWORD***;-- 职责角色CREATEROLE ROLE_TENANT_A_RW NOLOGIN;CREATEROLE ROLE_TENANT_B_RW NOLOGIN;CREATEROLE ROLE_SHARED_RO NOLOGIN;CREATEROLE ROLE_BATCH_EXEC NOLOGIN;-- 角色成员关系GRANTROLE_TENANT_A_RWTOAPP_A_RW;GRANTROLE_SHARED_ROTOAPP_A_RW;GRANTROLE_TENANT_B_RWTOAPP_B_RW;GRANTROLE_SHARED_ROTOAPP_B_RW;GRANTROLE_SHARED_ROTOREPORT_RO;不要将应用账号设为超级用户也不要给它CREATEROLE、CREATEDB等管理能力。金仓数据库角色既可代表用户也可代表用户组正适合用职责角色收敛授权。4.3 第三步创建 Schema 并固定所有者CREATEROLE OWNER_TENANT_A NOLOGIN;CREATEROLE OWNER_TENANT_B NOLOGIN;CREATEROLE OWNER_SHARED NOLOGIN;CREATESCHEMATENANT_AAUTHORIZATIONOWNER_TENANT_A;CREATESCHEMATENANT_BAUTHORIZATIONOWNER_TENANT_B;CREATESCHEMASYS_DICTAUTHORIZATIONOWNER_SHARED;CREATESCHEMASHARED_RPTAUTHORIZATIONOWNER_SHARED;对象所有者不建议直接作为应用登录账号。这样可避免应用连接被利用后执行 DDL也便于后续统一变更对象所有权。4.4 第四步加载 Schema 与对象权限-- 租户 AGRANTUSAGEONSCHEMATENANT_ATOROLE_TENANT_A_RW;GRANTSELECT,INSERT,UPDATE,DELETEONALLTABLESINSCHEMATENANT_ATOROLE_TENANT_A_RW;GRANTUSAGE,SELECTONALLSEQUENCESINSCHEMATENANT_ATOROLE_TENANT_A_RW;-- 公共字典只读GRANTUSAGEONSCHEMASYS_DICTTOROLE_SHARED_RO;GRANTSELECTONALLTABLESINSCHEMASYS_DICTTOROLE_SHARED_RO;-- 报表共享层GRANTUSAGEONSCHEMASHARED_RPTTOROLE_SHARED_RO;GRANTSELECTONALLTABLESINSCHEMASHARED_RPTTOROLE_SHARED_RO;迁移后还要处理未来新建对象的默认权限否则新表上线后应用会突然报错ALTERDEFAULTPRIVILEGESFORROLE OWNER_TENANT_AINSCHEMATENANT_AGRANTSELECT,INSERT,UPDATE,DELETEONTABLESTOROLE_TENANT_A_RW;ALTERDEFAULTPRIVILEGESFORROLE OWNER_TENANT_AINSCHEMATENANT_AGRANTUSAGE,SELECTONSEQUENCESTOROLE_TENANT_A_RW;默认权限的执行者必须与未来创建对象的所有者一致若多个发布账号都可能建表则每个所有者都要配置。4.5 第五步重建受控同义词保留同义词时坚持三条规则租户业务对象只建私有同义词同义词名与目标映射进入版本库每个同义词必须绑定一条基对象授权验证。CREATESYNONYM APP_A_RW.ORDERSFORTENANT_A.ORDERS;CREATESYNONYM APP_A_RW.CUSTOMERFORTENANT_A.CUSTOMER;CREATESYNONYM APP_B_RW.ORDERSFORTENANT_B.ORDERS;CREATESYNONYM APP_B_RW.CUSTOMERFORTENANT_B.CUSTOMER;对于共享字典可以保留显式 Schema 引用确需兼容时建议为每个应用账号建立私有同义词而不是创建全局公共同义词。4.6 第六步建立权限矩阵矩阵应覆盖“主体 × Schema × 对象类型 × 操作”至少包含登录、连接数据库SchemaUSAGE与CREATE表的SELECT/INSERT/UPDATE/DELETE/TRUNCATE/REFERENCES/TRIGGER序列USAGE/SELECT/UPDATE函数与过程EXECUTEDDL、运维、审计和备份能力是否允许向其他角色转授是否属于临时迁移权限。权限矩阵示例主体TENANT_ATENANT_BSYS_DICTSHARED_RPTAPP_A_RW表读写、序列使用禁止只读只读APP_B_RW禁止表读写、序列使用只读只读REPORT_RO只读视图只读视图只读只读BATCH_JOB指定过程执行指定过程执行只读写入汇总表DBA_OPS变更审批后管理变更审批后管理管理管理PUBLIC禁止禁止禁止禁止4.7 第七步自动生成差异与验证脚本目标端验证脚本应从三个层面执行。4.7.1 对象解析验证-- 使用真实应用账号连接后执行SELECTcurrent_user,current_schema;SELECTCOUNT(*)FROMorders;SELECTCOUNT(*)FROMcustomer;SELECTCOUNT(*)FROMcode_item;-- 显式对象与同义词结果必须一致SELECT(SELECTCOUNT(*)FROMorders)ASsynonym_count,(SELECTCOUNT(*)FROMTENANT_A.ORDERS)ASqualified_count;4.7.2 正向授权验证-- APP_A_RW 应成功SELECTCOUNT(*)FROMTENANT_A.ORDERS;INSERTINTOTENANT_A.ORDERS(ORDER_ID,TENANT_ID,ORDER_STATUS)VALUES(990000001,A,MIG_TEST);ROLLBACK;-- REPORT_RO 应成功查询SELECTCOUNT(*)FROMSHARED_RPT.DAILY_ORDER_SUMMARY;4.7.3 反向越权验证“应该失败”的用例比“应该成功”的用例更重要-- APP_A_RW 必须失败访问租户 BSELECTCOUNT(*)FROMTENANT_B.ORDERS;-- REPORT_RO 必须失败写入租户表UPDATETENANT_A.ORDERSSETORDER_STATUSXWHEREORDER_ID1;-- 应用账号必须失败在业务 Schema 建表CREATETABLETENANT_A.PRIV_TEST(IDINTEGER);-- 应用账号必须失败向他人转授GRANTSELECTONTENANT_A.ORDERSTOPUBLIC;自动化测试程序应把 SQLSTATE、错误类别和预期结果记录下来而不是只比对错误文本。错误消息可能随版本与语言变化SQLSTATE 更适合回归。示例验证表CREATETABLEMIGRATION_PRIV_TEST_LOG(TEST_IDVARCHAR(64)PRIMARYKEY,LOGIN_ROLEVARCHAR(128)NOTNULL,TEST_SQLTEXTNOTNULL,EXPECTED_RESULTVARCHAR(16)NOTNULL,-- SUCCESS / DENIEDACTUAL_RESULTVARCHAR(16),SQLSTATE_CODEVARCHAR(8),ERROR_MESSAGETEXT,TEST_TIMETIMESTAMPDEFAULTCURRENT_TIMESTAMP);4.8 第八步数据一致性校验权限迁移看似不涉及数据转换但对象解析错误会让 SQL 查询到“另一张同名表”因此必须进行数据校验。-- 1. 租户键一致SELECTtenant_id,COUNT(*),SUM(order_amount)FROMTENANT_A.ORDERSGROUPBYtenant_id;-- 2. 禁止混入其他租户SELECTCOUNT(*)ASwrong_tenant_rowsFROMTENANT_A.ORDERSWHEREtenant_idA;-- 3. 通过同义词和显式对象分别计算摘要SELECTCOUNT(*)ASrow_cnt,COALESCE(SUM(order_amount),0)ASamount_sum,MIN(order_id)ASmin_id,MAX(order_id)ASmax_idFROMorders;SELECTCOUNT(*)ASrow_cnt,COALESCE(SUM(order_amount),0)ASamount_sum,MIN(order_id)ASmin_id,MAX(order_id)ASmax_idFROMTENANT_A.ORDERS;对报表视图还需按业务日、租户、币种、状态计算分组摘要防止因为搜索路径或同义词映射错误产生“行数接近但业务归属错误”的假一致。4.9 第九步灰度切换推荐步骤冻结源端授权变更导出最终权限基线目标端创建所有者、登录角色、职责角色和 Schema迁移对象加载对象权限、默认权限和同义词使用影子账号执行正向与反向权限用例先切报表只读流量再切批处理最后切核心写流量开启登录、授权失败、DDL 和敏感对象访问审计达到门禁条件后关闭 Oracle 写链路保留只读观察窗口。切换门禁建议同义词映射覆盖率 100%未限定名称解析命中率 100%权限正向用例通过率 100%越权用例成功数为 0核心 SQL 数据摘要差异为 0角色成员关系、默认角色和默认权限均完成复核回退脚本已在演练环境执行成功。5. 结果对比5.1 改造前后对比项目迁移前改造后对象访问大量未限定名称核心 SQL 显式 Schema遗留应用使用私有同义词公共同义词47 个存在租户对象仅保留 6 个真正公共对象应用授权直接授权、角色、ANY 权限混合以职责角色为主关键过程补直接授权Schema 所有者与应用账号混用独立 NOLOGIN 所有者租户隔离依赖约定正向与反向用例自动验证新对象权限发布后人工补授权配置默认权限回退能力无统一脚本角色撤回、连接回切、差异数据补录均有脚本5.2 示例验证结果指标迁移初测整改后未解析对象630公共同义词冲突90越权成功用例70缺失 Schema USAGE210程序对象缺直接授权140新建对象缺默认权限180核心摘要差异3 组0这些数值只用于说明验证方法。实际投稿应替换为真实扫描结果、整改批次、执行耗时和审计截图。5.3 性能影响同义词解析通常不是主要性能瓶颈但错误的搜索路径和同名对象会制造不可预测行为。显式Schema.对象可提升可读性、降低解析歧义也便于 SQL 审计和依赖分析。性能验证仍应关注权限检查和角色切换是否改变连接初始化耗时报表是否因共享视图增加额外过滤层同义词改为视图后谓词能否正常下推连接池是否在复用会话时遗留SET ROLE或 Schema 状态大量授权对象是否延长发布和元数据导入时间。6. 风险与复盘6.1 主要风险风险一把 Schema 当成 Oracle 用户的机械复制。Oracle 中用户与 Schema 高度绑定目标端更适合把登录角色、对象所有者和职责角色拆开。机械复制会继续保留高权限应用账号。风险二只迁移同义词不迁移授权链。同义词可创建并不代表可访问。基对象权限、Schema 使用权和角色状态缺一不可。风险三公共同义词污染全局命名空间。多租户环境尤其危险。公共同义词应逐个审批不应批量照搬。风险四只做“成功用例”不做“越权用例”。权限迁移最严重的问题通常不是访问失败而是本不该访问的对象被成功访问。风险五忽视程序对象的直接权限。存储过程、函数、包和触发器应使用对象所有者真实编译、真实执行不可仅靠管理员账号验证。风险六默认权限遗漏。迁移当天没有问题下一次发布新建表后才暴露权限故障。默认权限必须纳入发布基线。风险七连接池会话状态污染。如果应用执行SET ROLE、修改当前 Schema 或搜索路径归还连接前必须恢复否则可能把租户 A 的解析上下文带给租户 B。6.2 回退方案回退不是简单把连接串改回 Oracle。权限和数据写入已经发生后应按顺序处理暂停目标端写入保留现场与审计日志撤销目标端应用角色成员关系阻断继续访问导出切换窗口内新增或变更数据按业务主键生成补录文件校验 Oracle 源端当前数据执行幂等回放将应用连接切回 Oracle恢复原角色和服务对目标端保留只读分析对象解析、权限或数据差异修复后重新跑全量权限测试与回退演练。目标端快速止损脚本示例-- 撤销登录账号的业务角色REVOKEROLE_TENANT_A_RWFROMAPP_A_RW;REVOKEROLE_SHARED_ROFROMAPP_A_RW;-- 阻止账号继续登录具体语法按实际版本验证ALTERROLE APP_A_RW NOLOGIN;重新开放前必须复核GRANTROLE_TENANT_A_RWTOAPP_A_RW;GRANTROLE_SHARED_ROTOAPP_A_RW;ALTERROLE APP_A_RW LOGIN;6.3 项目复盘本次迁移最大的经验是同义词迁移不是 DDL 转换问题而是名称解析与安全边界重建问题。真正可靠的交付物不应只有建库脚本而应至少包括同义词与基对象映射表Schema、所有者、登录角色和职责角色设计权限矩阵及直接授权白名单正向访问与反向越权验证脚本数据摘要校验结果默认权限配置灰度切换、审计观察和回退记录。当对象解析、授权和数据校验三条链路都可追溯迁移才算完成。否则即使所有对象都“创建成功”也可能在真实业务压力下暴露跨租户访问、程序权限失效和报表读错对象等问题。附录 A权限基线核对清单所有公共同义词均经过必要性审批租户表不存在公共同义词每个同义词均能定位到唯一基对象同义词目标对象类型与源端一致应用登录账号不是对象所有者应用账号无超级用户及ANY类高危权限每个租户职责角色只拥有本租户权限公共数据通过只读角色或共享视图开放程序对象跨 Schema 权限已验证直接授权要求默认权限覆盖未来新建表、序列和函数连接池会话归还前清理角色和 Schema 状态越权测试全部按预期失败灰度期间的权限与数据变化可审计回退脚本已演练。转载自https://blog.csdn.net/u014727709/article/details/163190723欢迎 点赞✍评论⭐收藏欢迎指正