Oracle Application Server Containers for J2EE Services Guide 10g (9.0.4) Part Number B10326-01 |
|
This chapter describes how to configure and use data sources in your Oracle Application Server Containers for J2EE (OC4J) application. A data source is a vendor-independent encapsulation of a connection to a database server. A data source instantiates an object that implements the javax.sql.DataSource
interface.
This chapter covers the following topics:
A data source is a Java object that implements the javax.sql.DataSource
interface. Data sources offer a portable, vendor-independent method for creating JDBC connections. Data sources are factories that return JDBC connections to a database. J2EE applications use JNDI to look up DataSource
objects. Each JDBC 2.0 driver provides its own implementation of a DataSource
object, which can be bound into the JNDI name space. After this data source object has been bound, you can retrieve it through a JNDI lookup. Because data sources are vendor-independent, we recommend that J2EE applications retrieve connections to data servers using data sources.
In OC4J, Data Sources are classified as follows:
Figure 4-1 summarizes the key differences between each data source type.
Note that if you access a non-emulated data source by the ejb-location
, then you are using the OC4J pool and cache. If you use OracleConnectionCacheImpl
, you have access to both OC4J and Oracle JDBC pool and cache.
Figure 4-2 summarizes the decision making tree that should guide you when choosing a data source type.
The following sections describe each data source type in detail.
Emulated data sources are data sources that emulate the XA protocol for JTA transactions. Emulated data sources offer OC4J caching, pooling and Oracle JDBC extensions for Oracle data sources. Historically, emulated data sources were necessary because many JDBC drivers did not provide XA capabilities. Today even though most JDBC drivers do provide XA capabilities, there are still cases where emulated XA is preferred (such as transactions that don't require two-phase commit.)
Connections that are obtained from emulated data sources are extremely fast, because the connections emulate the XA API without providing full XA global transactional support. In particular, emulated data sources do not support two-phase commit. We recommend that you use emulated data sources for local transactions or when your application uses global transactions without requiring two-phase commit (For information on the limitations of two-phase commit, see Chapter 7, "Java Transaction API").
The following is a data-sources.xml
configuration entry for an emulated data source:
<data-source class="com.evermind.sql.DriverManagerDataSource" name="OracleDS" location="jdbc/OracleCoreDS" xa-location="OracleDS" ejb-location="jdbc/OracleDS" connection-driver="oracle.jdbc.driver.OracleDriver" username="scott" password="tiger" url="jdbc:oracle:thin:@localhost:5521:oracle" inactivity-timeout="30" />
When defining an emulated data source in data-sources.xml you must provide values for the location
, ejb-location
, and xa-location
attributes. However, when looking up an emulated data source via JNDI you should look it up by the value that was specified with the ejb-location
attribute. For example:
Context ic = new InitialContext(); DataSource ds = (DataSource) ic.lookup("jdbc/OracleDS"); // This lookup could also be done as // DataSource ds = (DataSource) ic.lookup("java:comp/env/jdbc/OracleDS"); Connection con = ds.getConnection();
This connection opens a database session for scott/tiger
.
If you use an emulated data source inside a global transaction you must exercise caution. Because the XAResource
that you enlist with the transaction manager is an emulated XAResource
, the transaction will not be a true two-phase commit transaction. If you want true two-phase commit semantics in global transactions, then you must use a non-emulated data source. (For information on the limitations of two-phase commit, see Chapter 7, "Java Transaction API".)
Retrieving multiple connections from a data source using the same user name and password within a single global transaction causes the logical connections to share a single physical connection. The following code shows two connections--conn1
and conn2
--that share a single physical connection. They are both retrieved from the same data source object. They also authenticate with the same user name and password.
Context ic = new InitialContext(); DataSource ds = (DataSource) ic.lookup("jdbc/OracleCMTDS1"); Connection conn1 = ds.getConnection("scott", "tiger"); Connection conn2 = ds.getConnection("scott", "tiger");
Non-emulated data sources provide full (non-emulated) JTA services, including two-phase commit capabilities for global transactions. Non-emulated data sources offer pooling, caching, distributed transactions capabilities, and vendor JDBC extensions (currently only Oracle JDBC extensions).
For information on the limitations of two-phase commit, see Chapter 7, "Java Transaction API".
We recommend that you use these data sources for distributed database communications, recovery, and reliability. Non-emulated data sources share physical connections for logical connections to the same database for the same user.
The following is a data-sources.xml
configuration entry for a non-emulated data source:
<data-source class="com.evermind.sql.OrionCMTDataSource" location="jdbc/OracleDS" connection-driver="oracle.jdbc.driver.OracleDriver" username="scott" password="tiger" url="jdbc:oracle:thin:@localhost:5521:oracle </data-source>
JNDI lookups should be done using the value of the location
attribute.
Here are the expected attribute definitions:
location
is the JNDI name that this data source is bound to within the JNDI name space. Use location
in the JNDI lookup for retrieving this data source.
url
, username
, and password
identify the database and default user name and password to use when connections are retrieved with this data source.
class
defines what type of data source class to bind in the name space.
Native data sources are JDBC-vendor supplied implementations of the DataSource. They expose vendor's JDBC driver capabilities including caching, pooling and vendor specific extensions. One must exercise caution when using native data sources because OC4J cannot enlist them inside global transactions and they can be used by EJBs or other components requiring global transaction semantics.
Native data source implementations can be used directly without an emulator. OC4J supports the use of native data sources directly and benefits from their vendor-specific pooling, caching, extensions, and properties. However, native data sources do not provide JTA services (such as begin, commit, and rollback)
The following is a data-sources.xml
configuration entry for a native data source:
<data-source class="com.my.DataSourceImplementationClass" name="NativeDS" location="jdbc/NativeDS" username="user" password="pswd" url="jdbc:myDataSourceURL" </data-source>
JNDI lookups can only be performed via the value of the location
attribute.
A single application can use several different types of data sources.
If your application mixes data sources, be aware of the following issues:
You cannot enlist connections that are obtained from Native data sources in a JTA transaction.
To enlist multiple connections in a two-phase commit transaction, all the connections must use non-emulated data sources. (For information on the limitations of two-phase commit, see Chapter 7, "Java Transaction API".)
javax.transaction.UserTransaction
, all future transaction work must be performed through that object.
If you try to invoke the connection's rollback()
or commit()
methods, you will receive the SQLException "calling commit()
[or
rollback()] is not allowed on a container-managed transactions Connection
".
The following example explains what happens:
Context ic = new InitialContext(); DataSource ds = (DataSource) ic.lookup("JDBC/OracleCMTDS1"); // Using JTA DataSources Connection conn1 = ds.getConnection("scott", "tiger"); javax.transaction.UserTransaction ut = (javax.transaction.UserTransaction)ic.lookup("java:comp/UserTransaction"); ut.begin(); conn1.query(); conn1.commit(); // not allowed, returns error: calling commit[or rollback] is not allowed // on a container-managed transaction connection
You define OC4J data sources in an XML file known as data-sources.xml
.
The data-sources.xml file installed with OC4J includes predefined, default data sources that may be sufficient for your needs. If not, you must define your own.
Table 4-1 summarizes the configuration requirements for each type of data source.
Table 4-2 summarizes the characteristics for each type of data source.
To define a new data source object:
data-sources.xml
file (see "Configuration Files")
One main configuration file establishes data sources at the OC4J server level: J2EE_HOME/config/data-sources.xml
.
Each application also has a separate JNDI name space. The files web.xml
, ejb-jar.xml
, orion-ejb-jar.xml
, and orion-web.xml
contain entries that you can use to map application JNDI names to data sources, as the next section describes.
Your application can know about the data sources defined in this file only if the application.xml
file knows about it. The path
attribute in the <data-sources>
tag in the application.xml
file must contain the name and path to your data-sources.xml
file, as follows:
<data-sources path="data-sources.xml"/>
The path
attribute of the <data-sources>
tag contains a full path name for the data-sources.xml
file. The path can be absolute, or it can be relative to where the application.xml
is located. Both the application.xml
and data-sources.xml
files are located in the J2EE_HOME/config/application.xml
directory. Thus, the path contains only the name of the data-sources.xml
file.
Each application can define its own data-sources.xml
file in its EAR file. This is done by having the reference to the data-sources.xml
file in the orion-application.xml
file packaged in the EAR file.
To configure this:
data-sources.xml
and orion-application.xml
file in your application's META-INF directory.
the orion-application.xml
file to add a <data-sources>
tag as follows:
<orion-application> <data-sources path="./data-sources.xml"/> </orion-application>
A data source can take many attributes. Some are required, but most are optional. The required attributes are marked below. The attributes are specified in a <data-source>
tag.
Table 4-3 lists the attributes and their meanings.
In addition to the data-source
attributes described in Table 4-3, you can also add property
sub-nodes to a data-source
. These are used to configure generic properties on a data source object (following Java Bean conventions.) A property
node has a name
and value
attribute used to specify the name and value of a data source bean property.
All OC4J data source attributes are applicable to the infrastructure database as well. For more information on the infrastructure database, see Oracle High Availability Architecture and Best Practices.)
Attribute Name | Meaning of Value | Default Value |
---|---|---|
|
Names the class that implements the data source. For non-emulated, this can be |
N/A |
|
The JNDI logical name for the data source object. OC4J binds the class instance into the application JNDI name space with this name. This JNDI lookup name is used for non-emulated data sources. See also Table 4-1, "Data Source Configuration Summary" |
N/A |
|
The data source name. Must be unique within the application. |
None |
|
The JDBC-driver class name for this data source, some data sources that deal with |
None |
|
Default user name used when getting data source connections. |
None |
|
Default password used when getting data source connections. See also "Password Indirection" |
None |
|
The URL for database connections. |
None |
|
The logical name of an XA data source.Emulated data sources only. See also Table 4-1, "Data Source Configuration Summary" |
None |
|
Use this for JTA single-phase commit transactions or looking up emulated data sources. If you use it to retrieve the data source, you can map the returned connection to |
None |
stmt-cache-size |
A performance tuning attribute set to a non-zero value to enable JDBC statement caching and to define the maximum number of statements cached. Enabled to avoid the overhead of repeated cursor creation and statement parsing and creation. Applicable only for emulated data sources where |
0 (disabled) |
|
Time (in seconds) to cache an unused connection before closing it. |
60 seconds |
|
Time (in seconds) to wait before retrying a failed connection attempt. |
1 second |
|
The maximum number of open connections for a pooled data source. |
Depends on the data source type |
|
The minimum number of open connections for a pooled data source. OC4J does not open these connections until the |
0 |
|
The number of seconds to wait for a free connection if the pool has reached |
60 |
|
The number of times to retry making a connection. Useful when the network or environment is unstable for any reason that makes connection attempts fail. |
3 |
|
This optional attribute specifies the threshold (in seconds) for when a cleanup of available connections will occur. For example, if a connection is bad, the available connections are cleaned up. If another connection is bad (that is, it throws an exception), and if the threshold time has elapsed, then the available connections are cleaned up again. If the threshold time has not elapsed, then the available connections are not cleaned up again. |
30 |
|
This optional attribute specifies whether or not the system is enabled for Real Application Clusters (RAC). For information on using this flag with an infrastructure database, see Oracle High Availability Architecture and Best Practices.) and with a user database, see "Using DataDirect JDBC Drivers" and "High Availability Support for Data Sources"
If the data source points to an RAC database, you should set this property to |
false |
schema |
This optional attribute specifies the |
None |
The following example shows the use of the clean-available-connections-threshold and rac-enabled attributes:
<data-source class="com.evermind.sql.OrionCMTDataSource" name="NEDS1" location="jdbc/NELoc1" connection-driver="oracle.jdbc.driver.OracleDriver" min-connections="5" max-connections="10" clean-available-connections-threshold="35" rac-enabled="true" username="scott" password="tiger" url="jdbc:oracle:thin:@jsnyder-us:1521:jsnyder" inactivity-timeout="30" max-connect-attempts="5" />
For each data source you define, OC4J may create and bind within JNDI up to four data sources: one each for location
, ejb-location
, xa-location
, and pool-location
. The type of data source selected is determined by the values associated with data-sources.xml
attributes class
, connection-driver
, and url
and the JNDI context in which the data source object is created and looked-up. For more information about data source types, see "Types of Data Sources".
You can define any type of data source with the Oracle Enterprise Manager.
How to define data sources is explained in detail in the Data Sources Primer chapter of the Oracle Application Server Containers for J2EE User's Guide.
See the Oracle Application Server Containers for J2EE User's Guide to find out how to use the Administrative tools. See the Oracle Enterprise Manager Administrator's Guide for Oracle Enterprise Manager information.
This section provides a brief overview of these procedures.
Use the Oracle Enterprise Manager and drill down to the Data Source page. OC4J parses the data-sources.xml
file when it starts, instantiates data source objects, and binds them into the server JNDI name space. When you add a new data source specification, you must restart the OC4J server to make the new data source available for lookup.
To define emulated data sources, follow the same steps as for defining non-emulated data sources, until the step in which you define the JNDI location. There the screen shot shows one field, Location, to be filled out. That is for a non-emulated data source. For an emulated data source, fill out the three fields Location, XA-Location, and EJB-Location.
The $J2EE_HOME/config/data-sources.xml
file is preinstalled with a default data source. For most uses, this default is all you need. However, you can also add your own customized data source definitions.
The default data source is an emulated data source.
For more information about data source types, see "Types of Data Sources".
The following is a simple emulated data source definition that you can modify for most applications:
<data-source class="com.evermind.sql.DriverManagerDataSource" name="OracleDS" location="jdbc/OracleCoreDS" xa-location="OracleDS" ejb-location="jdbc/OracleDS" connection-driver="oracle.jdbc.driver.OracleDriver" username="scott" password="tiger" url="jdbc:oracle:thin:@localhost:5521:oracle" inactivity-timeout="30" />
See "Data Source Attributes" for details on all data source attributes.
The data-sources.xml
file requires passwords for authentication. Embedding these passwords into deployment and configuration files poses a security risk, especially if the permissions on this file allows it to be read by any user. To avoid this problem, OC4J supports password indirection.
An indirect password is made up of a special indirection symbol (->
) and a user name (or user name and realm). When OC4J encounters an indirect password, it uses its privileged access to retrieve the password associated with the specified user from the security store provided by a user manager.
For more information on creating users and passwords and working with a user manager, see the section on password management in the Oracle Application Server Containers for J2EE Security Guide.
For example, the sample code under "Emulated Data Sources" contains the following line:
password="tiger"
You could replace that with the indirection symbol (->
) and a user name (scott
) as follows:
password="->scott"
This assumes that a user named scott
with the password tiger
has been created in a user manager.
Because OC4J has privileged access to the security store, it can retrieve the password (tiger
) associated with this user (scott
).
There are two ways to configure password indirection:
To configure an indirect password using the Oracle Enterprise Manager:
The Oracle Enterprise Manager for Oracle Application Server home page is displayed.
A list of data sources is displayed.
The Edit Data Source page is displayed as shown in Figure 4-3.
To configure an indirect password for a data source manually:
For example: <data-source password="->Scott">
This will cause the User Manager to look up the user name "Scott" and use the password stored for that user.
The data source identifies a database instance. The data source schema
attribute allows you to associate a data source with a database-schema.xml
file that you can customize for its particular database.
When using CMP, the container is responsible for creating the database schema necessary to persist a bean. Associating a data source with a database-schema.xml
file allows you to influence what SQL is ultimately generated by the container. This can help you solve problems such as accommodating additional data types supported in your application (like java.math.BigDecimal
) but not in your database.
A database-schema.xml
file contains a database-schema
element as shown in Example 4-1. It is made up of the attributes listed in Table 4-4.
<database-schema case-sensitive="true" max-table-name-length="30" name="MyDatabase" not-null="not null" null="null" primary-key="primary key"> <type-mapping type="java.math.BigDecimal" name="number(20,8)" /> <disallowed-field name="order" /> </database-schema>
The database-schema
element may contain any number of the following sub-elements:
This sub-element is used to map a Java type to the corresponding type appropriate for this database instance. It contains two attributes:
This sub-element identifies a name that must not be used because it is a reserved word in this database instance. It contains one attribute:
This example shows how to map a data type supported in your application (java.math.BigDecimal
) to a data type supported by the underlying database.
java.math.BigDecimal
in your database-schemas/oracle.xml
file as follows:
<type-mapping type="java.math.BigDecimal" name="number(20,8)" />
data-source
as follows:
<data-source class="com.evermind.sql.DriverManagerDataSource" name="OracleDS" ejb-location="jdbc/OracleDS" schema="database-schemas/oracle.xml" connection-driver="oracle.jdbc.driver.OracleDriver" username="scott" password="tiger" url="jdbc:oracle:thin:@localhost:1521:DEBU" clean-available-connections-threshold="30" rac-enabled="false" inactivity-timeout="30" />
data-source
for your ejbs:
<orion-ejb-jar> <enterprise-beans> <entity-deployment name="BigDecimalTest" data-source="jdbc/OracleDS" /> </enterprise-beans>
The following sections describe how to use data sources in your application can:
For information on data source methods, refer to your J2EE API documentation.
When the OC4J server starts, the data sources in the data-sources.xml
file in the j2ee/home/config
directory are added to the OC4J JNDI tree. When you look up a data source using JNDI, specify the JNDI lookup as follows:
DataSource ds = ic.lookup("jdbc/OracleCMTDS1");
The OC4J server looks in its own internal JNDI tree for this data source.
However, we recommend--and it is much more portable--for an application to look up a data source in the application JNDI tree, using the portable java:comp/env
mechanism. Place an entry pointing to the data source in the application web.xml
or ejb-jar.xml
files, using the <resource-ref>
tag. For example:
<resource-ref> <res-ref-name>jdbc/OracleDS</res-ref-name> <res-type>javax.sql.DataSource</res-type> <res-auth>Container</res-auth> </resource-ref>
where <res-ref-name>
can be one of the following:
jdbc/OracleDS
--that is defined in the data-sources.xml
file. In this situation, no mapping is necessary. The preceding code example demonstrates this. The <res-ref-name>
is the same as the JNDI name bound in the data-sources.xml
file.
Retrieve this data source without using java:comp/env
, as shown by the following JNDI lookup:
InitialContext ic = new InitialContext(); DataSource ds = ic.lookup("jdbc/OracleDS");
orion-web.xml
or orion-ejb-jar.xml
. The OC4J-specific XML files then define a mapping from the logical name in the web.xml
or ejb-jar.xml
file to the actual JNDI name that is defined in the data-sources.xml
file.
The following code demonstrates the second of the two preceding options. If you want to choose a logical name of "jdbc/OracleMappedDS
" to be used within your code for the JNDI retrieval, then place the following in your web.xml
or ejb-jar.xml
files:
<resource-ref> <res-ref-name>jdbc/OracleMappedDS</res-ref-name> <res-type>javax.sql.DataSource</res-type> <res-auth>Container</res-auth> </resource-ref>
For the actual JNDI name to be found, you must have a <resource-ref-mapping>
element that maps the jdbc/OracleMappedDS
to the actual JNDI name in the data-sources.xml
file. If you are using the default emulated data source, then the ejb-location
will be defined with jdbc/OracleDS
as the actual JNDI name. For example:
<resource-ref-mapping name="jdbc/OracleMappedDS" location="jdbc/OracleDS" />
You can then look up the data source in the application JNDI name space using the Java statements:
InitialContext ic = new InitialContext(); DataSource ds = ic.lookup("jdbc/OracleMappedDS");
One way to modify data in your database is to retrieve a JDBC connection and use JDBC or SQLJ statements. We recommend that you, instead, use data source objects in your JDBC operations.
Perform the following steps to modify data within your database:
DataSource
object through a JNDI lookup on the data source definition in the data-sources.xml
file.
The lookup is performed on the logical name of the default data source, which is an emulated data source that is defined in the ejb-location
tag in the data-sources.xml
file.
You must always cast or narrow the object that JNDI returns to the DataSource
, because the JNDI lookup()
method returns a Java object
.
DataSource
object.
After you have the connection, you can construct and execute JDBC statements against this database that is specified by the data source.
The following code represents the preceding steps:
Context ic = new InitialContext(); DataSource ds = (DataSource) ic.lookup("jdbc/OracleDS"); Connection conn = ds.getConnection();
Use the following methods of the DataSource
object in your application code to retrieve a connection to your database:
getConnection();
The user name and password are those that are defined in the data source definition.
getConnection(String username, String password);
This user name and password overrides the user name and password that are defined in the data source definition.
If the data source refers to an Oracle database, then you can cast the connection object that is returned on the getConnection
method to oracle.jdbc.OracleConnection
and use all the Oracle extensions. See "Using Oracle JDBC Extensions" for details.
The following example illustrates this:
oracle.jdbc.OracleConnection conn =
(oracle.jdbc.OracleConnection) ds.getConnection();
After you retrieve a connection, you can execute SQL statements against the database through either SQLJ or JDBC.
Refer to Retrieving Connections with a Non-emulated Data Source for information on handling common connection retrieval error conditions.
The physical behavior of a non-emulated data source object changes depending on whether you retrieve a connection from the data source that is outside of or within a global transaction. The following sections discuss these differences:
If you retrieve a connection from a non-emulated data source and you are not involved in a global transaction, then every getConnection
method returns a logical handle. When the connection is used for work, a physical connection is created for each connection that is created. Thus, if you create two connections outside of a global transaction, then both connections use a separate physical connection. When you close each connection, it is returned to a pool to be used by the next connection retrieval.
If you retrieve a connection from a non-emulated data source and you are involved in a global JTA transaction, all physical connections that are retrieved from the same DataSource
object by the same user within the transaction share the same physical connection.
For example, if you start a transaction and retrieve two connections from the jdbc/OracleCMTDS1
DataSource
with the scott
user, then both connections share the physical connection. In the following example, both conn1
and conn2
share the same physical connection.
Context ic = new InitialContext(); DataSource ds = (DataSource) ic.lookup("jdbc/OracleCMTDS1"); txn.begin(); //start txn Connection conn1 = ds.getConnection("scott", "tiger"); Connection conn2 = ds.getConnection("scott", "tiger");
However, separate physical connections are retrieved for connections that are retrieved from separate DataSource
objects. The following example shows both conn1
and conn2
are retrieved from different DataSource
objects: jdbc/OracleCMTDS1
and jdbc/OracleCMTDS2
. Both conn1
and conn2
will exist upon a separate physical connection.
Context ic = new InitialContext(); DataSource ds1 = (DataSource) ic.lookup("jdbc/OracleCMTDS1"); DataSource ds2 = (DataSource) ic.lookup("jdbc/OracleCMTDS2"); txn.begin; //start txn Connection conn1 = ds1.getConnection(); Connection conn2 = ds2.getConnection();
The following mistakes can create an error condition:
When you retrieve a connection from a DataSource
object with a user name and password, this user name and password are used on all subsequent connection retrievals within the same transaction. This is true for all data source types.
For example, suppose an application retrieves a connection from the jdbc/OracleCMTDS1
data source with the scott
user name. When the application retrieves a second connection from the same data source with a different user name, such as adams
, the user name that is provided is ignored. Instead, the scott
user is used.
Context ic = new InitialContext(); DataSource ds = (DataSource) ic.lookup("jdbc/OracleCMTDS1"); txn.begin(); //start txn Connection conn1 = ds.getConnection("scott", "tiger"); //uses scott/tiger Connection conn2 = ds.getConnection("adams", "woods"); //uses scott/tiger also
Thus, you cannot authenticate using two different users to the same data source. If you try to access the tables as "adams/woods
", you enter into an error condition.
If you are using the OCI JDBC driver, ensure that you have configured it according to the recommendations in "Using the OCI JDBC Drivers".
The Oracle two-phase commit coordinator is a DTC (distributed transaction coordinator) engine that performs two phase commits with appropriate recovery. The two-phase commit engine is responsible for ensuring that when the transaction ends, all changes to all databases are either totally committed or fully rolled back. The two-phase commit engine can be one of the databases that participates in the global transaction, or it can be a separate database. If multiple databases or multiple sessions in the same database participate in a transaction, then you must specify a two-phase commit coordinator. Otherwise, you cannot commit the transaction.
Specify a commit coordinator in one of the following ways:
application.xml
in the J2EE_HOME/config
directory.
orion-application.xml
file.
For example:
<commit-coordinator> <commit-class class="com.evermind.server.OracleTwoPhaseCommitDriver" /> <property name="datasource" value="jdbc/OracleCommitDS" /> <property name="username" value="system" /> <property name="password" value="manager" /> </commit-coordinator>
Note:
The password attribute of the |
Note: Two-phase commit may only be configured for non-emulated data sources. For more information on data source types, see "Types of Data Sources". |
If you specify a user name and password in the global application.xml
file, then these values override the values in the datasource.xml
file. If these values are null, then the user name and password in the datasource.xml
file are used to connect to the commit coordinator.
The user name and password used to connect to the commit coordinator (for example, System) must have "force any transaction" privilege. By default, during installation, the commit-coordinator
is specified in the global application.xml
file with the user name and password set as null.
Each data source that is participating in a two-phase commit should specify dblink
information in the OrionCMTDatasource
data source. file This dblink
should be the name of the dblink
that was created in the commit coordinator database to connect to this database.
For example, if db1
is the database for the commit coordinator and db2
and db3
are participating in the global transactions, then you create link2
and link3
in the db1
database as shown in the following example.
connect commit_user/commit_user create database link link2 using "inst1_db2"; // link from db1 to db2 create database link link3 using "inst1_db3"; // link from db1 to db3;
Next, define a data source called jdbc/OracleCommitDS
in the application.xml
file:
<data-source class="com.evermind.sql.OrionCMTDataSource" name="OracleCommitDS" location="jdbc/OracleCommitDS" connection-driver="oracle.jdbc.driver.OracleDriver" username="system" password="manager" url="jdbc:oracle:thin:@localhost:5521:db1" inactivity-timeout="30"/>
Here is the data source description of db2
that participates in the global transaction. Note that link2
, which was created in db1
, is specified as a property here:
<data-source class="com.evermind.sql.OrionCMTDataSource" name="OracleDB2" location="jdbc/OracleDB2" connection-driver="oracle.jdbc.driver.OracleDriver" username="scott" password="tiger" url="jdbc:oracle:thin:@localhost:5521:db2" inactivity-timeout="30"> <property name="dblink" value="LINK2.REGRESS.RDBMS.EXAMPLE.COM"/> </data-source>
Here is the data source description of db3
that participates in the global transaction. Note that link3
, which is created in db1
, is specified as a property here:
<data-source class="com.evermind.sql.OrionCMTDataSource" name="OracleDB3" location="jdbc/OracleDB3" connection-driver="oracle.jdbc.driver.OracleDriver" username="scott" password="tiger" url="jdbc:oracle:thin:@localhost:5521:db3" inactivity-timeout="30"> <property name="dblink" value="LINK3.REGRESS.RDBMS.EXAMPLE.COM"/> </data-source>
For information on the limitations of two-phase commit, see Chapter 7, "Java Transaction API".
To use Oracle JDBC extensions, cast the returned connection to oracle.jdbc.OracleConnection
, as follows:
Context ic = new InitialContext(); DataSource ds = (DataSource) ic.lookup("jdbc/OracleCMTDS1"); oracle.jdbc.OracleConnection conn =
(oracle.jdbc.OracleConnection) ds.getConnection();
You can use any of the Oracle extensions on the returned connection, conn
.
// you can create oracle.jdbc.* objects using this connection
oracle.jdbc.Statement orclStmt =
(oracle.jdbc.OracleStatement)conn.createStatement();
// assume table is varray_table
oracle.jdbc.OracleResultSet rs =
orclStmt.executeQuery("SELECT * FROM " + tableName);
while (rs.next())
{
oracle.sql.ARRAY array = rs.getARRAY(1);
...
}
You can define the database caching scheme to use within the data source definition. There are three types of caching schemes: DYNAMIC_SCHEME
, FIXED_WAIT_SCHEME
, and FIXED_RETURN_NULL_SCHEME
. The Connection Pooling and Caching chapter of the Oracle9i JDBC Developer's Guide and Reference, found on OTN at the following location, describe these schemes:
http://st-doc.us.oracle.com/9.0/920/java.920/a96654/toc.htm
To specify a caching scheme, specify an integer or string value for a <property>
element named cacheScheme
. Table 4-5 shows the supported values.
Value | Cache Scheme |
---|---|
1 |
|
2 |
|
3 |
|
The following example is a data source using the DYNAMIC_SCHEME
.
<data-source
class="oracle.jdbc.pool.OracleConnectionCacheImpl"
name="OracleDS"
location="jdbc/pool/OracleCache"
connection-driver="oracle.jdbc.driver.OracleDriver"
username="scott"
password="tiger"
url="jdbc:oracle:thin:@hostname:TTC port number:DB SID
inactivity-timeout="30">
<property name="cacheScheme" value="1" />
</data-source>
In the preceding, for the <property name>
element, you could also specify value="DYNAMIC_SCHEME"
.
When you create a data source in data-sources.xml
, be aware of the following: when class
is set to oracle.jdbc.pool.OracleConnectionCacheImpl
, the ejb-location
, xa-location
, and pooled-location
attributes must not be specified. Only the location
attribute should be specified. Accessing the data source using any other attribute with JNDI will cause unpredictable cleanup of cached connections in the event that the database goes down.
The examples of Oracle data source definitions in this chapter use the Oracle JDBC thin driver. However, you can use the Oracle JDBC OCI (thick) driver as well. Do the following before you start the OC4J server:
ORACLE_HOME
variable.
LD_LIBRARY_PATH
(or the equivalent environment variable for your OS) to $ORACLE_HOME/lib
.
TNS_ADMIN
to a valid Oracle administration directory with a valid tnsnames.ora
file.
The URL to use in the url
attribute of the <data-source>
element definition can have any of these forms:
jdbc:oracle:oci8:@
This TNS entry is for a database on the same system as the client, and the client connects to the database in IPC mode.
jdbc:oracle:oci8:@
TNS service name
The TNS service name is an entry in the instance tnsnames.ora
file.
jdbc:oracle:oci8:@
full_TNS_listener_description
For more TNS information, see the Oracle Net Administrator's Guide.
When your application must connect to heterogeneous databases, use DataDirect JDBC drivers. DataDirect JDBC drivers are not meant to be used with an Oracle database but for connecting to non-Oracle databases, such as Microsoft, SQLServer, Sybase, and DB2. If you want to use DataDirect drivers with OC4J, then add corresponding entries for each database in the data-sources.xml
file.
Install the DataDirect JDBC drivers as described in the DataDirect Connect for JDBC User's Guide and Reference.
Once you have installed the drivers, follow these instructions to set them up.
DDJD_INSTALL
.
OC4J_INSTALL
/j2ee/
INSTANCE_NAME
/applib
if it does not already exist.
DDJD_INSTALL
/lib
to the OC4J_INSTALL
/j2ee/
INSTANCE_NAME
/applib
directory.
application.xml
contains a library entry that references the j2ee/home/applib
location, as follows:
<library path="../../INSTANCE_NAME/applib" />
data-source.xml
as described in "Example DataDirect Data Source Entries".
This section shows an example data source entry for each of the following non-Oracle databases:
You can also use vendor-specific data sources in the class attribute directly. That is, it is not necessary to use an OC4J-specific data source in the class attribute.
For more detailed information, refer to the DataDirect Connect for JDBC User's Guide and Reference.
The following is an example of a data source entry for SQLServer.
<data-source class="com.evermind.sql.DriverManagerDataSource" name="MerantDS" location="jdbc/MerantCoreSSDS" xa-location="jdbc/xa/MerantSSXADS" ejb-location="jdbc/MerantSSDS" connection-driver="com.oracle.ias.jdbc.sqlserver.SQLServerDriver" username="test" password="secret" url="jdbc:sqlserver//hostname:port;User=test;Password=secret" inactivity-timeout="30" />
For a DB2 database, here is a data source configuration sample:
<data-source class="com.evermind.sql.DriverManagerDataSource" name="MerantDS" location="jdbc/MerantDB2DS" xa-location="jdbc/xa/MerantDB2XADS" ejb-location="jdbc/MerantDB2DS" connection-driver="com.oracle.ias.jdbc.db2.DB2Driver" username="test" password="secret" url="jdbc:db2://hostname:port;LocationName=jdbc;CollectionId=default;" inactivity-timeout="30" />
For a Sybase database, here is a data source configuration sample:
<data-source class="com.evermind.sql.DriverManagerDataSource" name="MerantDS" location="jdbc/MerantCoreSybaseDS" xa-location="jdbc/xa/MerantSybaseXADS" ejb-location="jdbc/MerantSybaseDS" connection-driver="com.oracle.ias.jdbc.sybase.SybaseDriver" username="test" password="secret" url="jdbc:sybase://hostname:port;User=test;Password=secret" inactivity-timeout="30" />
A high availability (HA) architecture must encompass redundancy across all components, achieve fast client failover for all types of outages, provide consistent high performance, and provide protection from user errors, corruptions, and site disasters, while being easy to deploy, manage, and scale.
The Oracle Maximum Availability Architecture (MAA) provides recommendations and configuration instructions to help you choose and implement an Oracle platform availability architecture that best fits your availability requirements.
The main MAA recommendations are:
For more information about MAA, see http://otn.oracle.com/deploy/availability/htdocs/maa.htm.
Oracle Data Guard is software integrated with the Oracle database that maintains a real-time copy of a production database, called a standby database, and keeps this instance synchronized with its redundant mate. Oracle Data Guard manages the two databases by providing log transport services, managed recovery, switchover, and failover features.
RAC uses two or more nodes or machines, each running an Oracle instance that accesses a single database residing on shared-disk storage. In a RAC environment, all active instances can concurrently execute transactions against the shared database. RAC automatically coordinates each instance's access to the shared data to provide data consistency and data integrity.
RAC depends on two types of failover mechanisms:
Network failover is the default failover and is the only type of failover available when using the JDBC thin driver. Network failure ensures that newer database connections created after a database instance in a RAC cluster goes down are created against a backup or surviving database instance in that cluster even though the tns alias that was used to create the newer database connection was for the database instance that went down. When network failover is the only available failover mechanism then existing connections are not automatically reconnected to surviving RAC instances. These existing connections are no longer usable and you will get ORA-03113 exceptions if you try to use them. On-going database operations (including AQ operations) can fail with a wide variety of exceptions when failover occurs in a RAC cluster configured to perform only network failover.
TAF failover is only available when using the thick JDBC driver. To enable it, you must set the FAILOVER_MODE as part of the CONNECT_DATA portion of the tns alias used to create the JDBC connection.
TAF is a runtime failover for high-availability environments, such as RAC and Data Guard, that refers to the failover and re-establishment of application-to-service connections. It enables client applications to automatically reconnect to the database if the connection fails, and optionally resume a SELECT statement that was in progress. This reconnect happens automatically from within the Oracle Call Interface (OCI) library.
TAF provides a best effort failover mechanism for on-going operations on a database connection created against a database instance which is part of a RAC cluster. It also attempts to ensure that existing connections (which are not in use at failover time) are reconnected to a backup or surviving database instance. However TAF is not always able to replay transactional operations which occur past the last committed transaction. When this happens it usually throws an ORA-25408 ("cannot safely replay call") error. It is then your application's responsibility to explicitly rollback the current transaction before the database connection can be used again. Your application will also need to replay all the operations past the last committed transaction to get into the same state as that before the failover occurred.
TAF protects or fails-over:
TAF neither protects nor fails-over:
Oracle Application Server Containers for J2EE can be integrated with RAC, Data Guard, and TAF as part of your HA architecture.
The remainder of this section describes configuration issues specific to Oracle Application Server Containers for J2EE that relate directly to HA. Use this information in conjunction with MAA recommendations and procedures.
Oracle Application Server Containers for J2EE HA configuration issues include:
To configure OC4J to use network failover:
<data-source class="com.evermind.sql.DriverManagerDataSource" name="OracleDS" location="jdbc/OracleCoreDS" xa-location="jdbc/xa/OracleXADS" ejb-location="jdbc/OracleDS" connection-driver="oracle.jdbc.driver.OracleDriver" username="scott" password="tiger" url="jdbc:oracle:thin:@(DESCRIPTION= (LOAD_BALANCE=on) (ADDRESS=(PROTOCOL=TCP) (HOST=host1) (PORT=1521)) (ADDRESS=(PROTOCOL=TCP) (HOST=host2) (PORT=1521)) (CONNECT_DATA=(SERVICE_NAME=service_name)))" inactivity-timeout="300" connection-retry-interval="2" max-connect-attempts="60" max-connections="60" min-connections="12" />
In this example, note the url
element. As long as two or more hosts are specified, the JDBC client will randomly choose one of the alternatives if the current host is unreachable.
For details on data source configuration, see "Defining Data Sources".
To configure OC4J for use with TAF:
<data-source class="com.evermind.sql.DriverManagerDataSource" name="OracleDS" location="jdbc/OracleCoreDS" xa-location="jdbc/xa/OracleXADS" ejb-location="jdbc/OracleDS" connection-driver="oracle.jdbc.driver.OracleDriver" username="scott" password="tiger" url="jdbc:oracle:oci8:@(description=(load_balance=on)(failover=on) (address=(protocol=tcp)(host=db-node1)(port=1521)) (address=(protocol=tcp)(host=db-node2)(port=1521)) (address=(protocol=tcp)(host=db-node3)(port=1521)) (address=(protocol=tcp)(host=db-node4)(port=1521)) (connect_data= (service_name=db.us.oracle.com) (failover_mode=(type=select)(method=basic)(retries=20)(delay=15))))" rac-enabled="true" inactivity-timeout="300" connection-retry-interval="2" max-connect-attempts="60" max-connections="60" min-connections="12" />
In this example, note the url
element failover
is on
and failover_mode
is defined. As long as two or more hosts are specified, the JDBC client will randomly choose one of the alternatives if the current host is unreachable. For a description of failover_mode
options, see Table 4-6, "TAF Configuration Options".
For details on data source configuration, see "Defining Data Sources".
orion-application.xml
file. For example:
<resource-provider class="oracle.jms.OjmsContext" name="cartojms1"> <description> OJMS/AQ </description> <property name="datasource" value="jdbc/CartEmulatedDS"></property> </resource-provider>
TAF is configured using Net8 parameters in the tnsnames.ora
file.
TAF can be configured by including a FAILOVER_MODE parameter under the CONNECT_DATA section of a connect descriptor. TAF supports the sub-parameters described in Table 4-6.
In the following example, Oracle Net connects randomly to one of the protocol addresses on sales1-server or sales2-server. If the instance fails after the connection, then the TAF application fails over to the listener on another node.
sales.us.acme.com= (DESCRIPTION= (LOAD_BALANCE=on) (FAILOVER=on) (ADDRESS=(PROTOCOL=tcp)(HOST=sales1-server)(PORT=1521)) (ADDRESS=(PROTOCOL=tcp)(HOST=sales2-server)(PORT=1521)) (CONNECT_DATA= (SERVICE_NAME=sales.us.acme.com) (FAILOVER_MODE= (TYPE=session) (METHOD=basic) (RETRIES=20) (DELAY=15))))
For more information on configuring TAF, refer to the Oracle10i Net Services Administrator's Guide.
If you have a transaction spanning two beans and each bean gets a JDBC connection to the same database but different instances, then on commit, OC4j will issue a simple commit (instead of Two-Phase Commit) which will make the transaction suspect. If your application will encounter such transactions, use either TAF or connection pooling, but not both.
In case of an instance failure, dead connections are cleaned from both the OC4J connection pool and from the JDBC type 2 connection pool.
If a database goes down and getConnection()
is called, and if connection pooling is used, the pool is cleaned up. The caller must catch the exception on the getConnection()
call and retry. In some cases, the OC4J container does the retries.
OC4J cleans up a connection pool when the connection is detected to be bad. That is, if getConnection()
throws an SQLException
with error code of 3113 or 3114.
When an exception occurs while using a user connection handle, it is useful for OC4J to detect if the exception is due to a database connection error or to a database operational error. The most common error codes thrown by the database when a connection error occurs are 3113 and 3114. These are returned typically for in-flight connections that get dropped. In addition, new connection attempts may receive error codes 1033, 1034, 1089 and 1090.
Fast-connection cleanup is implemented in both non-RAC and RAC environments.
In a non-RAC environment, when ajava.sql.SQLException
is thrown, all un-allocated connections are removed from the pool.
In a RAC environment, when ajava.sql.SQLException
is thrown, first the states of all un-allocated connections are checked. If they are alive, they are left alone. Otherwise, they are removed from the pool.
Active Update transactions are rolled back at the time of failure because TAF cannot preserve active transactions after failover. TAF requires an acknowledgement from the application that a failure has occurred via a rollback command (in other words, the application receives an error message until a ROLLBACK is submitted).
A common failure scenario is as follows:
Using Oracle Call Interface (OCI) call backs and failover events, your application can customize TAF operation to automatically provide the required acknowledgement.
Your application (J2EE components) can capture the failure status of an Oracle instance and customize TAF by providing a function that the OCI library will automatically call during fail-over using OCI callback capabilities. Table 4-7 describes the fail-over events defined in the OCI API.
For more information, see the Oracle Call Interface Programmer's Guide.
Depending on the driver type used, SQLExceptions will have different error codes and transaction replay may or may not be supported.
These error codes are obtained by making a getErrorCode()
call on the java.sql.SQLException
that is thrown to the caller.
Table 4-8 summarizes these issues by driver type.
Driver | Error Code | Servlet Layer | Session Bean (CMT, BMT) | Entity Bean (CMP) |
---|---|---|---|---|
Thin JDBC |
17410 |
Replay works. |
Replay works (ignore "No _activetransaction" error). |
Replay not supported. |
OCI |
3113, 3114 |
Replay works. |
Replay not supported. |
Replay not supported. |
OCI/TAF |
|
After application sends acknowledgement to TAF (see "Acknowledging TAF Exceptions"), replay on surviving node works. |
After application sends acknowledgement to TAF (see "Acknowledging TAF Exceptions"), replay on surviving node works. |
If application sends acknowledgement to TAF (see "Acknowledging TAF Exceptions"), then OC4J proceeds transparently. |
|
Copyright © 1996, 2003 Oracle Corporation. All Rights Reserved. |
|