Integrating BTM with Hibernate
Hibernate can be integrated straight with any JTA transaction manager. These instructions have been verified against BTM 1.3 and Hibernate 3.3.0.SP1.
The biggest added value (omitting the fact that you can use Hibernate and two databases) is Hibernate's Current Session context management with JTA. You do not have to take care about opening nor closing Session as Hibernate will automatically bind them to the JTA transaction's lifecycle. You just have to make sure JTA transactions are properly started and ended.
| JPA, Hibernate and BTM 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
- JTA datasources
- Setting up the BTM JNDI server
- API way: Creating the datasources
- Resource Loader way: Creating the datasources
- Hibernate Session factories
- Datasource JNDI location
- Current session context
- Transaction factory class
- Transaction manager lookup class
- SessionFactory XML configuration files
- End result
- Download
JTA datasources
Hibernate cannot directly create a BTM PoolingDataSource. You will have to create them yourself (either via the API or the Resource Loader).
Setting up the BTM JNDI server
You have to bind the datasources and the transaction manager to some JNDI server. You can use any one you wish, but BTM 1.3 ships with one you might find more convenient to use.
It is very easy to use it in a standalone J2SE application. Just create a jndi.properties file at the root of your classpath. It should only contain this line:
You can now just create a InitialContext with the no-args constructor to have access to it.
| Multiple JNDI providers If you are running your application in a context in which there already is a JNDI provider installed (for instance in a web application) you can tell Hibernate to perform lookups in a specific JNDI environment instead by setting the hibernate.jndi.class property to |
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:
| Datasource's unique name and JNDI location correspondence The BTM JNDI provider will automatically bind the datasources under their unique name. In this case, you can look up jdbc/testDS1 or jdbc/testDS2 as soon as the transaction manager started without having anything else to configure. |
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 and shutdown code.
Create a datasources.properties file in the current directory containing these properties:
| Resource Loader and JNDI binding As with the API, the datasources will be available in JNDI under their unique name. |
In your application code, you will have to configure BTM to use the resource loader:
This has the exact same behavior as creating the PoolingDataSource objects 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:
Current session context
You have to set current_session_context_class to jta.
Transaction factory class
You have to set transaction.factory_class to org.hibernate.transaction.JTATransactionFactory.
| JPA / EJB3 API When you use Hibernate via the JPA / EJB3 API (also known as Hibernate EntityManager) you should not set the |
Transaction manager lookup class
You have to set transaction.manager_lookup_class to an implementation of TransactionManagerLookup. Hibernate ships with one that can lookup BTM since version 3.3.
add this property to your config to use it:
| BTMTransactionManagerLookup and JNDI The BTMTransactionManagerLookup implementation which ships with Hibernate has a limitation regarding JNDI lookup of the transaction manager. If you're going to use it within an application server that already contains a JNDI server you might encounter problems. |
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.
And here is the hibernate_testDS2.cfg.xml for the second datasource:
| Hibernate connection release mode There currently is a bug in BTM's connection pool that impacts all versions up to and including 1.3.2. You must set connection.release_mode to after_statement to workaround the bug (see Hibernate's documentation). If you don't, you might end up seeing BTM throwing exceptions and leaking connections. This is bug BTM-33 which has been fixed in BTM 1.3.3. |
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.
You can download this demo here: HibernateBTM13.zip.
There is an ant build.xml file included as well as a the necessary batch and shell scripts required to run the application from Windows or Unix.
Before you run the application, you have to create the Derby database. Just run the included derby-create.sh or derby-create.bat script to do so, it will create two directories called users1 and users2. Then you can start the demo by either running run_api.sh or run_api.bat for the API version, run_rl.sh or run_rl.bat for the Resource Loader version.
Here is the list of JAR files with version required to run this demo. They're all included in the downloadable ZIP file.
JAR name |
Version |
|---|---|
btm-1.3.jar |
BTM 1.3 |
geronimo-jta_1.0.1B_spec-1.0.1.jar |
BTM 1.3 |
slf4j-api-1.5.2.jar |
SLF4J 1.5.2 |
slf4j-jdk14-1.5.2.jar |
SLF4J 1.5.2 |
derby-10.3.1.4.jar |
Derby 10.3.1.4 |
derbytools-10.3.1.4.jar |
Derby 10.3.1.4 |
antlr-2.7.6.jar |
Hibernate 3.3.0.SP1 |
hibernate-cglib-repack-2.1_3.jar |
Hibernate 3.3.0.SP1 |
javassist-3.4.GA.jar |
Hibernate 3.3.0.SP1 |
commons-collections-3.1.jar |
Hibernate 3.3.0.SP1 |
dom4j-1.6.1.jar |
Hibernate 3.3.0.SP1 |
hibernate3.jar |
Hibernate 3.3.0.SP1 |

