Application Container

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

关于应用容器

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

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

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

管理应用容器

根节点

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

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

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必须属于应用根节点下。

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

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

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

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

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

应用种子pdb

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

# 创建种子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

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

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语句。

PARAMETER_NAME                                               TYPE        VALUE
------------------------------------------------------------ ----------- --------------------------
default_sharing                                              string      METADATA

默认都是元数据共享。

元数据关联

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

# 创建应用
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视图查看刚创建的应用

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

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当中

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的关系状态

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,然后创建数据关联的公用表

# 升级应用程序
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

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当中

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

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

# 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有自己独立的数据存在。

应用程序卸载

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

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