在线迁移pdb

在线迁移pdb的目的

某些情况下要对cdb进行升级、停机等操作,而其中的部分pdb需要保持对外提供服务,那么就可以将pdb迁移到其他的cdb上运行。在线迁移pdb是目前在不停机或者最短停机时间情况下移动pdb的最快方法,如果采用其他的拔下再插入的方式,那么就需要一定的停机时间。

将pdb在不同的数据中心移动时,或者从私有机房迁移到云上环境时,所有的数据都需要物理的移动。对于那些特别大的pdb来说,这个过程则会消耗较长的时间。而PDB在线迁移则可以完全的消除这些不便之处,在线迁移pdb的过程中,应用依然可以对外提供服务,也不需要改变应用的连接设置等。

在线迁移pdb的实现方式

前提条件:

  • 本地cdb下用户必须有CREATE PLUGGABLE DATABASE权限
  • 远端CDB处于local undo模式和归档模式
  • 本地要有指向远端cdb的数据链,数据链里配置的远端cdb用户必须有PLUGGABLE DATABASESYSDBASYSOPER权限
  • 两个数据库要有相同的字节顺序
  • 如果本地CDB字符集是AL32UTF8,则远端字符集不限。否则两者的字符集必须一致

通过CREATE PLUGGABLE DATABASE语句来将pdb从一个CDB中迁移到其他CDB当中。通过FROM语句来指定当前pdb的位置,RELOCATE语句来指定pdb是被迁移而不是之前说的克隆。在这些操作完成以后,pdb就会被添加到新的CDB当中,同时会将pdb相关的文件也移动过去。

另外在迁移的过程中,被迁移的库是可以处于读写模式下实时提供服务的,在传输和应用redo到新的位置过程中会自动将原pdb静止在旧位置。最后当pdb准备好了,则会将其在新位置上线。当pdb在线迁移完毕,当前指向新位置的的DML和DDL操作会暂停,而查询则不受影响。

必须要创建一个数据链来进行迁移操作,从本地cdb指向远端新位置所在的CDB。

也可以将cdb下的pdb迁移到另一个应用容器下作为容器pdb,也可以将应用容器下的pdb迁移到另一个应用容器下,也可以将一个不包含应用pdb的应用根节点迁移到应用容器下作为应用pdb

pdb迁移后,有两种方式处理连接,AVAILABILITY MAX和AVAILABILITY NORMAL。AVAILABILITY MAX可以将指向旧位置的连接重定向到新位置,而这种情况下又包含下面这些选项

  • 如果系统采用Oracle Internet Directory (Oracle’s LDAP directory service),则连接信息会在一个中心区域进行更新而不是更新每个客户端的配置文件。
  • 如果新位置pdb也采用的同样的监听,则新的连接会在迁移完成后自动路由到新的PDB位置
  • 如果新位置pdb采用不同的监听,则需要配置local_listenerremote_listener参数来使用它们各自的监听进行交叉注册,位置的变换是无缝的,因为pdb服务器的可用性和位置都是通过监听自动注册的。

在线迁移pdb

远端cdb上新建用户,必须要有CREATE PLUGGABLE DATABASE的权限

1
2
3
4
5
6
7
8
9
10
11
12
13
create user c#xb identified by xb container=all;
grant create session,sysoper, create pluggable database to c#xb container=all;

# 必须本地undo模式和归档模式下
archive log list;

col property_name for a30
col property_value for a30
select property_name,property_value from database_properties where property_name='LOCAL_UNDO_ENABLED';

PROPERTY_NAME PROPERTY_VALUE
------------------------------ ------------------------------
LOCAL_UNDO_ENABLED TRUE

本地cdb新建数据链

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
drop public database link to_remote;

create public database link to_remote connect to c#xb identified by xb using '(DESCRIPTION =
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = TCP)(HOST = stbyum)(PORT = 1521))
)
(CONNECT_DATA =
(SERVICE_NAME = cdb1)
)
)';

