Integrating BTM with Hibernate
Hibernate can be integrated straight with any JTA transaction manager. These instructions have been verified against BTM 1.2 and Hibernate 3.2.6.
...
| Info | ||
|---|---|---|
| ||
The example discussed here uses the Hibernate API but the JPA API could be used as well. You just need to use the EntityManager but the same configuration applies. |
Contents
| Table of Contents | ||||
|---|---|---|---|---|
|
JTA datasources
Hibernate cannot directly create a BTM PoolingDataSource. You will have to create them yourself (either via the API or the Resource Loader) and make sure they are bound to a JNDI server.
Setting up a JNDI server
You have to bind the datasources to some JNDI server. You can use any one you wish, including the one embedded in your application server.
...
This will configure Tomcat's JNDI server as the default implementation. It is a simple intra-VM server that implements the most important JNDI features. You can now just create a InitialContext with the no-args constructor to have access to it.
API way: Creating the datasources
As you can expect, you will need to create one PoolingDataSource per database. Say that you want to use two Embedded Derby databases, and configure them via the BTM API. Here is what your code would look like:
...
| Code Block |
|---|
Context ctx = new InitialContext();
ctx.createSubcontext("jdbc");
ctx.rebind("jdbc/testDS1", ds1);
ctx.rebind("jdbc/testDS2", ds2);
ctx.close();
|
Resource Loader way: Creating the datasources
You can use BTM's Resource Loader instead of the BTM API. It is usually a good idea when you want to create a fully standalone application as you can get rid of the datasources creation, JNDI binding and shutdown code.
...
This has the exact same behavior as creating the PoolingDataSource objects and binding them to JNDI yourself. It is just more convenient.
Hibernate Session factories
You need to configure exactly one SessionFactory per datasource.
Datasource JNDI location
You have to tell Hibernate where to get the BTM datasource via JNDI. Add a connection.datasource property and set its value to the JNDI location of your datasource:
| Code Block | ||
|---|---|---|
| ||
<property name="connection.datasource">jdbc/testDS1</property> |
Current session context
You have to set current_session_context_class to jta.
| Code Block | ||
|---|---|---|
| ||
<property name="current_session_context_class">jta</property> |
Transaction factory class
You have to set transaction.factory_class to org.hibernate.transaction.JTATransactionFactory.
| Code Block | ||
|---|---|---|
| ||
<property name="transaction.factory_class">org.hibernate.transaction.JTATransactionFactory</property> |
Transaction manager lookup class
You have to set transaction.manager_lookup_class to an implementation of TransactionManagerLookup that you have to create yourself. Here is an example implementation if this interface:
...
| Code Block | ||
|---|---|---|
| ||
<property name="transaction.manager_lookup_class">bitronix.examples.hibernate.BitronixTransactionManagerLookup</property> |
SessionFactory XML configuration files
Here is what the hibernate_testDS1.cfg.xml file will look like for the first datasource. Some other mandatory properties also have to be added, like the dialect, cache.provider_class and of course the required object mappings.
...
| Code Block | ||
|---|---|---|
| ||
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="connection.datasource">jdbc/testDS2</property>
<property name="current_session_context_class">jta</property>
<property name="transaction.factory_class">org.hibernate.transaction.JTATransactionFactory</property>
<property name="transaction.manager_lookup_class">bitronix.examples.hibernate.BitronixTransactionManagerLookup</property>
<property name="dialect">org.hibernate.dialect.DerbyDialect</property>
<property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
<property name="show_sql">true</property>
<mapping resource="bitronix/examples/hibernate/entities/User.hbm.xml"/>
</session-factory>
</hibernate-configuration>
|
End result
Now that Hibernate and BTM are properly configured, you can simply use the JTA and Hibernate APIs in your application.
Application code
Here is what your code will look like when you want to update the content of both databases atomically:
...
Say that persistUser() creates a new user, in no way will a user be created in one database and not in the other.
Download
You can download a sample runnable application putting these explanations in practice. It contains all the code that has been skipped for clarity in this page. Both the API and Resource Loader ways are implemented so you can try both and see which one you prefer.
...