# [OCI-26ai] Refreshable Clone PDBs

*El artículo también se encuentra publicado en Ingles* [***English version***](https://dbaintheshadow.com/oci-26ai-refreshable-clone-pdbs?showSharer=true)*.*

En el artículo de hoy, vamos a ver como podemos realizar una copia de una PDB y mantenerla actualizada con el origen.

Este tipo de migración, la podemos realizar de manera local (dentro de la misma CDB) o de manera remota (otra CDB). En este artículo nos vamos a centrar en como hacerlo remotamente.

Otro punto que tenemos que tener en cuenta es que debemos tener configurado **SEPS** ya que vamos a definir las distintas PDB usando **external store**. En próximos artículos, os explicare como configurar este punto fácilmente.

Para poder llevar a cabo este laboratorio, vamos a definir dos máquinas virtuales, ambas con la última versión de Oracle en OCI.

Las máquinas que hemos definido son las siguientes:

* **Source**: 26ai VM DB System Oracle Cloud (*test\_ORI*).
    
* **Target**: 26ai VM DB System Oracle Cloud (*test\_TARGET*).
    

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1766234418615/7af4855c-a9fd-42fd-8227-5b195d359ea8.png align="center")

Y el modelo que vamos a seguir es el siguiente:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1766234319392/ee0c4aa8-31b2-48bd-8f0b-05c4e91b44c3.png align="center")

* 1º: Definir la PDB REFRESH\_PDB en TEST\_ORI:
    

```plaintext
SQL> CREATE PLUGGABLE DATABASE REFRESH_PDB ADMIN USER admin IDENTIFIED BY admin;
Pluggable database created.
SQL> ALTER PLUGGABLE DATABASE REFRESH_PDB OPEN;
Pluggable database altered.
SQL> ALTER PLUGGABLE DATABASE REFRESH_PDB SAVE STATE;
Pluggable database altered.
SQL> SHOW PDBS

    CON_ID CON_NAME                       OPEN MODE  RESTRICTED
---------- ------------------------------ ---------- ----------
         2 PDB$SEED                       READ ONLY  NO
         4 REFRESH_PDB                    READ WRITE NO
SQL> ! hostname
source
```

* 2º: Comprobamos que no hay otra PDB, solo está la PDB$SEED.
    

```plaintext
SQL> show pdbs

    CON_ID CON_NAME                       OPEN MODE  RESTRICTED
---------- ------------------------------ ---------- ----------
         2 PDB$SEED                       READ ONLY  NO
SQL> ! hostname
target
```

* 3º: Definir un **common user**, no **local user**. El usuario debe llamarse igual y debe tener la misma contraseña en origen como destino.
    

```plaintext
SQL> CREATE USER C##MANAGER IDENTIFIED BY "XXXXXX";
User created.
SQL> GRANT CREATE SESSION, RESOURCE, CREATE ANY TABLE, UNLIMITED TABLESPACE TO C##MANAGER CONTAINER=ALL;
Grant succeeded.
SQL> GRANT CREATE PLUGGABLE DATABASE TO C##MANAGER CONTAINER=ALL;
Grant succeeded.
SQL> GRANT SYSOPER TO C##MANAGER CONTAINER=ALL;
Grant succeeded.
```

* 4º: Definir los **DB Links**. Antes de definirlo, debemos modificar el *tnsnames* para incluir ambas cadenas de conexión.
    

Origen:

```plaintext
SQL> ! hostname
source

SQL> ! tail -8  $ORACLE_HOME/network/admin/tnsnames.ora
TARGET =
  (DESCRIPTION =
    (ADDRESS = (PROTOCOL = TCP)(HOST = XXXXXXXXXXXXXXXXXXXX)(PORT = 1521))
    (CONNECT_DATA =
      (SERVER = DEDICATED)
      (SERVICE_NAME = XXXXXXXXXXXXXXXXXXXX)
    )
  )
```

Destino:

```plaintext
SQL> ! hostname
target
SQL> ! tail -8  $ORACLE_HOME/network/admin/tnsnames.ora
SOURCE =
  (DESCRIPTION =
    (ADDRESS = (PROTOCOL = TCP)(HOST = XXXXXXXXXXXXXXXXXXXX)(PORT = 1521))
    (CONNECT_DATA =
      (SERVER = DEDICATED)
      (SERVICE_NAME = XXXXXXXXXXXXXXXXXXXX)
    )
  )
```

Una vez que tenemos modificado el **tnsnames**, podemos definir el DB Link en **target** y en **source**.

```plaintext
SQL> CREATE DATABASE LINK DB_Source CONNECT TO C##MANAGER IDENTIFIED BY "XXXXXXXXX" USING 'SOURCE';
Database link created.
SQL> Select * From Dual@DB_Source;
D
-
X
```

Una vez que hemos comprobado que el DB funciona correctamente, ya podemos definir nuestra PDB.

La PDB en origen no contiene nada de información ahora mismo, así que vamos a definir algo en ella antes de clonarla.

```plaintext
SQL> alter session set container=REFRESH_PDB;
Session altered.
SQL> CREATE TABLE C##MANAGER.COPY_NUMERICOS AS 
     SELECT ROWNUM NUM 
       FROM DUAL 
    CONNECT BY ROWNUM <= 1000000;
Table created.
```

* 5º: Procedemos a clonar nuestra PDB usando external store:
    