# 测试数据链
sys@ORA12C> select * from dual@to_remote;

D
-
X

# 检查cdb的本地undo模式和archive log
col property_name for a30
col property_value for a30
select property_name,property_value from database_properties where property_name='LOCAL_UNDO_ENABLED';

PROPERTY_NAME PROPERTY_VALUE
------------------------------ ------------------------------
LOCAL_UNDO_ENABLED TRUE

archive log list;

在线迁移pdb

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
sys@ORA12C> create pluggable database pdb3 from pdb3@to_remote relocate;

Pluggable database created.

sys@ORA12C> show pdbs;

CON_ID CON_NAME OPEN MODE RESTRICTED
---------- ------------------------------ ---------- ----------
2 PDB$SEED READ ONLY NO
3 PDB12C READ WRITE NO
4 PDB3 MOUNTED

# 这个时候本地新建的pdb3还是mount状态,而远端的pdb3还是读写,可以提供服务
sys@CDB1> show pdbs;

CON_ID CON_NAME OPEN MODE RESTRICTED
---------- ------------------------------ ---------- ----------
2 PDB$SEED READ ONLY NO
3 PDB3 READ WRITE NO
sys@CDB1> alter session set container=pdb3;

Session altered.

sys@CDB1> select * from dual;

D
-
X

而当将本地pdb3打开以后,远端的pdb3会自动drop掉

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
sys@ORA12C> alter pluggable database pdb3 open;

Pluggable database altered.

sys@ORA12C> show pdbs;

CON_ID CON_NAME OPEN MODE RESTRICTED
---------- ------------------------------ ---------- ----------
2 PDB$SEED READ ONLY NO
3 PDB12C READ WRITE NO
4 PDB3 READ WRITE NO
sys@ORA12C> select file#,name from v$datafile where con_id=4;

FILE# NAME
---------- ----------------------------------
134 /u01/app/oracle/oradata/ORA12C/8C1E38D38CD88F9EE0536992A8C0E93B/datafile/o1_mf_system_gk8xtgs6_.dbf
135 /u01/app/oracle/oradata/ORA12C/8C1E38D38CD88F9EE0536992A8C0E93B/datafile/o1_mf_sysaux_gk8xtgs7_.dbf
136 /u01/app/oracle/oradata/ORA12C/8C1E38D38CD88F9EE0536992A8C0E93B/datafile/o1_mf_undotbs1_gk8xtgs8_.dbf
137 /u01/app/oracle/oradata/ORA12C/8C1E38D38CD88F9EE0536992A8C0E93B/datafile/o1_mf_tbs1_gk8xtgs8_.dbf

# 远端的pdb被清除了
sys@CDB1> show pdbs;

CON_ID CON_NAME OPEN MODE RESTRICTED
---------- ------------------------------ ---------- ----------
2 PDB$SEED READ ONLY NO

sys@CDB1> select file#,name from v$datafile where con_id=3;

no rows selected

# 删除数据链
drop public database link to_remote;

Proxy PDB

关于proxy pdb

proxy pdb可以让你访问远端cdb像在本地访问一样,类似一个符号链。

可以通过创建一个本地代理pdb来引用一个不同cdb里的pdb,这个被引用的pdb则称为引用pdb。如果要访问引用pdb的数据,那么可以直接访问本地代理pdb即可,简化了一些书写。当不同cdb里的应用容器有相同的应用程序时,可以通过代理pdb来同步应用容器的根节点。

创建代理pdb时都需要创建数据链,都是在本地代理pdb所属的CDB中创建数据链,指向远端的CDB或者引用pdb。

同样也可以在应用容器中创建代理pdb,这样引用pdb则必须是应用根节点或者应用pdb。数据链则要在应用根节点中创建,指向远端的应用根节点或者应用pdb。

  • 代理pdb中的DML和DDL语句都会传输到引用pdb中,结果都会返回代理pdb
  • 当前库是代理pdb时,执行ALTER PLUGGABLE DATABASE和ALTER DATABASE语句都只影响本身,不会传输到引用pdb
  • 当前库是代理pdb所在的cdb时,执行ALTER PLUGGABLE DATABASE语句都只影响本身,不会传输到引用pdb

