tl;dr To configure JPA in Spring via Hibernate, you wire up one of the classes provided by Spring that creates a bean of type EntityManagerFactory which then makes EntityManager available for you. There are two types of Entity Managers, and the class you wire up depends on which Entity Manager factory you would be using. We have Application Managed and Container Managed Entity Managers.
This post gives an overview of how to configure Hibernate as a JPA implantation, for use in a Spring application. It is part of the Configuring Spring Series.
In Configuring Hibernate in Spring Framework, we saw that in other to talk to the database via Hibernate, your application code would do so via Spring's implementation of Hibernate's main interface: org.hibernate.Session which is made available via an implementation of org.hibernate.SessionFactory. And the process of configuration is just a process of wiring up Spring's to provide this needed SessionFactory as a bean.
You have a similar procedure when it comes to configuring Hibernate JPA in Spring.
Instead of working with a SessionFactory, you work with EntityManagerFactory. And instead of Hibernates' Session you have EntityManager through which the actual database access is done.
The process of configuring Hibernate JPA in Spring hence, is all about wiring the Spring bean that would make available for you the EntityManagerFactory.
Before we get to the business of actual configuration, let's get some key concept's explained.
Types of EntityManagers
There are two types of EntityManagers. Application Managed and Container Managed the difference between these two lie not in their nature (they are technically the same as they both implement the EntityManager interface), but in how they are created. An Application Managed EntityManager are the type that are created when an application directly request one from the EntityManagerFactory while a Container Managed EntityManager are the type that are created by a Java EE container and then made available to your application code via dependency injection or via JNDI.
With Application Managed EnityManager, the application is concerned with managing the Entity Manager after creation; ie. opening and closing etc. With Container Managed, this task is delegated to the container that provides it.
Technically this difference is not much of a concern when working with Hibernate JPA via Spring as Spring plays the role of "the application" when an Application Managed EntityManager is needed and also "the Container", in case of Container Managed EntityManager. The only thing to be aware of is the slight difference in the configuration process for these two types of Entity Managers.
Persistence.xml and Persistence Unit
Hibernate (via JPA or not) is an ORM tool; meaning it bridges the domain between Object Oriented Programming and the Relational domain of databases; making an OOP developer interact with relational database as if it was still in the OOP domain. Working with such a tool requires what is usually referred to as Entity Classes. Which are representation of database tables via Java classes and whose instances can be stored in a database. You can read Understanding Entity Relationship Mapping, Part 1: The basic concepts for some more fundamental discuss on Entity and relationship mapping between Entities.
A Persistence Unit in JPA is therefore a logical grouping of one or more of these Entity Classes together with any required extra configuration needed to work with them e.g. the data source or the ORM mapping file in case where XML based mapping is used.
The Persistence Unit is defined in the persistence.xml file, which must be located in the META-INF directory within the class path.
A typical persistence.xml file may look thus:
<pre><persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence">
<persistence-unit name="mySpringApp">
<class>com.MyApp.Enitity.Person</class>
<class>com.MyApp.Enitity.Votes</class>
<properties>
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"></property>
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/jpatestdb"></property>
<property name="javax.persistence.jdbc.user" value="root"></property>
<property name="javax.persistence.jdbc.password" value="root"></property>
</properties>
</persistence-unit>
</persistence>
</pre>
In the persistence.xml above, two Entity classes are defined: com.MyApp.Enitity.Person and com.MyApp.Enitity.Votes, while additional configuration is provided within the
@PersistenceUnit and @PersistenceContext
The PersistenceContext is a cache. it is the representation in memory, of the database.
It has already being pointed out that when using Hibernate JPA, you work with the EntityManager. The EntityManager is actually a PersistenceContext; or in another words, the EntityManager is a cache. It is the representation of your database state in memory and it is this representation that your application code manipulates.
And like any other kind of cache, to make modifications to the cache lasting, it needs to be flushed; which is basically moving the modification into a persistent facility: a database, file system etc.
When working with Application Managed Entity Managers, the EntityManagerFactory that makes the EntityManager available for your code can be injected via the @PeristenceUnit annotation while in case of Container Managed Entity Managers, the EntityManager can be injected to your code via @PersistenceContext
Note the difference: With Application Managed Entity Managers, your application gets the EntityManagerFactory via @PeristenceUnit from which you have to manually create (by calling the createEntityManager method) and manage an EntityManager. In the case of Container Managers Entity Managers, on the other hand, the EntityManager is created already and handed to your application code via @PersistenceContext. This is in line with the difference between the two Entity Manager as already explained.
With these concepts explained and out of the way, we can now look into how you do the actual configuration.
The configuration differs depending on whether you are configuring a Application Managed Entity Manager or a Container Managed Entity Manager.
Dependencies
I am using Maven as dependency manager, and as such the POM file to enable the configuration example to work would include these dependencies
<dependencies>
<dependency>
<groupid>org.springframework</groupid>
<artifactid>spring-core</artifactid>
<version>4.0.3.RELEASE</version>
</dependency>
<dependency>
<groupid>org.springframework</groupid>
<artifactid>spring-context</artifactid>
<version>4.0.3.RELEASE</version>
</dependency>
<dependency>
<groupid>org.springframework</groupid>
<artifactid>spring-orm</artifactid>
<version>4.0.3.RELEASE</version>
</dependency>
<dependency>
<groupid>org.hibernate</groupid>
<artifactid>hibernate-core</artifactid>
<version>4.3.4.Final</version>
</dependency>
<dependency>
<groupid>org.hibernate</groupid>
<artifactid>hibernate-entitymanager</artifactid>
<version>4.3.4.Final</version>
</dependency>
<dependency>
<groupid>mysql</groupid>
<artifactid>mysql-connector-java</artifactid>
<version>5.1.23</version>
</dependency>
<!-- As from Spring 4 this is actually no longer needed as Spring now comes with cglib -->
<dependency>
<groupid>cglib</groupid>
<artifactid>cglib</artifactid>
<version>3.1</version>
</dependency>
</dependencies>
Make sure you have these dependencies in whatever dependency management tool you are using.
Configuring Application Managed Entity Manager
To get this flavor of EntityManager, you do so by configuring the corresponding Spring factory bean: The LocalEntityManagerFactoryBean, which is responsible for producing an Application Managed Entity Manager.
Configuring the LocalEnityManagerFactoryBean requires the presence of a persistence.xml file. So using the persistence.xml file already defined above, configuring the LocalEntityManagerFactoryBean would look thus:
<bean class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean" id="entityManagerFactory">
<property name="persistenceUnitName" value="mySpringApp">
</property></bean>
The value of persistenceUntiName above, mySpringApp, refers to the persistence name defined in the persistence.xml
Configuring Container Managed Entity Manager
The bean configuration for Container Managed Entity Manager has more to it compared to the bean configuration for Application Managed Entity Managers. There are quite a couple of options that the configuration can specify. Would highlight some of this based on what function they perform.
We have the part of the configuration that specifies:
1. The Data Source
2. The JPA implementation that would be used. ie. the vendor via jpaVendorAdapter
3. The specific JPA properties via jpaProperties
4. The database access configuration in case Data Source is not used
5. And the configuration that specifies the path to scan for Entities (this applies when persistence.xml is not used)
So a typical configuration would look thus:
<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="entityManagerFactory">
<!-- the data source -->
<property name="dataSource" ref="dataSource"></property>
<!-- configuration that specifies the JPA Adapter to use -->
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
</bean></property>
<!-- configuration to specify JPA behaviors -->
<property name="jpaProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">create-drop</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
</props>
</property>
</bean>
in case dataSource is not used, the required configuration can be provided inline: i.e.
<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="entityManagerFactory">
<!-- configuration needed in place of data source -->
<property name="database" value="HSQL"></property>
<property name="showSql" value="true"></property>
<property name="generateDdl" value="false"></property>
<property name="databasePlatform" value="org.hibernate.dialect.HSQLDialect"></property>
<!-- configuration that specifies the JPA Adapter to use -->
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"></bean>
</property>
<!-- configuration to specify JPA behaviors -->
<property name="jpaProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">create-drop</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
</props>
</property>
</bean>
This configuration requires that persistence.xml is in META-INF. It is possible to out rightly omit the persistence.xml file. This is possible starting from Spring 3.1, in which case you now need to specify the path Spring should search within to find Entity classes. This you do using the packagesToScan property. The configuration would then look like
<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="entityManagerFactory">
<property name="dataSource" ref="dataSource"></property>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
</bean></property>
<property name="jpaProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">create-drop</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
</props>
</property>
<!-- configuration that specifies where Entity Classes should be picked from when persistence.xml is omitted -->
<property name="packagesToScan">
<list>
<value>my.package.name</value>
<value>my.anotherpackage.name</value>
</list>
</property>
</bean>
A quick tip to actually know the available properties to configure for the bean (or any other bean for that matter) is to check the Javadoc of the classes you want to configure as a bean. The setter methods gives away the available properties that can be configured.
Retrieving EntityManager For Use
Once the configuration is done, retrieving an EntityManager for use is as simple as you would retrieve any other bean. You could either retrieve the bean from the context manually or via annotations. You can read Configuring Beans in Spring Framework for some information on how this process works.
In case you would be retrieving the bean via annotations, then @PersistenceContext is the annotation to use to enable this "auto wiring".
An annotated class can then look like this
@Repository class PersonDao() { @PersistenceContext public EntityManager em public void save(Person person) { em.persist(person); } .... }
No comments:
Post a Comment