5 Comments
Hide/Show CommentsDec 05, 2008
Simon Massey
I found that if I used the example on this page and the spring example on this wiki then including both a factory class and a manager lookup in the hibernate did not work. I got JNDI lookup exceptions when I was not using a JNDI but a direct spring configuration of the BTMTransaction Manager:
Caused by: org.hibernate.TransactionException: Could not find UserTransaction in JNDI:
at org.hibernate.transaction.JTATransaction.(JTATransaction.java:64)
I had to delete the reference to the JTATransactionFactory as shown here to remove the dependency on JNDI:
<bean id="hibernateSessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="mappingResources">
<list>
<value>HibernateMappedObject.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.use_outer_join">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.cache.use_query_cache">false</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.DerbyDialect</prop>
<prop key="hibernate.cache.provider_class">org.hibernate.cache.NoCacheProvider</prop>
<prop key="hibernate.cache.use_second_level_cache">false</prop>
<!- JTA stuff ->
<prop key="hibernate.connection.release_mode">after_statement</prop>
<prop key="hibernate.current_session_context_class">jta</prop>
<prop key="hibernate.transaction.manager_lookup_class">org.hibernate.transaction.BTMTransactionManagerLookup</prop>
</props>
</property>
</bean>
Dec 06, 2008
Ludovic Orban
If you remove the JTATransactionFactory property then Hibernate will not integrate with the TM and quite some features won't work as they should (2nd level cache, session management...).
Hibernate has a problem looking up the transaction manager in your case, there certainly is a reason for that. You should fix the root cause of the problem (ie: why does the JNDI lookup fail) instead of changing the Hibernate config at random.
Jan 28, 2009
Helder Sousa
The problem that Simon refers is because Hibernate. See this link http://opensource.atlassian.com/projects/hibernate/browse/HHH-3481
Basically, when the code in method getUserTransaction() throws an exception, that exception is catched and creates a exception "string message" that calls again the method getUserTransaction() and this leads to a loop.
The hibernate guys already correct this, calling the getUserTransactionName() instead of the getUserTransaction().
Now, why the first exception of the loop occurs in first place? The first exception is:
javax.naming.NamingException: Cannot create resource instance
I did some debug, and when the application runs with tomcat, the constructor of BitronixContext() is called during startup (because of <prop key="hibernate.transaction.manager_lookup_class">org.hibernate.transaction.BTMTransactionManagerLookup</prop>
), but the lookup method of BitronixContext class is never called.
See the defaultInitCtx variable in "variables view". The bitronixContext is there.
Why the lookup method of BitronixContext is not called? What do you think about this Ludovic?
Jan 28, 2009
Ludovic Orban
This might be due to the way JNDI works but I can't really say with so little information. Please move the discussion to the mailing list if you want to investigate deeper.
Jan 29, 2009
Ludovic Orban
Check this thread in the mailing list for the solution to the JNDI problem discussed above: http://www.nabble.com/Hibernate-JTATransactionFactory-and-BTMTransactionManagerLookup-td21706680.html