创建proxy pdb

1
2
3
create pluggable database pdb3_proxy as proxy from pdb3@to_remote;

alter pluggable database pdb3_proxy open;

通过查看proxy pdb的信息,会发现cdb显示的是远端cdb

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
sys@ORA12C> alter session set container=PDB3_PROXY ;

Session altered.

sys@ORA12C> select name from v$database;
select name from v$database
*
ERROR at line 1:
ORA-01017: invalid username/password; logon denied
ORA-02063: preceding line from PROXYPDB$DBLINK


sys@ORA12C> conn sys@ora12c as sysdba
Enter password:
Connected.

sys@ORA12C> alter session set container=PDB3_PROXY ;

Session altered.

sys@ORA12C> select name from v$database;

NAME
---------
CDB1

查看代理pdb的相关信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
sys@ORA12C> select con_id,name,open_mode,proxy_pdb from v$pdbs;

CON_ID NAME OPEN_MODE PRO
---------- ------------------------------ ---------- ---
2 PDB$SEED READ ONLY NO
3 PDB12C READ WRITE NO
4 PDB4 READ WRITE NO
5 APP_ROOT READ WRITE NO
6 APP1 READ WRITE NO
7 APP_ROOT$SEED READ ONLY NO
8 APP2 READ WRITE NO
9 F3483665686_3_1 READ WRITE NO
10 F3483665686_3_2 READ WRITE NO
11 F3483665686_3_3 READ WRITE NO
12 PDB3_PROXY READ WRITE YES

sys@ORA12C> select pdb_name,status,IS_PROXY_PDB from cdb_pdbs;

PDB_NAME STATUS IS_
------------------------------ ---------- ---
PDB$SEED NORMAL NO
PDB12C NORMAL NO
PDB4 NORMAL NO
APP_ROOT NORMAL NO
APP1 NORMAL NO
APP_ROOT$SEED NORMAL NO
APP2 NORMAL NO
F3483665686_3_1 NORMAL NO
F3483665686_3_2 NORMAL NO
F3483665686_3_3 NORMAL NO
PDB3_PROXY NORMAL YES

也可以通过V$PROXY_PDB_TARGETS视图来查看代理pdb指向的哪个引用pdb

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
set linesize 300
col target_host format a20
col target_service format a40
col target_user format a20

select con_id,
target_port,
target_host,
target_service,
target_user
from v$proxy_pdb_targets;

CON_ID TARGET_PORT TARGET_HOST TARGET_SERVICE TARGET_USER
---------- ----------- -------------------- ---------------------------------------- --------------------
12 1521 stbyum 8c1e38d38cd88f9ee0536992a8c0e93b

根据target_service的名称,可以去远端确定是哪个pdb
sys@CDB1> select name,open_mode from v$pdbs where guid=upper('8c1e38d38cd88f9ee0536992a8c0e93b');

NAME OPEN_MODE
---------- ----------
PDB3 READ WRITE

proxy pdb数据传输

验证在代理pdb上创建数据,看是否会影响引用pdb

1
2
3
4
5
6
7
8
9
10
11
12
13
conn sys/oracle@pdb3_proxy as sysdba
create table t1 (id number);

insert into t1 values(1);
commit;

# 查看引用pdb
conn sys/oracle@pdb3 as sysdba
sys@PDB3> select * from t1;

ID
----------
1

看如果反过来的情况怎么样

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
sys@PDB3> insert into t1 values(2);

1 row created.

sys@PDB3> commit;

Commit complete.

# 查看proxy pdb
sys@PDB3_PROXY> select * from t1;

ID
----------
1
2

可以看到无论是在哪边进行ddl、dml的操作,得到的结果都是一样。