```plaintext
SQL> CREATE PLUGGABLE DATABASE REFRESH_PDB FROM REFRESH_PDB@DB_Source REFRESH MODE MANUAL keystore identified by external store;

Pluggable database created.
```

Si nos fijamos en la sentencia que hemos ejecutado, hemos indicado **REFRESH MODE MANUAL**.

Cuando definimos la PDB como **REFRESH MODE MANUAL**, la PDB no se actualiza de manera automática, en cambio si la definimos **REFRESH MODE EVERY &lt;min&gt;**, la PDB sí se actualiza de manera automática.

El estado de la PDB que nos marca *DBA\_PDBs* es **REFRESHING**.

```plaintext
SQL> select con_id, pdb_name, status, refresh_mode, refresh_interval from dba_pdbs where pdb_name='REFRESH_PDB';

    CON_ID PDB_NAME             STATUS               REFRESH_MODE         REFRESH_INTERVAL
---------- -------------------- -------------------- -------------------- ----------------
         3 REFRESH_PDB          REFRESHING           MANUAL
```

Abrimos las PDB en modo lectura y consultamos si la tabla se encuentra en la PDB

```plaintext
SQL> ALTER SESSION SET CONTAINER=REFRESH_PDB;
Session altered.
SQL> ALTER PLUGGABLE DATABASE OPEN READ ONLY;
Pluggable database altered.
SQL> SELECT COUNT(*) FROM C##MANAGER.COPY_NUMERICOS;

  COUNT(*)
----------
   1000000
```

Volvemos a insertar registros en la tabla y refrescamos de nuevo la PDB.

```plaintext
 SQL> ALTER PLUGGABLE DATABASE CLOSE IMMEDIATE;

Pluggable database altered.

SQL> ALTER PLUGGABLE DATABASE REFRESH;

Pluggable database altered.

SQL> ALTER PLUGGABLE DATABASE OPEN READ ONLY;

Pluggable database altered.

SQL>  SELECT COUNT(*) FROM C##MANAGER.COPY_NUMERICOS;

  COUNT(*)
----------
   2000000
```

Perfecto, tenemos ambas PDBs sincronizadas.

Como último paso, podemos hacer dos cosas:

* **Finalizar**, es decir, que pase de **refreshable clone** a **regular PDB**:
    

```plaintext
SQL> ALTER PLUGGABLE DATABASE CLOSE IMMEDIATE;
Pluggable database altered.
SQL>  alter pluggable database refresh mode none;
Pluggable database altered.
SQL> ALTER PLUGGABLE DATABASE OPEN;
Pluggable database altered.

SQL> select con_id, pdb_name, status, refresh_mode, refresh_interval 
     from dba_pdbs where pdb_name='REFRESH_PDB';

    CON_ID PDB_NAME             STATUS               REFRESH_MODE         REFRESH_INTERVAL
---------- -------------------- -------------------- -------------------- ----------------
         3 REFRESH_PDB          NORMAL               NONE
```

* **Switch the roles:** Nuestra PDB de *source* pasará de **NORMAL** a **REFRESHING** y la PDB de *target* de **REFRESHING** a **NORMAL**:
    
    Origen:
    
    ```plaintext
    SQL> col pdb_name format a15
    SQL>  set linesize 1000
    SQL> select con_id, pdb_name, status, refresh_mode, refresh_interval from dba_pdbs where pdb_name='REFRESH_PDB';
    
        CON_ID PDB_NAME        STATUS     REFRES REFRESH_INTERVAL
    ---------- --------------- ---------- ------ ----------------
             4 REFRESH_PDB     NORMAL     NONE
    
    SQL> ALTER SESSION SET CONTAINER = REFRESH_PDB;                                                                 
    
    Session altered.
    
    SQL>  ALTER PLUGGABLE DATABASE REFRESH MODE MANUAL FROM REFRESH_PDB@DB_Target SWITCHOVER;
    
    Pluggable database altered.
    
    SQL> alter pluggable database open read only;
    
    Pluggable database altered.
    
    SQL> select con_id, pdb_name, status, refresh_mode, refresh_interval from dba_pdbs where pdb_name='REFRESH_PDB';
    
        CON_ID PDB_NAME        STATUS     REFRES REFRESH_INTERVAL
    ---------- --------------- ---------- ------ ----------------
             4 REFRESH_PDB     REFRESHING MANUAL
    ```
    
    Destino:
    
    ```plaintext
    SQL> r
      1* select con_id, pdb_name, status, refresh_mode, refresh_interval from dba_pdbs where pdb_name='REFRESH_PDB'
    
        CON_ID PDB_NAME        STATUS     REFRES REFRESH_INTERVAL
    ---------- --------------- ---------- ------ ----------------
             3 REFRESH_PDB     REFRESHING MANUAL
    
    SQL> alter pluggable database refresh_pdb open read only;
    
    Pluggable database altered.
    
    SQL> select con_id, pdb_name, status, refresh_mode, refresh_interval from dba_pdbs where pdb_name='REFRESH_PDB';
    
        CON_ID PDB_NAME        STATUS     REFRES REFRESH_INTERVAL
    ---------- --------------- ---------- ------ ----------------
             3 REFRESH_PDB     NORMAL     NONE
    ```
    
    Así de sencillo podemos cambiar los roles.
    

Espero que os guste. ¡Nos vemos en el próximo artículo!
