Part 3 - 12c Database and WLS - Multi Tenant Database (CDB/PDB)
By Steve Felts-Oracle on Sep 05, 2013
I introduced WLS support for 12c database at https://blogs.oracle.com/WebLogicServer/entry/part_1_12c_database_and and the Application Continuity feature at https://blogs.oracle.com/WebLogicServer/entry/part_2_12c_database_and .
One of the biggest new features in the 12c database is officially called the Oracle Multitenant option. I'm going to point out what I think are some of the highlights here and eventually get down into some WLS sample code. See http://docs.oracle.com/cd/E16655_01/server.121/e17636/part_cdb.htm#BGBIDDFD for the Oracle Database Administration documentation for this feature. Technical folks, administrators and programmers, will call this feature "CDB/PDB" after the Container Database and Pluggable Databases that are used to implement it. As the names imply, you have a CDB to contain a collection of PDB's. If you are an administrator, you can appreciate the ability to create, manage, monitor, backup, patch, tune, etc. one entity instead of a bunch of them. As a programmer, its great that you can connect to your PDB and it looks and behaves just like a non-PDB. All that you need to know is the host, port, and service name just like the non-PDB. Of course, the service name needs to be unique in your environment so that you get to the right PDB in the right CDB.
As you might expect, there needs to be a container at the top to hold all of the PDB's - it's called the CDB$ROOT. There also needs to be some users in charge of the PDB's. These users are called "common users" and the names must begin with "C##". A common user is created in the root (it fails within a PDB) and exist in all PDB's. "Local users" are created within individual PDB's and behave like users in non-PDB's. When you are doing administration from tools like sqlplus or sqldeveloper, you connect to the database in the root and can switch to a PDB by using something like "alter session set container = PDB1" and then "alter session set container = CDB$ROOT" to get back to the root. There are new views to keep track of the CDB/PDB information - use "select pdb from cdb_services where pdb is not null" to see what PDB's exist. Some operations can only be done at the root level. For example, Database Resident Connection Pooling (DRCP), another new 12c feature, can only be started at the root. A PDB is managed pretty much like a non-PDB with startup and shutdown. Each PDB has an administrative database service that you can't configure (Enterprise Manager needs something consistent to manage the PDB) and you can create additional database services with your own choice of attributes. You can use the dba_services table within a PDB to see just the services for that PDB.
So how do you use this? The easy way to use this is for improving density and scalability on the data tier. You can move multiple standalone databases into a single container database with individual PDB's corresponding to each standalone database. On the WebLogic Server side, you can still have a data source defined for each of these PDB's, just as you have today.
Feeling more ambitious? You can share a single data source across multiple PDB's. To do that, you need to get a connection and switch to the PDB that you want to work on by executing the SQL statement "ALTER SESSION SET CONTAINER = pdbname". You might be wondering if any state is leaked from one PDB to another by doing this. Under the covers, the Oracle database server tells the Oracle driver that the PDB has been switched so driver connection state can be cleaned up. Then the driver tells the WLS data source that the PDB has been switched so that the WLS connection state can be cleaned up. Although general use of a PDB is transparent to WLS so that it can be used with versions starting with WLS release 10.3.6, PDB SET CONTAINER isn't supported until WLS release 12.1.2.
Switching PDB's is not a cheap operation so you should minimize doing this. To minimize the overhead, you really want to keep track of what PDB is associated with each connection. WLS data source has a mechanism for associating labels with connections that's ideal for this purpose. See http://docs.oracle.com/middleware/1212/wls/JDBCA/ds_labeling.htm#BCGFADIH for the connection labeling documentation.
Take a look at the sample code at this source code link (the .txt file is actually a .java file). It's written up as a servlet (don't get caught up in those details). It assumes that there is a 12c container database with PDB1 and PDB2 that has been configured as a generic data source with a JNDI name "ds0". When it first gets the data source, a labeling callback is created and registered (we only want to do this once). The program gets connections on each PDB. The first time it gets a connection on a PDB, it needs to do a switch; the next time, it can reuse the same connection. The labeling getConnection API is used; it takes a Properties object and the label name is "TENANT". Looking at the callback, if the label properties match then 0 is returned, otherwise a non-zero value is returned (some debugging information is printed so it's possible to watch the matching process). The key work is in the configure method, which is called when the tenant label doesn't match. In that case, the SET CONTAINER is done using the tenant label value and the label properties are reset.
Climbing back out of the code, the Oracle Multitenant option can be a big win on the database server side immediately with no change on the WLS side except maybe for the URL in the JDBC descriptor. Longer term, I believe applications will want higher density on the mid-tier and start to collapse the number of data sources. Along the same lines of improving density but not for multiple tenants, you can also move your SALES and CRM databases into PDB's within a container, and merge the two data sources into a single data source using the methods described above. It will be interesting to see how customers leverage the power of this new feature.