那试一下ALTER PLUGGABLE DATABASE的操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 关闭proxy pdb
sys@PDB3_PROXY> alter pluggable database close immediate;

Pluggable database altered.

sys@ORA12C> select open_mode from v$pdbs where name='PDB3_PROXY';

OPEN_MODE
----------
MOUNTED

# 而引用pdb状态仍然是读写
sys@PDB3> show pdbs;

CON_ID CON_NAME OPEN MODE RESTRICTED
---------- ------------------------------ ---------- ----------
3 PDB3 READ WRITE NO

这样就验证了之前的结论。

代理pdb并不是将全部的数据文件同步到本地,而只有一些系统表空间

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 在代理pdb端新建表空间
sys@PDB3_PROXY> create tablespace tbs1 datafile size 10m;

Tablespace created.

sys@ORA12C> select file#,name from v$datafile where con_id=12;

FILE# NAME
---------- ------------------------------------------------------------------------------------------------------------------------
128 /u01/app/oracle/oradata/ORA12C/8C1E5E9B7B4A86A6E0536892A8C0D8F8/datafile/o1_mf_system_gk34lm03_.dbf
129 /u01/app/oracle/oradata/ORA12C/8C1E5E9B7B4A86A6E0536892A8C0D8F8/datafile/o1_mf_sysaux_gk34lm14_.dbf
130 /u01/app/oracle/oradata/ORA12C/8C1E5E9B7B4A86A6E0536892A8C0D8F8/datafile/o1_mf_undotbs1_gk34lm15_.dbf

# 引用pdb端
sys@CDB1> select file#,name from v$datafile where con_id=3;

FILE# NAME
---------- ------------------------------------------------------------------------------------------------------------------------
17 /u01/app/oracle/oradata/CDB1/8C1E38D38CD88F9EE0536992A8C0E93B/datafile/o1_mf_system_gk33yoco_.dbf
18 /u01/app/oracle/oradata/CDB1/8C1E38D38CD88F9EE0536992A8C0E93B/datafile/o1_mf_sysaux_gk33yodn_.dbf
19 /u01/app/oracle/oradata/CDB1/8C1E38D38CD88F9EE0536992A8C0E93B/datafile/o1_mf_undotbs1_gk33yodn_.dbf
20 /u01/app/oracle/oradata/CDB1/8C1E38D38CD88F9EE0536992A8C0E93B/datafile/o1_mf_tbs1_gk3x1g2l_.dbf

说明除了其他表空间外,其他的数据文件都是存放在引用pdb端的,代理pdb都是通过引用pdb端来访问。

当proxy pdb创建完毕,数据链就可以删除了

1
2
drop public database link to_remote;
drop user c#xb cascade ;

proxy pdb和监听

这时代理pdb是直接与引用pdb进行通信,代理pdb通常是采用默认值。

  • 监听端口:1521

    如果引用pdb不是使用的默认端口,那么必须通过PORT选项来指定,可以在创建的时候指定,也可以创建完毕以后修改代理pdb属性

  • 监听主机名称: 包含引用pdb的CDB所在的主机名称

    如果不是默认值,则需要通过HOST选项来指定,可以在创建的时候指定,也可以创建完毕以后修改代理pdb属性

1
2
3
4
5
6
7
8
9
create pluggable database pdb3_proxy as proxy from pdb3@to_remote PORT=1522 HOST='testyum';

-- 修改远端host
alter pluggable database containers host='stbyum';
alter pluggable database containers host rest;

-- 修改远端端口
alter pluggable database containers port='1522';
alter pluggable database containers port rest;

Application Container

顾名思义,表示应用容器。与之前的cdb不同的是,它是作为CDB中的一个pdb存在的,在应用容器下面还可以创建新一级的pdb给应用程序使用。这个应用容器中的程序是可以同步到挂在它下面的一个或多个相同业务模块的pdb当中去。

关于应用容器

