JTA Introduction
-
Summary
1.1What Is JTA
1.1.1 What Is JTA
JTA is short for Java Transaction API, it is one of the Java EE API s allowing distributed transactions to be done across multiple resources in the Java environment. It is a high-level API which defines interfaces between a transaction manager and the parties involved in a distributed transaction system: the resource manager, the application server, and the transactional applications.
For more detail explanation of JTA, can refer to the JTA specification document - http://192.168.18.224:8888/svn/Work_Space/Research/scarlett/booking-service/doc/jta-1_1-spec.pdf
1.1.2 What Is Distributed Transaction
A transaction defines a logical unit of work that either completely succeeds or produces no result at all. This is known as the ACID(Atomicity,Consistency,Isolation,Durability) feature of transaction.
A distributed transaction is simply a transaction that accesses and updates data on two or more resources, and therefore must be coordinated among those resources. The Transaction Manager coordinates all of this through a XA protocol called Two Phase Commit (2PC). This protocol also has to be supported by the individual resources which is known as XA data source.
A distributed transaction should also fulfil the transaction's ACID feature, a Distributed transaction is generally known as a global transaction.
The distributed transaction is achieved based on the XA(eXtended Architecture) specification, which is an X/Open group standard for accessing multiple resources within the same transaction. So distributed transaction also called XA transaction.
An XA data source is a data source that can participate in a distributed transaction.
1.1.3 What Is Local Transaction
Different from distributed transaction, a local transaction will only involve just one resource, a local transaction has no transaction coordinator, the single resource is doing all its transaction work itself.
In most general cases, the local transaction is used.
In this document, we will not talk much about the local transaction.
1.2 Why Use JTA
- JTA can span multiple transactional resources.
- JTA will change to local transaction mode(that means will not use two phase commit) if there is only one resource involved. So the performance will not worse than local transaction.
- JTA is lightweight.
- When with JTA, even if the application currently accesses only one resource, It will be more flexible and easy to include some other transactional resource in future.
- Currently, our application need to access two different databases in one transaction. One is DroolsTasks database which stores tasks related info and the other is Bookings database which stores booking data.
So we will remommend to use JTA transaction.
1.3 JTA Provider
A Java EE application server have already implemented the JTA interface, so within a Java EE application server, can directly use JTA.
Without a Java EE application server, there are some standalone JTA providers: Bitronix(BTM), Atomikos, JOTM, Jboss TS and etc.
We choose to use BTM in our application, the configurations which will be described in the document are about BTM JTA. As BTM is used by Drools, although no intensive evaluation has been done, as we are planned to use the abstract layer of the Spring JTA Transaction Manager (Ref to Chapter 3) , switching from one to others will be easy.
1.4 JTA Environment
To enable a JTA compliant application, some Environment need to set up:
Database: database engine should support the XA protocol, As we use the MySQL5.1 database, so we choose MySQL5.1 with InnoDB engine. For detail info about MySQL InnoDB, can refer to http://dev.mysql.com/doc/refman/5.1/en/innodb-parameters.html.
JDBC Driver: com.mysql.jdbc.jdbc2.optional.MysqlXADataSource which has implemented the XADataSource and can participate in a JTA transaction.
-
Project Environment
JDK version: Java SE 6 environment.
ORM framework: Hibernate implementation of JPA - http://192.168.18.224:8888/svn/Work_Space/Research/scarlett/booking-service/doc/JPA_lesson_v2.2.doc
Transaction framework: Spring JtaTransactionManager abstraction of underlying JTA transaction manager.
-
Use BTM JTA With Plain Java SE
BTM is a simple but complete implementation of the JTA 1.1 API, it is a fully working XA transaction manager that provides all services required by the JTA API while trying to keep the code as simple as possible.
Configuring the BTM JTA with Hibernate JPA is very easy.
2.1 Config Classpath
To use BTM and JTA, need to import some necessary libraries, the core library are:
jta-1.1.jar – the JTA API
btm-2.1.1.jar – the BTM implementation of JTA(now the latest stable version is 2.1.1)
After get these libraries, add them to the classpath.
2.2 Configure BTM
BTM provides many configurable features, including engine setting, journal setting, timers setting and resource loader setting, they can be configured through a property file or directly set on the Configuration object.
When set through a property file, the file can be stored anywhere on the file system, and you need to set the bitronix.tm.configuration system to tell BTM where the file lies. Generally, we can call the properties file bitronix-default-config.properties and store it at the root of your classpath.
e.g.
bitronix.tm.serverId = jvm-1
bitronix.tm.journal.disk.logPart1Filename = ./tx-logs/part1.btm
bitronix.tm.journal.disk.logPart2Filename = ./tx-logs/part2.btm
When directly set on the Configuration object, first need to get the Configuration object by calling TransactionManagerServices.getConfiguration(), then call setter to set any property.
e.g.
Configuration conf = TransactionManagerServices.getConfiguration();
conf.setServerId("jvm-1"); conf.setLogPart1Filename("./tx-logs/part1.btm"); conf.setLogPart2Filename("./tx-logs/part2.btm");
BTM has already provided sensible default value for these settings except the resource loader, for a first time user, all default settings are good enough, we only need to set the resource loader. For more details of the engine, journal, timers settings, pls refer to - http://docs.codehaus.org/display/BTM/Configuration2x
-
Configure Resource Loader and XA Resources
2.3.1 Configure Resource Loader
The configuration of Resource Loader is same as section 2.2, either can be set in the configuration file
e.g.
bitronix.tm.resource.configuration=src/datasources.properties
or directly set on the Configuration object
e.g.
Configuration conf = TransactionManagerServices.getConfiguration();
conf.setResourceConfigurationFilename("src/datasources.properties");
2.3.2 Configure XA Resources
Resource Loader is a facility that allows easy configuration and management of resources,
it loads and configures XA resources using configuration stored in a properties file. In the resources configuration file, we can configure a JDBC connection pool.
A JDBC connection pool wraps the database JDBC driver's javax.sql.XADataSource implementation and presents it to user as a javax.sql.DataSource.
In our application, we use the MySQL database, the XADataSource implementation we used is com.mysql.jdbc.jdbc2.optional.MysqlXADataSource, and DataSource implementation bitronix.tm.resource.jdbc.PoolingDataSource has wrapped the MysqlXADataSource.
e.g.
resource.ds1.className=com.mysql.jdbc.jdbc2.optional.MysqlXADataSource
resource.ds1.uniqueName=jdbc/booking
resource.ds1.maxPoolSize=3
resource.ds1.driverProperties.databaseName=Bookings
resource.ds1.driverProperties.user=root
resource.ds1.driverProperties.password=password
resource.ds1.driverProperties.URL=jdbc:mysql://localhost:3306/Bookings
resource is constant and never changes, ds1 is an arbitrary name used to group a set of properties together, and the part after ds1 is a javabean property of bitronix.tm.resource.jdbc.PoolingDataSource.
If configured like this way, then in the application code, will have to configure BTM to use the resource loader as described in section 2.2. we can do it by the API:
e.g.
Configuration conf = TransactionManagerServices.getConfiguration();
conf.setResourceConfigurationFilename("src/datasources.properties");
The XA resources can also be configured by directly setting on the PoolingDataSource object. For how to configure on the PoolingDataSource object and what are all the properties can be set for JDBC connection pool, can refer to – http://docs.codehaus.org/display/BTM/JdbcConfiguration2x
BTM also supports JMS, for detail of how to set the JMS XA connection pool, can refer to - http://docs.codehaus.org/display/BTM/JmsConfiguration2x
-
Set BTM JNDI Server
BTM has to work with JNDI, the resources and transaction manager need to be bound to a JNDI server, then they can be accessed through the JNDI server. In a Java EE application server, there is already JNDI provider, but in the Java SE encironment, we have to use a standalone JNDI provider. BTM has provided one which is convenient to use, and we choose this one in our application.
The setting up is very easy, just create a jndi.properties file at the root of the classpath. And in the file you write:
java.naming.factory.initial=bitronix.tm.jndi.BitronixInitialContextFactory
If this is used in an environment where there is already a JNDI provider, you can tell Hibernate to use this one by setting the property:
<property name="hibernate.jndi.class" value="bitronix.tm.jndi.BitronixInitialContextFactory"/>
The BTM JNDI provider will automatically bind the datasource configured in Chapter 2.3 under their unique name. Then the datasource can be looked up by the unique name after the transaction manager is started.
-
Configure Hibernate JPA Properties
In order to use the BTM JTA transaction manager, we have to add some configuration for Hibernate, as work with JPA, we need to add the Hibernate property configuration in the persistence.xml file.
In the Chapter 2.4 of JPA lesson doument, we have already explained the persistemce.xml file and given an example of it which with the transaction-type as RESOURCE_LOCAL - http://192.168.18.224:8888/svn/Work_Space/Research/scarlett/booking-service/doc/JPA_lesson_v2.2.doc
If the transaction-type is RESOURCE_LOCAL, it is using local transaction, if to use a JTA transaction(distributed transaction), we should set the transaction-type to JTA instead.
e.g.
<persistence-unit name="booking-jta" transaction-type="JTA">
In Java SE environment, we have to config it, if not config this atribute, the default one is RESOURCE_LOCAL.
Other properties need to be added are:
<property name="hibernate.connection.datasource" value="jdbc/booking" />
<property name="hibernate.current_session_context_class" value="jta" />
<property name="hibernate.transaction.factory_class" value="org.hibernate.transaction.JTATransactionFactory" />
<property name="hibernate.transaction.manager_lookup_class" value="org.hibernate.transaction.BTMTransactionManagerLookup" />
The hibernate.connection.datasource tells Hibernate where to get the BTM datasource via JNDI, the value is the datasource unique name defined in the XA resources configuration file.
The
hibernate.current_session_context_class
defines how to manage the scope of Hibernate Session/JPA EM, when
the value set to jta, it means it will use JTASessionContext
,
the session scope will bound to JTA transaction scope, when the
transaction shut down, the session will be closed. Other available
value are
thread
and
managed
,
for detail pls refer to Section 2.5 of -
http://docs.jboss.org/hibernate/core/3.3/reference/en/html/architecture.html#architecture-current-session
The
hibernate.transaction.factory_class
defines the transaction factory to be used, the
org.hibernate.transaction.JTATransactionFactory
should be used when in JTA transaction. But when work with JPA/EJB3,
this property should not be set, as the Ejb3Configuration class will
configure a special one which is JTA compatible.
The
hibernate.transaction.manager_lookup_class
defines the transaction manager lookup class in JTA environment,
this property is required when JVM-level caching is enabled or when
using
hilo
generator in a JTA environment.
Compared
to the RESOURCE_LOCAL
one, A complete JTA compatible
persistence.xml
example can be like:
e.g.
<persistence-unit
name="booking-
jta
"
transaction-type="JTA">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<properties>
<property name="hibernate.archive.autodetection" value="class"/>
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.format_sql" value="true"/>
<property name="hibernate.connection.datasource" value="jdbc/booking" />
<property name="hibernate.current_session_context_class" value="jta" />
<property name="hibernate.transaction.manager_lookup_class" value="org.hibernate.transaction.BTMTransactionManagerLookup" />
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect" />
<!-- after first run the application, should comment it, else it will drop and create table each time
<property name="hibernate.hbm2ddl.auto" value="create" /> -->
</properties>
</persistence-unit>
2.6 Use BTM In DAO
After having configured the classpath(2.1), set up the datasource(2.2,2.3), created JNDI server(2.4) and configured the persistence unit(2.5), you can use the BTM in DAO.
e.g.
Configuration conf = TransactionManagerServices.getConfiguration();
conf.setResourceConfigurationFilename("src/datasources.properties");
UserTransaction ut = TransactionManagerServices.getTransactionManager();
ut.begin();
…
ut.commit();
As described in JPA lesson, we have used the Spring framework in our application. When come to Spring, with the help of dependency injection, we can use the BTM without the JNDI.
-
Configure DataSource
XA resources such as DataSource can be configured as a bean in the Spring application context file.
e.g.
<bean id="dataSource1" class="bitronix.tm.resource.jdbc.PoolingDataSource" init-method="init" destroy-method="close">
<property name="className" value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource" />
<property name="driverProperties" >
<props>
<prop key="URL">jdbc:mysql://localhost:3306/Bookings</prop>
<prop key="user">root</prop>
<prop key="password">ACahlof</prop>
</props>
</property>
<property name="minPoolSize" value="0" />
<property name="maxPoolSize" value="3" />
</bean>
For each bean, we should define an id for it, then other bean can refer to it by the id.
The class defines which implementation of javax.sql.DataSource will be used.
The init-method indicates the method which will be called to create the PoolingDataSource when start the Spring container.
The destroy-method indicates the method which will be called to destroy the PoolingDataSource when shut down the Spring container.
The property className defines the database driver which has implemented javax.sql.XADataSource. The PoolingDataSource will wrap this DataSource.
The property driverProperties defines the database connection info.
The last two properties define the minPoolSize and maxPoolSize feature of the connection pool.
As have described in Chapter 2, all available configuration can be set to PoolingDataSource can refer to - http://docs.codehaus.org/display/BTM/JdbcConfiguration13
-
Configure Transaction Manager
Spring abstracts a general set of transaction facilities from different transaction management APIs. The core transaction management abstraction is PlatformTransactionManager which is a general interface for all Spring's transaction managers, Spring's built-in implementations of this interface can be used with different transaction management APIs.
The built-in implementations are JtaTransactionManager, JpaTransactionManager, DataSourceTransactionManager, HibernateTransactionManager, JdoTransactionManager, JmsTransactionManager. If you only deal with a single data source and access it with JDBC, you can simply use the DataSourceTransactionManager. If you are using an OR mapping framework such as JPA to access one database, you can use JpaTransactionManager, if you are using JTA transaction strategy to access multiple data sources, you can use JtaTransactionManager andetc.
Whatever transaction strategy you choose, you need to configure the corresonding transaction manager in Spring.
3.2.1 Configure Non-JTA Transaction Manager
Below is an example of DataSourceTransactionManager configuration, it need to refer to one data source which is also configured in Spring.
e.g.
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy- method="close">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="" />
<property name="password" value="${jdbc.password}" />
</bean>
<!-- Transaction Manager configuration -->
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
3.2.2 Configure JTA Transaction Manager
In our application, we need to access different data sources(DroolsTasks and Bookins) in one transaction, so we have to use the JtaTransactionManager, then we configure an instance of JtaTransactionManager.
e.g.
<!-- Create Spring JtaTransactionManager -->
<bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManager" ref="bitronixTransactionManager"/>
<property name="userTransaction" ref="bitronixTransactionManager"/>
</bean>
<!-- Create the BTM transaction manager -->
<bean id="bitronixTransactionManager" factory-method="getTransactionManager" class="bitronix.tm.TransactionManagerServices"
depends-on="btmConfig,dataSource1" destroy-method="shutdown"/>
<!-- Bitronix Transaction Manager embedded configuration -->
<bean id="btmConfig" factory-method="getConfiguration"
class="bitronix.tm.TransactionManagerServices">
<property name="serverId" value="spring-btm" />
</bean>
Spring JtaTransactionManager's configuration is different from other transaction managers, in Java SE environment, it need to work based on a standalone JTA provider, here we use the BTM, so in the configuration of JtaTransactionManager, should set the property transactionManager and userTransaction to the BTM transaction manager bitronixTransactionManager.
In the configuration of bitronixTransactionManager, factory-method defines which method will be called to get the BTM transaction manager instance. class defines the class where the factory-method exists. destroy-method indicates which method will be called to shut down the BTM transaction method. depends-on indicates the BTM transaction manager will depends on btmConfig and dataSource1, then before initialize the BTM transaction manager, the btmConfig and dataSource should be initialized first.
DataSource1 configuration is same as described in Chapter 3.1.
btmConfig defines the BTM configurations which are introduced in Chapter 2.2. we can define more properties when necessary, but generally, we do not need to define it, as BTM has already provided the meaningful default value.
-
Configure Persistence
Different from the configuration described in Chapter 2.6, the persistence configuration including the EMF, JpaVendor, persistence-unit, should refer to the Chapter 3 of JPA lesson document - http://192.168.18.224:8888/svn/Work_Space/Research/scarlett/booking-service/doc/JPA_lesson_v2.2.doc
-
Enable Transaction In DAO
With Spring, developers do not need to handle the underlying transaction management APIs in DAO, Spring provides a consistent abstraction across different transaction management APIs. For BTM transaction, we do not need to handle the transaction as Chapter 2.6 does, instead we will use the Spring way to manage the transaction.
Spring supports programmatic transaction management and declarative transaction management, with Spring's declarative transaction management, the applicaton code is non- invasived and least impacted. So In our application, we choose the declarative transaction management.
3.4.1 Three Ways Of Setting Declarative Transaction
Spring supports declarative transaction management through the Spring AOP framework, there are three ways to set a declarative transaction.
When in Spring 1.x, it provides a classic around advice called TransactionInterceptor for transaction management.
When come to Spring 2.x, it offers a new AOP approach which can be easily configured via the <tx:advice> element.
Declaring declarative transaction in the bean configuration file requires the knowledge of AOP concepts such as pointcuts, advices. Developers who lack this knowlesge might find it hard to set.
In addtion to above two ways, Spring also allows to declare transactions simply by annotating your transactional methos or class with @Transactional and enabling the <tx:annotation- driven> element.
Actually we choose the annotation driven way in our application.
3.4.2 Enable Annotation Driven Declarative Transaction
In the Spring application context configuration file, we enable the <tx:annotation-driven> element.
e.g.
<tx:annotation-driven transaction-manager="txManager" />
<bean id="start" class="com.sample.Start" />
The <tx:annotation-driven> configuration will enable the Spring annotation driven mechanism.transaction-manager points to the Spring JtaTransactionManager we have configured in Chapter 3.2.
The transactional bean com.sample.Start should be configured here then Spring container can create an instance of it and manager it.
Then in the transactional DAO com.sample.Start, we should set the @Transactional annotation.
e.g.
@Transactional(
propagation = Propagation.REQUIRED,
isolation = Isolation.DEFAULT
)
publicclass Start {…}
We can set the @Transactional annotation on one class, then all the public non-static methods of this class will be transactional. We also can set the @Transactional annotation dcirectly on one public non-static method to just enable this method.
Finally, when we call the DAO to access data source, we need to get the DAO instance from Spring container.
e.g.
…
//get the managered bean
Start s = (Start) ctx.getBean("start");
s.start(bookingList);
The ctx refers to the Spring ApplicationContext, after Spring container start up, it can get the container managed bean com.sample.Start, if it is annotated with @Transactional, then the transaction will be applied to this method when it is executed.
Spring offers two ways for programmatic transaction management, one is using PlatformTransactionManager API, another is to use TransactionTemplate. For how to use programmatic transaction management and how to configure declarative transaction management in other ways, pls refer to Chapter 11 of Spring reference manual - http://192.168.18.224:8888/svn/Work_Space/Research/scarlett/booking-service/doc/spring-framework-reference.pdf
-
Transaction Attribute Setting
3.5.1 Propagation
Propagation defines how the transaction should be propagated when a transactional method is called by another method.
Spring supports 7 propagation behaviors:
REQUIRED: if there is an existing transaction in progress, the current method should run within this transaction. Otherwise, it should start a new transaction and run within it.
REQUIRES_NEW: the current method must start a new transaction and run within it, there is exsting transaction in progress, it should be suspended.
SUPPORTS: If there’s an existing transaction in progress, the current method can run within this transaction. Otherwise, it is not necessary to run within a transaction.
NOT_SUPPORTED: The current method should not run within a transaction. If there’s an existing transaction in progress, it should be suspended.
MANDATORY: The current method must run within a transaction. If there’s no existing transaction In progress, an exception will be thrown.
NEVER: The current method should not run within a transaction. If there’s an existing transaction in progress, an exception will be thrown.
NESTED: If there’s an existing transaction in progress, the current method should run within the nested transaction (supported by the JDBC 3.0 save point feature) of this transaction. Otherwise, it should start a new transaction and run within its own transaction.
Propagation behavior is very important and meaningful. When a method is called by another method, if the method will not update database but only read from database, it is necessary to set the transaction propagation to NOT_SUPPORTED to make sure the method will not be involved in a transaction in order to improve the efficiency. When two methods are called by another method, if want the two methods to process as a unit of work which will both update seccessfully or both rollback when either one fails, we have to set the propagation to REQUIRED to make sure they run in one transaction. When a method is transactional or not depends on how it is later used, we can set the propagation to SUPPORTS to allow it to be either in a transaction or not in a transaction according to the caller, this can help make ease of modulization.
Spring's default propagation behavior is REQUIRED. We can set different propagation behavior according to situation. Below is an example of how to set propagation behavior when using Spring annotation driven declarative transaction management.
e.g.
@Transactional(
propagation = Propagation.REQUIRES_NEW
)
3.5.2 Isolation
Isolation defines how one transaction is isolated from another. When two transaction are operating on the same dataset, the isolation behavior is important.
Spring supports 5 isolation levels:
DEFAULT: Uses the default isolation level of the underlying database. For most databases, the default isolation level is READ_COMMITTED.
READ_UNCOMMITTED: Allows a transaction to read uncommitted changes by other transactions.
READ_COMMITTED: Allows a transaction to read only those changes that have been committed by other transactions.
REPEATABLE_READ: Ensures that a transaction can read identical values from a field multiple times. For the duration of this transaction, updates made by other transactions to this field are prohibited.
SERIALIZABLE: Ensures that a transaction can read identical rows from a table multiple times. For the duration of this transaction, inserts, updates, and deletes made by other transactions to this table are prohibited.
The transaction isolation should be supported by the underling database, MySQL InnoDB default isolation level is REPEATABLE_READ. It supports 4 isolation levels described by the SQL standard: READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE
Below is an example of how to set isolation behavior when using the Spring annotation driven declarative transaction management.
e.g.
@Transactional(
isolation = Isolation.DEFAULT
)
3.5.3 Rollback
Rollback defines if the transaction will be rolled back for a specific exception. By default only unchecked excepton will cause rollback, checked exception will not. But you can change the rollback behavior by setting rollback attribute. Any exceptions not explicitly specified in this attribute will be handled by the default rollback rule.
A transaction's rollback rule can be defined via the rollbackFor and noRollbackFor attributes. Below is an example of how to set rollback behavior when using Spring annotation driven declarative transaction management.
e.g.
@Transactional(
rollbackFor = IOException.class,
noRollbackFor = ArithmeticException.class
)
3.5.4 Timeout
Timeout attribute indicates how long the transaction can survive before it is forced to roll back. This can prevent a long transaction from tying up resources.
Below is an example of how to set Timeout behavior when using Spring annotation driven declarative transaction management. The timeout is measured in seconds.
e.g.
@Transactional(
timeout = 30
)
3.5.5 Read-Only
Read-Only attribute indicates that this transaction will only read but not update data.
Below is an example of how to set Read-Only behavior when using Spring annotation driven declarative transaction management.
e.g.
@Transactional(
readOnly = true
)
3.6 Current Application Configuration
Above have described how to use BTM JTA with Spring, and our current application just use this framework, we have given out some snippet of the configuration, for the complete JTA configuration of current application, can refer to below.
3.6.1 Spring Bean Configuration
<!-- Configure the data source for database DroolsTasks -->
<bean id="dataSource" class="bitronix.tm.resource.jdbc.PoolingDataSource" init- method="init" destroy-method="close">
<property name="className" value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource" />
<property name="driverProperties" >
<props>
<prop key="URL">jdbc:mysql://localhost:3306/DroolsTasks</prop>
<prop key="user">root</prop>
<prop key="password">ACahlof</prop>
</props>
</property>
<property name="uniqueName" value="jdbc/task" />
<property name="minPoolSize" value="0" />
<property name="maxPoolSize" value="5" />
</bean>
<!-- Configure the data source for database Bookings -->
<bean id="dataSource1" class="bitronix.tm.resource.jdbc.PoolingDataSource" init- method="init" destroy-method="close">
<property name="className" value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource" />
<property name="driverProperties" >
<props>
<prop key="URL">jdbc:mysql://localhost:3306/Bookings</prop>
<prop key="user">root</prop>
<prop key="password">ACahlof</prop>
</props>
</property>
<property name="uniqueName" value="jdbc/booking" />
<property name="minPoolSize" value="0" />
<property name="maxPoolSize" value="3" />
</bean>
<!-- Enable the annotation driven mechanism -->
<tx:annotation-driven transaction-manager="txManager" />
<!-- Configure the Spring JtaTransactionManager -->
<bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManager" ref="bitronixTransactionManager"/>
<property name="userTransaction" ref="bitronixTransactionManager"/>
</bean>
<!-- Configure the BTM TransactionManager -->
<bean id="bitronixTransactionManager" factory-method="getTransactionManager"
class="bitronix.tm.TransactionManagerServices"
depends-on="dataSource,dataSource1" destroy-method="shutdown"/>
<!-- Configure the transactional DAO -->
<bean id="start" class="com.sample.Start" />
3.6.2 Transaction DAO Setting
@Transactional(
propagation = Propagation.REQUIRED,
isolation = Isolation.DEFAULT,
timeout = 30,
readOnly = true
)
publicclass Start {
publicvoid start(List<BookingBasic> bookingList){
…
}
}
3.6.3 Invoke Transaction DAO
publicstaticvoid main(String[] args) {
//initialize the Spring container
ApplicationContext ctx = new FileSystemXmlApplicationContext("applicationContext.xml");
((AbstractApplicationContext) ctx).registerShutdownHook();
//get the managered bean
Start s = (Start) ctx.getBean("start");
…
//call the bean's method
s.start(bookingList);
…
}
-
DataSource And Connection
With BTM PoolingDataSource configured in Spring bean configuration file(refer to Chapter 3.6.1), two database connections will be created and stored in the connection pool when Spring container initializes. One connection refers to resource dataSource, the other connection refers to resource dataSource1.
With this BTM JTA setting and the EMF setting documented in the JPA lesson, we have done some testing about EMF and connection, EMF referring to dataSource(dataSource1) will use the connection also referring to dataSource(dataSource1), more lessons we have learnt and the dos and don'ts we suggested are listed in the Chapter 4.4 of the JPA lesson - http://192.168.18.224:8888/svn/Work_Space/Research/scarlett/booking-service/doc/JPA_lesson_v2.2.doc