• 沒有找到結果。

Integration with JTA

在文檔中 Praise for the First Edition (頁 132-136)

This chapter covers

2.4 Integration with Java EE services

2.4.1 Integration with JTA

The Java Transaction API (JTA) is the standardized service interface for transaction control in Java enterprise applications. It exposes several interfaces, such as the UserTransactionAPI for transaction demarcation and the TransactionManager API for participation in the transaction lifecycle. The transaction manager can coordinate a transaction that spans several resources—imagine working in two Hibernate Sessions on two databases in a single transaction.

A JTA transaction service is provided by all Java EE application servers. How-ever, many Java EE services are usable stand-alone, and you can deploy a JTA pro-vider along with your application, such as JBoss Transactions or ObjectWeb JOTM. We won’t have much to say about this part of your configuration but focus on the integration of Hibernate with a JTA service, which is the same in full application servers or with stand-alone JTA providers.

Look at figure 2.6. You use the Hibernate Session interface to access your database(s), and it’s Hibernate’s responsibility to integrate with the Java EE ser-vices of the managed environment.

In such a managed environment, Hibernate no longer creates and maintains a JDBC connection pool—Hibernate obtains database connections by looking up a Datasource object in the JNDI registry. Hence, your Hibernate configuration needs a reference to the JNDI name where managed connections can be obtained.

<hibernate-configuration>

<session-factory>

<property name="hibernate.connection.datasource">

java:/MyDatasource

Figure 2.6 Hibernate in an environment with managed resources

</property>

<property name="hibernate.dialect">

org.hibernate.dialect.HSQLDialect </property>

...

</session-factory>

</hibernate-configuration>

With this configuration file, Hibernate looks up database connections in JNDI using the name java:/MyDatasource. When you configure your application server and deploy your application, or when you configure your stand-alone JTA provider, this is the name to which you should bind the managed datasource. Note that a dialect setting is still required for Hibernate to produce the correct SQL.

NOTE Hibernate with Tomcat—Tomcat isn’t a Java EE application server; it’s just a servlet container, albeit a servlet container with some features usually found only in application servers. One of these features may be used with Hibernate: the Tomcat connection pool. Tomcat uses the DBCP connection pool internally but exposes it as a JNDI datasource, just like a real application server. To configure the Tomcat datasource, you need to edit server.xml, according to instructions in the Tomcat JNDI/JDBC documentation. Hibernate can be configured to use this datasource by setting hibernate.connection.datasource. Keep in mind that Tomcat doesn’t ship with a transaction manager, so you still have plain JDBC transaction semantics, which Hibernate can hide with its optional Transaction API. Alternatively, you can deploy a JTA-compatible stand-alone transaction manager along with your web application, which you should consider to get the standardized UserTransaction API. On the other hand, a regular application server (especially if it’s modular like JBoss AS) may be easier to configure than Tomcat plus DBCP plus JTA, and it provides better services.

To fully integrate Hibernate with JTA, you need to tell Hibernate a bit more about your transaction manager. Hibernate has to hook into the transaction lifecycle, for example, to manage its caches. First, you need to tell Hibernate what transac-tion manager you’re using:

<hibernate-configuration>

<session-factory>

<property name="hibernate.connection.datasource">

java:/MyDatasource </property>

<property name="hibernate.dialect">

org.hibernate.dialect.HSQLDialect </property>

<property name="hibernate.transaction.manager_lookup_class">

org.hibernate.transaction.JBossTransactionManagerLookup </property>

<property name="hibernate.transaction.factory_class">

org.hibernate.transaction.JTATransactionFactory </property>

...

</session-factory>

</hibernate-configuration>

You need to pick the appropriate lookup class for your application server, as you did in the preceding code—Hibernate comes bundled with classes for the most popular JTA providers and application servers. Finally, you tell Hibernate that you want to use the JTA transaction interfaces in the application to set transaction boundaries. The JTATransactionFactory does several things:

It enables correct Session scoping and propagation for JTA if you decide to use the SessionFactory.getCurrentSession() method instead of opening and closing every Session manually. We discuss this feature in more detail in chapter 11, section 11.1, “Propagating the Hibernate session.”

It tells Hibernate that you’re planning to call the JTAUserTransaction inter-face in your application to start, commit, or roll back system transactions.

It also switches the Hibernate Transaction API to JTA, in case you don’t want to work with the standardized UserTransaction. If you now begin a transaction with the Hibernate API, it checks whether an ongoing JTA trans-action is in progress and, if possible, joins this transtrans-action. If no JTA transac-tion is in progress, a new transactransac-tion is started. If you commit or roll back with the Hibernate API, it either ignores the call (if Hibernate joined an existing transaction) or sets the system transaction to commit or roll back.

We don’t recommend using the Hibernate Transaction API if you deploy in an environment that supports JTA. However, this setting keeps existing code portable between managed and nonmanaged environments, albeit with possibly different transactional behavior.

There are other built-in TransactionFactory options, and you can write your own by implementing this interface. The JDBCTransactionFactory is the default in a nonmanaged environment, and you have used it throughout this chapter in

the simple “Hello World” example with no JTA. The CMTTransactionFactory should be enabled if you’re working with JTA and EJBs, and if you plan to set trans-action boundaries declaratively on your managed EJB components—in other words, if you deploy your EJB application on a Java EE application server but don’t set transaction boundaries programmatically with the UserTransaction interface in application code.

Our recommended configuration options, ordered by preference, are as follows:

If your application has to run in managed and nonmanaged environments, you should move the responsibility for transaction integration and resource management to the deployer. Call the JTA UserTransaction API in your application code, and let the deployer of the application configure the application server or a stand-alone JTA provider accordingly. Enable JTATransactionFactory in your Hibernate configuration to integrate with the JTA service, and set the right lookup class.

Consider setting transaction boundaries declaratively, with EJB components.

Your data access code then isn’t bound to any transaction API, and the CMT-TransactionFactory integrates and handles the Hibernate Session for you behind the scenes. This is the easiest solution—of course, the deployer now has the responsibility to provide an environment that supports JTA and EJB components.

Write your code with the Hibernate Transaction API and let Hibernate switch between the different deployment environments by setting either JDBCTransactionFactory or JTATransactionFactory. Be aware that trans-action semantics may change, and the start or commit of a transtrans-action may result in a no-op you may not expect. This is always the last choice when portability of transaction demarcation is needed.

FAQ How can I use several databases with Hibernate? If you want to work with several databases, you create several configuration files. Each database is assigned its own SessionFactory, and you build several SessionFactory instances from distinct Configuration objects. Each Session that is opened, from any SessionFactory, looks up a managed datasource in JNDI. It’s now the responsibility of the transaction and resource manager to coordinate these resources—Hibernate only executes SQL statements on these database connections. Transaction boundaries are either set programmatically with JTA or handled by the container with EJBs and a declarative assembly.

Hibernate can not only look up managed resources in JNDI, it can also bind itself to JNDI. We’ll look at that next.

在文檔中 Praise for the First Edition (頁 132-136)