应用容器是一个可选的、用户创建的CDB组件,用于存储一个或多个应用端的数据和字典信息。一个CDB可以包含0个或多个应用容器。

比如你可以在一个应用容器中创建多个与销售相关的pdb,这些pdb可以共享一个由一组公共表和表定义的应用端。

创建PDB时只需要指定AS APPLICATION CONTAINER语句就可以创建出一个应用容器的根节点,这时是没有pdb的,需要连接到应用容器根节点以后创建相应的pdb。

管理应用容器

根节点

每个应用容器只有一个应用根节点,是这个应用容器中所有pdb的父节点。

创建的那一刻应用容器的根节点属性就确定了且无法更改,根节点与CDB根节点和标准的PDB都有区别,因为它能储存用户创建的公用对象。应用公用对象可以被所有应用容器下的应用pdb访问,但是这些对象无法被CDB根节点、其他应用根节点和所有不属于这个应用根节点下的pdb所访问。

1
2
3
4
5
6
7
8
9
10
11
12
13
create pluggable database app_root as application container admin user xb identified by xb;
alter pluggable database app_root open;

alter session set container=app_root;
col name format a20
col root format a10
select con_id, name, application_root as root,
application_pdb as pdb
from v$containers;

CON_ID NAME ROOT PDB
---------- -------------------- ---------- ---
5 APP_ROOT YES NO

对应用容器根节点的操作与常规pdb类似,都可以克隆、删除等。

应用容器pdb

创建完根节点以后,要登录到根节点才能创建相关应用pdb。可以通过种子pdb,克隆pdb或者插入一个已经拔下的pdb的方式来创建应用pdb。与CDB根节点下的pdb操作一样,在应用容器中你也可以克隆、拔下或者删除一个应用pdb。但是应用pdb必须属于应用根节点下。

1
2
3
alter session set container=app_root;
create pluggable database app1 admin user xb1 identified by xb;
alter pluggable database app1 open;

当创建完一个新的应用pdb后,需要将应用根节点的数据同步到pdb当中来

1
2
alter session set container=app1;
alter pluggable database application all sync;

可以通过在应用根节点或者CDB根节点来删除应用pdb

1
2
3
alter pluggable database close immediate;
alter session set container=cdb$root;
drop pluggable database app1 including datafiles;

应用种子pdb

应用种子pdb是可选的、在应用容器中由用户创建的pdb。可以让你很快速的创建应用pdb,在应用容器中的角色与CDB$root中的seed角色一样。

1
2
3
4
5
6
7
8
9
10
11
12
# 创建种子pdb
alter session set container=app_root;
create pluggable database as seed admin user seed_xb identified by xb;
alter pluggable database app_root$seed open;

# 刷新种子pdb
alter session set container=app_root$seed;
alter pluggable database application all sync;

# 将种子pdb置于只读
alter pluggable database close immediate;
alter pluggable database open read only;

也可以通过其他应用pdb来创建种子pdb

1
2
3
4
5
6
7
8
alter session set container=app_root;
alter pluggable database app_root$seed close immediate;
drop pluggable database app_root$seed including datafiles;

create pluggable database as seed from app1;
alter pluggable database app_root$seed open;
alter pluggable database app_root$seed close immediate;
alter pluggable database app_root$seed open read only;

通过应用根节点来创建种子pdb

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
create pluggable database as seed from app_root;
alter pluggable database app_root$seed open;

# 种子pdb打开时有告警
sys@ORA12C>
Warning: PDB altered with errors.

sys@ORA12C> select message,time from pdb_plug_in_violations;

MESSAGE TIME
---------------------------------------------------------------------------------------------------- ----------------------------------------------------
Non-Application PDB plugged in as an Application PDB, requires pdb_to_apppdb.sql be run. 20-JUN-19 01.37.32.388687 PM

# 提示要运行pdb_to_apppdb.sql
alter session set container=app_root$seed;
@$ORACLE_HOME/rdbms/admin/pdb_to_apppdb.sql

