5.3. Using JPA
- PersistenceUnit Deployed by the Container
- PersistenceUnit Created by Spring
- PersistenceContext and PersistenceUnit Injection
5.3.1. PersistenceUnit Deployed by the Container
web.xml file.
persistence.xml file:
Example 5.6. Persistence Unit Definition
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0"> <persistence-unit name="sportsclubPU"> <jta-data-source>java:jboss/datasources/ExampleDS</jta-data-source> </persistence-unit> </persistence>
Example 5.7. Persistence context binding in JNDI
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" metadata-complete="true"> <persistence-context-ref> <persistence-context-ref-name>example/em</persistence-context-ref-name> <persistence-unit-name>sportsclubPU</persistence-unit-name> </persistence-context-ref> </web-app>
Example 5.8. Spring Bean Representing a Container-managed Entity manager
<jee:jndi-lookup id="entityManager" jndi-name="java:comp/env/example/em"/>
Example 5.9. Hibernate-based DAO: a SessionFactory is Injected Directly in the Bean
public class HibernateAccountDao { @Autowired EntityManager entityManager; public List<Account> getAllAccounts() { return entityManager.createQuery("SELECT a FROM Account").getResultList(); } ... }
Example 5.10. Persistence unit binding in JNDI
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" metadata-complete="true"> <persistence-unit-ref> <persistence-unit-ref-name>example/emf</persistence-unit-ref-name> <persistence-unit-name>sportsclubPU</persistence-unit-name> </persistence-unit-ref> </web-app>
Example 5.11. Spring Bean Representing an Entity Manager Factory
<jee:jndi-lookup id="entityManagerFactory" jndi-name="java:comp/env/example/emf"/>
5.3.2. PersistenceUnit Created by Spring
Example 5.12. A Spring Method Declaring a Read-Only Transaction
@Transaction(readOnly = true) public List<Account> getAllAccounts() { return entityManager.createQuery("SELECT a FROM Account").getResultList(); }
@Transactional(readOnly=true) flag causes Spring to allow it. Application performance increases as the persistence context is discarded at the end of the transaction. Support for this mode is not obligatory in Spring, and applications are not expected to rely on this behaviour at all times.
Example 5.13. A Spring-defined JTA-based Entity Manager Factory
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="jpaVendorAdapter"> <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/> </property> <property name="jpaProperties"> <props> <prop key="hibernate.transaction.jta.platform"> org.hibernate.service.jta.platform.internal.JBossAppServerJtaPlatform </prop> </props> </property> </bean>
META-INF/persistence.xml file, which contains the persistence unit definition, to be present in the deployment. JBoss Enterprise Application Platform automatically deploys the persistence unit from the persistence.xml file. However, if you require to create a Spring-based EntityManager rather than use the container-managed EntityManagerFactory, prevent JBoss Enterprise Application Platform from deploying the persistence unit. Use one of the following methods to achieve this:
- Configuring JBoss Enterprise Application Platform to not create EntityManagerFactory
- Renaming or moving the
persistence.xmlfile
persistence.xml file, set the value of jboss.as.jpa.managed property to false. This stops JBoss Enterprise Application Platform from creating the EntityManagerFactory. By default, this property is set to true, which enables container managed JPA access to the persistence unit.
Example 5.14. Configuring JBoss Enterprise Application Platform to not create EntityManagerFactory
<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd" version="2.0"> <persistence-unit name="bookingDatabase"> <provider>org.hibernate.ejb.HibernatePersistence</provider> <class>org.springframework.webflow.samples.booking.User</class> <class>org.springframework.webflow.samples.booking.Booking</class> <class>org.springframework.webflow.samples.booking.Hotel</class> <properties> <property name="jboss.as.jpa.managed" value="false"/> <!-- other properties (omitted) --> </properties> </persistence-unit> </persistence>
persistence.xml file and use the persistenceXmlLocation property as follows:
Example 5.15. Renaming or moving the Persistence.xml file
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="persistenceXmlLocation" value="classpath*:META-INF/persistence-booking.xml"/> </bean>
persistence.xml file is located or what it is called, the WEB-INF/classes location is not scanned for persistent entries when the LocalContainerManagedEntityFactoryBean is used. In this case, the list of entities must be provided explicitly through one of the following methods:
- By enumerating the persistent classes in the
persistence.xmlfile (or other persistence unit configuration file name) - By packaging the entities in a JAR file and providing a <jar-file/> configuration entry in the
persistence.xmlfile - Using a PersistenceUnitPostprocessor
Example 5.16. Example of a PersistenceUnitPostProcessor Implementation That Adds all Classes Annotated with @Entity
package org.springframework.webflow.samples.booking; import java.io.IOException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.io.Resource; import org.springframework.core.io.support.ResourcePatternResolver; import org.springframework.core.type.classreading.CachingMetadataReaderFactory; import org.springframework.core.type.classreading.MetadataReader; import org.springframework.orm.jpa.persistenceunit.MutablePersistenceUnitInfo; import org.springframework.orm.jpa.persistenceunit.PersistenceUnitPostProcessor; public class MyPersistenceUnitPostProcessor implements PersistenceUnitPostProcessor { @Autowired private ResourcePatternResolver resourceLoader; public void postProcessPersistenceUnitInfo(MutablePersistenceUnitInfo mutablePersistenceUnitInfo) { try { Resource[] resources = resourceLoader.getResources("classpath:org/myexample/*.class"); for (Resource resource : resources) { CachingMetadataReaderFactory cachingMetadataReaderFactory = new CachingMetadataReaderFactory(); MetadataReader metadataReader = cachingMetadataReaderFactory.getMetadataReader(resource); if (metadataReader.getAnnotationMetadata().isAnnotated(javax.persistence.Entity.class.getName())) { mutablePersistenceUnitInfo.addManagedClassName(metadataReader.getClassMetadata().getClassName()); } } mutablePersistenceUnitInfo.setExcludeUnlistedClasses(true); } catch (IOException e) { throw new RuntimeException(e); } } }
Example 5.17. Adding the PersistenceUnitPostProcessor to the Context Definition
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <!-- other properties --> <property name="persistenceUnitPostProcessors"> <list> <bean class="org.springframework.webflow.samples.booking.MyPersistenceUnitPostProcessor"/> </list> </property> </bean>
5.3.3. PersistenceContext and PersistenceUnit Injection
persistence.xml file to use a Spring-based EntityManagerFactory. However, the presence of @PersistenceContext or @PersistenceUnit annotations in Spring can cause deployment errors when the persistence.xml file is renamed. The errors occur because in a Java EE 6 environment, the @PersistenceContext and @PersistenceUnit annotations are used for supporting the container-driven injection of container-managed persistence contexts and persistence units, respectively. During deployment, Red Hat JBoss Enterprise Application Platform scans the deployment classes and validates for the presence of such annotations, the corresponding managed persistence units exist as well. This is not the case if the persistence.xml file is renamed.
Example 5.18. Metadata-complete Flag to Disable Class Scanning by Red Hat JBoss Enterprise Application Platform
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" metadata-complete="true">
Example 5.19. SharedEntityManager Bean to Create an Injectable Transaction-aware EntityManager
<bean id="entityManagerWrapper" class="org.springframework.orm.jpa.support.SharedEntityManagerBean"> <property name="entityManagerFactory" ref="entityManagerFactory"/> </bean>