As of Spring Roo 1.1.3, both entity
and persistence
setup
commands support the persistenceUnit
argument which lets you create enterprise applications which interact with multiple databases. In this recipe we'll create two persistent units:
flight
: the flight
persistence unit consists of a single entity, Flight
. It uses Hibernate as a JPA provider and maps to a MySQL database named "myFlightDB".payment
: the payment
persistence unit consists of a single entity, Payment
. It uses Hibernate as the JPA provider and maps to a MySQL database named "myPaymentDB".Exit the Roo shell and delete the contents of the C:
oo-cookbookch02-recipes
directory.
Start the Roo shell from the C:
oo-cookbookch02-recipes
directory.
The following steps will demonstrate how to create an application that interacts with multiple databases:
flight-app
Roo project:..roo> project --topLevelPackage sample.roo.flightapp --java 6 --projectName flight-app
flight
persistence unit:..roo> persistence setup --provider HIBERNATE --database MYSQL --databaseName myFlightDB --persistenceUnit flight
Flight
entity, which is associated with the flight
persistence unit:..roo> entity --class ~.domain.Flight --table FLIGHT_TBL --persistenceUnit flight
Flight
entity:~.domain.Flight roo> field string --fieldName origin --column FLT_ORIGIN --notNull ~.domain.Flight roo> field string --fieldName destination --column FLT_ DESTINATION --notNull
Flight
entity:~.domain.Flight roo> test integration
payment
persistence unit:.. roo> persistence setup --provider HIBERNATE --database MYSQL --databaseName myPaymentDB --persistenceUnit payment
Payment
entity, which is associated with the payment
persistence unit:.. roo> entity --class ~.domain.Payment --table PAYMENT_TBL --persistenceUnit payment
Payment
entity:~.domain.Payment roo> field string --fieldName paymentType --column PYMT_TYPE --notNull
Payment
entity:~.domain.Payment roo> test integration
perform
eclipse
command to import the flight-app
project into Eclipse IDE:~.domain.Payment roo> perform eclipse
.. roo> perform tests
Executing the integration tests at this time will result in failure. We'll shortly see what we need to do to get the tests working when using multiple databases.
The concept of a persistence unit is not only useful when the enterprise application interacts with multiple databases but also when you want to logically group entities in your application. Using different persistence units can also be useful if you want to use different persistence providers for different logical groups of entities.
When setting up a persistence provider using the persistence
setup
command you can specify the persistence unit name by specifying the persistenceUnit
argument. Also, when creating entities using the entity
command you can use the persistenceUnit
argument to specify the persistence unit to which the entity belongs. Spring Roo makes use of the persistenceUnit
argument of the persistence
setup
command to define a different persistence unit in the /META-INF/persistence.xml
file. The following listing shows the persistence.xml
file of the flight-app
project after the execution of the persistence
setup
commands:
<persistence ..> <persistence-unit name="flight" transaction-type="RESOURCE_LOCAL"> <provider> org.hibernate.ejb.HibernatePersistence </provider> .. </persistence-unit> <persistence-unit name="payment" transaction-type="RESOURCE_LOCAL"> <provider> org.hibernate.ejb.HibernatePersistence </provider> .. </persistence-unit> </persistence>
In the code, the name
attribute of the <persistence-unit>
element reflects the persistenceUnit
argument value that you specified in the persistence
setup
command. As we have specified Hibernate as the JPA provider for both flight
and payment
persistent units, the <provider>
element contains org.hibernate.ejb.HibernatePersistence
as the JPA provider. If you want to use different JPA providers for your persistence unit, then specify it using the provider
argument of the persistence
setup
command.
As we are using different persistence units, the entities created using the entity
command use the persistenceUnit
attribute to identify the persistence unit with which the entity is associated. The following code listing shows that the persistenceUnit
argument value is used in the @RooEntity
annotation of the Flight
class:
@RooJavaBean
@RooToString
@RooEntity(persistenceUnit = "flight", table = "FLIGHT_TBL")
public class Flight {..}
In the code, the value of the persistenceUnit
attribute of @RooEntity
is flight
, which affects the way Roo generates the corresponding *_Roo_Entity.aj
AspectJ ITD file. The following code listing shows the affect of persistenceUnit
attribute of @RooEntity
annotation on the Flight_Roo_Entity.aj
ITD file:
privileged aspect Flight_Roo_Entity { @PersistenceContext(unitName = "flight") transient EntityManager Flight.entityManager; ... @Transactional("flight") public void Flight.persist() {..} @Transactional("flight") public void Flight.remove() {..} ... }
In the code, the @PersistenceContext
annotation makes use of the unitName
attribute to specify the persistence unit with which the EntityManager
persistence context is associated with. Also, notice that the @Transactional
annotation now makes use of the flight
qualifier to specify the transaction manager required for managing transactions.
As of Spring Roo 1.1.3, you'll have to ensure that the transaction manager, entity manager factory, and data source bean definitions for each persistence unit are configured in the /META-INF/spring/applicationContext.xml
file, as shown here:
<bean class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" id="flightDataSource"> .... </bean> <bean class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" id="paymentDataSource"> .... </bean> <bean class="org.springframework.orm.jpa.JpaTransactionManager" id="flightTransactionManager"> <qualifier value="flight"/> <property name="entityManagerFactory" ref="flightEntityManagerFactory"/> </bean> <bean class="org.springframework.orm.jpa.JpaTransactionManager" id="paymentTransactionManager"> <qualifier value="payment"/> <property name="entityManagerFactory" ref="paymentEntityManagerFactory"/> </bean> <tx:annotation-driven mode="aspectj" transaction-manager="flightTransactionManager"/> <tx:annotation-driven mode="aspectj" transaction-manager="paymentTransactionManager"/> <bean class="org.springframework.orm.jpa. LocalContainerEntityManagerFactoryBean" id="flightEntityManagerFactory"> <property name="persistenceUnitName" value="flight"/> <property name="dataSource" ref="dataSource"/> </bean> <bean class="org.springframework.orm.jpa. LocalContainerEntityManagerFactoryBean" id="paymentEntityManagerFactory"> <property name="persistenceUnitName" value="payment"/> <property name="dataSource" ref="dataSource"/> </bean>
The code shows that different transaction managers, entity manager factories, and data source beans are configured for each persistence unit. The transaction manager bean definitions make use of the <qualifier>
element, so that @Transactional
annotations can refer to the target transaction manager using a qualifier. Also, the LocalContainerEntityManagerFactoryBean
is passed the persistence unit name with which it is associated, using the persistenceUnitName
property.
To ensure that integration tests work, you'll also need to specify the transaction manager to use for the test methods annotated with the @Transactional
annotation. To achieve this, all you need to do is specify the @Transactional
annotation in your test class, as shown here for PaymentIntegrationTest
class:
@RooIntegrationTest(entity = Payment.class)
@Transactional("payment")
public class PaymentIntegrationTest {
@Test
public void testMarkerMethod() {
}
}
18.216.96.94