# 重新打开种子pdb
alter pluggable database app_root$seed close immediate;
alter pluggable database app_root$seed open read only;

应用公共对象

应用公共对象是创建在应用根节点里的应用的公共对象,访问它的pdb要么是数据关联或者是元数据关联。

对于数据关联的对象,应用pdb共享一组数据。比如一个销售应用容器当中有一个销售应用程序,版本是1.0,包含了一个数据关联的销售表。在这个情况下,虽然这个表是存储在应用根节点的,但是可以被这个根节点下的所有pdb所访问。

对于元数据关联的对象,应用pdb则只共享元数据,但是各自包含不同的数据。比如是之前那张销售表sales,这时每个pdb下有这样一张sales表,表定义完全一样,但是存储的是完全不同的数据。

创建应用公共对象

对象类型 共享内容 元数据存储 数据存储
数据关联 数据 应用根节点 应用根节点
扩展数据关联 扩展数据 应用根节点 应用根节点和应用pdb
元数据关联 元数据 应用根节点 应用pdb

有两种方式来决定对象的共享属性,DEFAULT_SHARING参数和SHARING语句。

1
2
3
PARAMETER_NAME                                               TYPE        VALUE
------------------------------------------------------------ ----------- --------------------------
default_sharing string METADATA

默认都是元数据共享。

元数据关联

因为只能在应用程序的安装、升级或打补丁时才能创建和修改公共对象,所以先创建应用程序。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 创建应用
alter session set container=app_root;
alter pluggable database application sales_app begin install '1.0';

# 创建表空间和用户
create tablespace tbs_sales datafile size 10m autoextend on;
create user sales_xb identified by xb container=all;
grant dba to sales_xb;
alter user sales_xb default tablespace tbs_sales;

# 创建元数据关联表
drop table sales_xb.sales purge;
create table sales_xb.sales SHARING=METADATA
(id number,
amount number);

insert into sales_xb.sales values(1,100);
commit;

# 结束应用的创建
alter pluggable database application sales_app end install '1.0';

现在可以通过DBA_APPLICATIONS视图查看刚创建的应用

1
2
3
4
5
6
7
8
9
10
11
12
col app_name format a20
col app_version format a10

select app_name,
app_version,
app_status
from dba_applications
where app_name = 'SALES_APP';

APP_NAME APP_VERSIO APP_STATUS
-------------------- ---------- ------------
SALES_APP 1.0 NORMAL

现在就可以通过ALTER PLUGGABLE DATABASE APPLICATION ... SYNC语句将应用程序的定义信息同步到应用的pdb当中去,每个应用的pdb会有一个与sales_xb.sales表一样元数据的表,但是数据是各自存在每个pdb自己当中的。

这里总共建了两个应用pdb,分别是pdb1和pdb2

1
2
3
4
5
6
7
8
sys@ORA12C> show pdbs;

CON_ID CON_NAME OPEN MODE RESTRICTED
---------- ------------------------------ ---------- ----------
5 APP_ROOT READ WRITE NO
6 APP1 READ WRITE NO
7 APP_ROOT$SEED READ ONLY NO
8 APP2 READ WRITE NO

同步到APP1当中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
alter session set container=app1;
select * from sales_xb.sales;

ERROR at line 1:
ORA-00942: table or view does not exist

# 刷新数据
alter pluggable database application sales_app sync;

sys@ORA12C> select * from sales_xb.sales;

ID AMOUNT
---------- ----------
1 100

这样应用程序就同步到了app1当中,可以通过视图DBA_APP_PDB_STATUS查询到应用程序与pdb的关系状态

1
2
3
4
5
6
7
8
9
10
11
12
13
alter session set container=app_root;
select c.name,
a.con_uid,
a.app_name,
a.app_version,
a.app_status
from dba_app_pdb_status a
join v$containers c on c.con_uid = a.con_uid
where a.app_name = 'SALES_APP';

