2. Using a Third-Party DataSource
Prev | Chapter 4. JDBC | Next

## 2. Using a Third-Party DataSource

You can use OpenJPA with any third-party `javax.sql.DataSource` . There are multiple ways of telling OpenJPA about a `DataSource`:

- Set the `DataSource` into the map passed to `Persistence.createEntityManagerFactory` under the `openjpa.ConnectionFactory` key.

- Bind the `DataSource` into JNDI, and then specify its location in the `jta-data-source` or `non-jta-data-source` element of the JPA XML format (depending on whether the `DataSource` is managed by JTA), or in the `openjpa.ConnectionFactoryName` property.

- Specify the full class name of the `DataSource` implementation in the `openjpa.ConnectionDriverName` property in place of a JDBC driver. In this configuration OpenJPA will instantiate an instance of the named class via reflection. It will then configure the `DataSource` with the properties in the `openjpa.ConnectionProperties` setting.

The features of OpenJPA's own `DataSource` can also be used with third-party implementations. OpenJPA layers on top of the third-party `DataSource` to provide the extra functionality. To configure these features use the `openjpa.ConnectionFactoryProperties` property described in the previous section.

Example 4.2. Properties File for a Third-Party DataSource

    <property name="openjpa.ConnectionDriverName" value="oracle.jdbc.pool.OracleDataSource"/>
    <property name="openjpa.ConnectionProperties"
        value="PortNumber=1521, ServerName=saturn, DatabaseName=solarsid, DriverType=thin"/>
    <property name="openjpa.ConnectionFactoryProperties" value="QueryTimeout=5000"/>

You can also force the Apache Commons DBCP BasicDataSource to be used for connection pooling when provided on the classpath by substituting it as the `ConnectionDriverName` and setting `ConnectionProperties=DriverClassName` to the actual JDBC driver value -

    <property name="openjpa.ConnectionDriverName" value="org.apache.commons.dbcp.BasicDataSource"/>
    <property name="openjpa.ConnectionProperties"
        value="DriverClassName=oracle.jdbc.pool.OracleDataSource, PortNumber=1521, ServerName=saturn, DatabaseName=solarsid, DriverType=thin, MaxIdle=0"/>
    <property name="openjpa.ConnectionFactoryProperties" value="QueryTimeout=5000"/>

### 2.1. Managed and XA DataSources

Certain application servers automatically enlist their `DataSource` s in global transactions. When this is the case, OpenJPA should not attempt to commit the underlying connection, leaving JDBC transaction completion to the application server. To notify OpenJPA that your third-party `DataSource` is managed by the application server, use the `jta-data-source` element of your `persistence.xml` file or set the `openjpa.ConnectionFactoryMode` property to `managed`.

Note that OpenJPA can only use managed `DataSource`s when it is also integrating with the application server's managed transactions. Also note that all XA `DataSource`s are enlisted, and you must set this property when using any XA `DataSource`.

When using a managed `DataSource`, you should also configure a second unmanaged `DataSource` that OpenJPA can use to perform tasks that are independent of the global transaction. The most common of these tasks is updating the sequence table OpenJPA uses to generate unique primary key values for your datastore identity objects. Configure the second `DataSource` using the `non-jta-data-source` `persistence.xml` element, or OpenJPA's various "2" connection properties, such as `openjpa.ConnectionFactory2Name` or `openjpa.Connection2DriverName`. These properties are outlined in Chapter 2, Configuration .

Example 4.3. Managed DataSource Configuration

    <!-- managed DataSource -->
    <jta-data-source>java:/OracleXASource</jta-data-source>
    <properties>
        <!-- use OpenJPA's built-in DataSource for unmanaged connections -->
        <property name="openjpa.Connection2UserName" value="scott"/>
        <property name="openjpa.Connection2Password" value="tiger"/>
        <property name="openjpa.Connection2URL" value="jdbc:oracle:thin:@CROM:1521:OpenJPADB"/>
        <property name="openjpa.Connection2DriverName" value="oracle.jdbc.driver.OracleDriver"/>
    </properties>

### 2.2. Setting the DataSource at runtime

As mentioned above, the JTA and Non-JTA DataSources may be passed in as configuration properties at EntityManagerFactory creation. Either the JPA standard properties ( `jakarta.persistence.jtaDataSource`, `java.persistence.nonJtaDataSource`) or their OpenJPA specific equivalents (`openjpa.ConnectionFactoryName`, `openjpa.ConnectionFactory2Name`) may be used. One use case for this function is to store production connection information in configuration files but override the value when testing.

Example 4.4. Setting DataSource at Runtime

    Map<Object,Object> props = new HashMap<Object,Object>();
    props.put("jakarta.persistence.jtaDataSource", "jdbc/myDataSource");
    props.put("jakarta.persistence.nonJtaDataSource", "jdbc/myNonJTADataSource");
    emf = Persistence.createEntityManagerFactory("example", props);

#### 2.2.1. Using different DataSources for each EntityManager

The JPA specification allows the DataSource (ConnectionFactory) to be specified on the EntityManagerFactory. OpenJPA extends this support and allows each EntityManager to override the DataSource from the EntityManagerFactory. It's expected that the EntityManagerFactory will also be configured with a valid JTA / Non-JTA DataSource. The DataSource configured on the EntityManagerFactory will be used to obtain a DBDictionary and (rarely) to gather some information about the database in use (e.g. version, JDBC driver version).

If the EntityManagerFactory is not configured with a valid DataSource there are a few additional caveats.

- The `openjpa.DBDictionary` property must be used to ensure the correct DBDictionary is used.

- OpenJPA will always attempt to obtain a DataSource from JNDI based on the configuration for the EntityManagerFactory. When a JNDI name is specified on the EntityManager this lookup happens slightly earlier than normal. If the lookup fails the JNDI name provided at EntityManager creation will be set into the EntityManagerFactory's configuration and used in subsequent attempts.

##### 2.2.1.1. Benefits

In effect this option allows a single set of entity definitions to be shared between multiple database instances or schemas within an instance. This can be highly beneficial when there are a large number of entity definitions (e.g. > 200), or a large number of databases / schemas in use.

##### 2.2.1.2. Limitations

- The same database type and version must be used by each EntityManager. OpenJPA will use the same DBDictionary for each EntityManager and will make no attempt to alter SQL syntax between EntityManager instances.

- It is the application's responsibility to ensure that the schema is identical on each database.

- The application may not specify schema names for individual entities.

- The DataSource (ConnectionFactory) name may only be specified when the EntityManager is created. The DataSource may not be switched while an EntityManager is in use.

- The L2 cache (DataCache) should not be used if different DataSources are specified for each EntityManager

- SynchronizeMappings should not be used with this feature.

- Table and Sequence generators should not be used with this feature.

- It is not required, but is recommended that the `openjpa.DBDictionary` property be specified when using this feature

##### 2.2.1.3. Error handling

If a JTA DataSource is not available when the EntityManager is created, an `IllegalArgumentException` will be thrown. The EntityManager will not fall back to the JTA DataSource defined in the configuration.

The same logic applies if a Non-JTA DataSource is not available when the EntityManager is created. OpenJPA will not fall back to the configured Non-JTA DataSource.

Prev | Up | Next
Chapter 4. JDBC | Home | 3. Runtime Access to DataSource