在oracle数据库的运维过程中,常常会有一些特殊场景,需要我们灵活运用知识去解决问题,今天,就和大家一起探讨分析一种情况。我们需要将一个数据库从一个环境迁移到另外一个,但因为种种限制因素,只能采用数据导入导出的方式来进行。在梳理环境编写迁移方案的时候,遇到了一个难题,数据库里有大量的dblink,大家知道这些dblink是在使用的,但是没有人知道密码。下面,我们使用模拟环境来表达分析解决过程。
数据库版本:
数据库链接:
在模拟环境中共有3数据库链接,我们以source这个为例。首先,我们确定这个dblink是可用的:
这个时候,很多同学可能就想到了,既然数据库链接source可以用,那就说明本地库(9i,服务名firefox)是知道访问远程库(11g,服务名source)时用到的用户名和密码的,那么oracle会把它存在哪里呢?难道是dba_db_links的其它列?我们一起来看看:
owner列存储dblink的所有者,值public代表是公共的;
db_link列存储dblink的名字;
username列存储dblink访问远程库的用户名;
host列存储dblink远程库的连接字符串,或者本地服务名;
create列存储列dblink的创建时间;
dba_db_links中对于dblink以哪个用户访问哪个库都做了详细的保存,但就是没有密码信息。到这里我们不要失望,因为我们知道所有的数据字典其实都不是真正的表格,而是基于内部表的一系列视图。我们去看看dba_db_links的定义:
知识点:其实数据字典严格的名字应该叫数据字典视图,它提供了数据库的一些系统信息,数据字典是基于数据字典基表(也叫内部表,以$结尾)所建立的一系列视图,数据字典视图主要包括三种类型:user_xxx,all_xxx和dba_xxx。
原来dba_db_links的数据来自于link$和user$两个内部表,那么密码会不会在这两个表里保存?我们去看看它们的结构:
知识点:内部表,sys用户下以$结尾的一系列表,是数据库内核的组成部分,用户只能在上面执行查询操作,其维护和修改是系统自动完成的,对其的不当操作可能会造成数据库宕机、甚至永久性损坏。
在link$和user$中我们发现都有一个password字段,那么哪一个是我们要找的dblink的密码呢?我们先来看看其中的内容:
内容太多,只选取相关的部分
我们发现link$中的密码以明文保存,user$中的密码以加密后的字符串保存。但到底哪个才是我们要找的密码呢?其实oracle在设计内部表时每个都有明确的作用和定义,其中link$是用来保存dblink相关信息的(包括密码),user$是用来数据库本地用户相关信息的。
那么现在我们就找到了数据库链接source的密码:tiger,再根据其它信息,可以很快写出其迁移重建语句:
create public database link SOURCE
connect to SCOTT identified by "tiger"
using '(DESCRIPTION =
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.127.136)(PORT = 1521))
)
(CONNECT_DATA =
(SERVICE_NAME = source)
)
)';
知识点:在10gR1及之前的版本里,所有dblink的密码都是以明文方式在sys.link$中存储,但是在10gR2及之后版本,oracle进行了改良,以加密方式存储。
针对10gR2及之后版本,我们虽然不能直接取得密码,但也可以通过更新内部表的方式来实现迁移。Oracle对于直接修改内部表是严格禁止的,因为不当操作可能会造成数据库宕机、甚至永久性损坏。因为dblink是数据库里比较独立关联性小的一个功能,因此我们才有可能采取这种方式。但即便如此,也要求在做好备份后,由经验丰富掌握相关知识的工程师进行操作。
同样,先来看看数据库版本:
数据库链接
还是以数据库链接source为例,我们先测试其可用性:
接下来我们看看sys.link$在10gR2及之后的表结构变化,并直接从其中查询密码:
与上面的9i对比,多了两个列,其中PASSWORDX列就是用来存储加密之后的密码。
通过查询我们发现,password列虽然还在,但是内容为空,passwordx列则保存了加密之后的密码。
我们可以通过pl/sql dev之类的工具,将sys.link$的内容导出为sql语句,每个insert语句对应一个dblink信息。对导出文件进行编辑,保留我们需要迁移的dblink语句,删掉其它。
在目标环境上以sys身份执行脚本,然后对迁移后的dblink进行测试。
至此,完成了在不知道密码情况下对 dblink 的迁移。另外,这里再插入个小知识点:还有另外的技巧能够简单快速的实现这个事情,使用 dbms_metadata 包,抽取 dblink 的 ddl,会生成包含加密密码的创建语句,在目标库跑这个 ddl,也能实现创建。但是这个方法,在11.2.0.4版本及以后被 Oracle 禁用了,不再支持。所以这里就不演示啦。那个 ddl 抽取出来的样子,基本是这样:
因为是用加密字符串表达密码,所以比平时多了个 values 关键字。
© 2016, morinson. 版权所有. 欢迎转载,但请保留作者及出处。