NAME CON_UID APP_NAME APP_VERSIO APP_STATUS
-------------------- ---------- -------------------- ---------- ------------
APP1 3232047153 SALES_APP 1.0 NORMAL

数据关联

这里升级应用程序从1.0到2.0,然后创建数据关联的公用表

1
2
3
4
5
6
7
8
9
10
11
12
# 升级应用程序
alter pluggable database application sales_app begin upgrade '1.0' to '2.0';

drop table sales_xb.sales2 purge;
create table sales_xb.sales2 SHARING=DATA
(id number,
amount number);

insert into sales_xb.sales2 values(2,100);
commit;

alter pluggable database application sales_app end upgrade to '2.0';

同步APP2的pdb

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
alter session set container=app2;

alter pluggable database application sales_app sync;
select * from sales_xb.sales2;

ID AMOUNT
---------- ----------
2 100

alter session set container=app_root;
select c.name,
a.con_uid,
a.app_name,
a.app_version,
a.app_status
from dba_app_pdb_status a
join v$containers c on c.con_uid = a.con_uid
where a.app_name = 'SALES_APP';

NAME CON_UID APP_NAME APP_VERSIO APP_STATUS
-------------------- ---------- -------------------- ---------- ------------
APP1 3232047153 SALES_APP 1.0 NORMAL
APP2 827740620 SALES_APP 2.0 NORMAL

扩展数据关联

新建扩展数据关联的公用表,然后同步到app1当中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
alter pluggable database application sales_app begin upgrade '2.0' to '3.0';

drop table sales_xb.sales3 purge;
create table sales_xb.sales3 SHARING=EXTENDED DATA
(id number,
amount number);

insert into sales_xb.sales3 values(3,100);
commit;

alter pluggable database application sales_app end upgrade to '3.0';


alter session set container=app1;

alter pluggable database application sales_app sync;
select * from sales_xb.sales3;

ID AMOUNT
---------- ----------
3 100

alter session set container=app_root;
select c.name,
a.con_uid,
a.app_name,
a.app_version,
a.app_status
from dba_app_pdb_status a
join v$containers c on c.con_uid = a.con_uid
where a.app_name = 'SALES_APP';

NAME CON_UID APP_NAME APP_VERSIO APP_STATUS
-------------------- ---------- -------------------- ---------- ------------
APP2 827740620 SALES_APP 2.0 NORMAL
APP1 3232047153 SALES_APP 3.0 NORMAL

接下来验证一下不同共享模式下数据的读写情况

1
2
3
4
5
6
7
8
9
10
# sales -> metadata
# sales2 -> data
# sales3 -> extended data
alter session set container=app1;
insert into sales_xb.sales values(1,200);
insert into sales_xb.sales2 values(2,200);
insert into sales_xb.sales3 values(3,200);
commit;

# 在插入sales2时出现报错 ORA-65097: DML into a data link table is outside an application action。

说明对于数据关联的表是无法在应用pdb级别进行dml操作的,而对于metadata和extended data来说,每个pdb只共享了元数据或部分数据,允许每个pdb有自己独立的数据存在。

应用程序卸载

1
2
3
4
5
6
7
alter session set container=app_root;

alter pluggable database application sales_app begin uninstall;
drop user sales_xb cascade;
drop tablespace tbs_sales including contents and datafiles;

alter pluggable database application sales_app end uninstall;

同步所有的pdb

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
alter session set container=app1;
alter pluggable database application sales_app sync;

alter session set container=app2;
alter pluggable database application sales_app sync;

alter session set container=app_root;
select c.name,
a.con_uid,
a.app_name,
a.app_version,
a.app_status
from dba_app_pdb_status a
join v$containers c on c.con_uid = a.con_uid
where a.app_name = 'SALES_APP';

NAME CON_UID APP_NAME APP_VERSIO APP_STATUS
-------------------- ---------- -------------------- ---------- ------------
APP1 3232047153 SALES_APP 3.0 UNINSTALLED
APP2 827740620 SALES_APP 3.0 UNINSTALLED