Java Persistence Example with Spring, JPA2 and Hibernate


Octocat **Promotion** - Efficiently manage your coding bookmarks, aka #codingmarks, on www.codingmarks.org and share your hidden gems with the world. They will be published weekly on Github. Please help us build THE programming-resources location - Star


This is sort of a follow up post for a previous post of mine – RESTful Web Services Example in Java with Jersey, Spring and MyBatis. It is based on the same example application, which, via a REST API, can execute CRUD operations against a single Podcasts table. If in the first post the focus was on how to build the REST API with Jersey, this time it is on the data persistence layer. I will present how to implement a container-agnostic persistence layer with JPA2/Hibernate, being glued in the application via Spring.

1. Architecture and technologies

1.1. Architecture

Example architecture

1.2. Technologies used

  1. Jersey 2.4
  2. Spring 3.2
  3. JPA 2
  4. Maven 3
  5. Tomcat 7
  6. Jetty 9
  7. MySql 5.6
  8. Hibernate 4

2. Source Code

If you want to follow along, you find all you need on GitHub:

  • https://github.com/amacoder/demo-restWS-spring-jersey-jpa2-hibernate
  • MySQL DB creation self-contained file – everything is configured for the username/password : rest_demo/rest_demo
  • 3. The coding

    3.1. Configuration

    3.1.1. Project dependencies

    I use Maven to build the project. In addition to Spring Core and persistence dependencies, we also need to define Hibernate in the pom.xml:

      
        <!-- ******* JPA/Hibernate ******** -->
        <dependency>
        	<groupId>org.hibernate</groupId>
        	<artifactId>hibernate-core</artifactId>
        	<version>${hibernate.version}</version>
        </dependency>
        <dependency>
        	<groupId>org.hibernate.javax.persistence</groupId>
        	<artifactId>hibernate-jpa-2.0-api</artifactId>
        	<version>1.0.1.Final</version>
        </dependency>
        <dependency>
        	<groupId>org.hibernate</groupId>
        	<artifactId>hibernate-entitymanager</artifactId>
        	<version>${hibernate.version}</version>
        </dependency>
      
    

    Code alert: If you want to see what other dependencies (Jersey, Spring, Jetty, testing etc.) are used in the project or how the jetty-maven-plugin is configured so that you can start the project in Jetty directly from Eclipse, you can download the complete pom.xml file from GitHub – https://github.com/amacoder/demo-restWS-spring-jersey-jpa2-hibernate/blob/master/pom.xml

    3.1.2. Spring application context configuration

    The Spring application context configuration is located at classpath:spring/applicationContext.xml:

      
        <beans xmlns="http://www.springframework.org/schema/beans"
        	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        	xmlns:context="http://www.springframework.org/schema/context"
        	xmlns:tx="http://www.springframework.org/schema/tx"
        	xsi:schemaLocation="
        		http://www.springframework.org/schema/beans
        		http://www.springframework.org/schema/beans/spring-beans.xsd
    
        		http://www.springframework.org/schema/tx
        		http://www.springframework.org/schema/tx/spring-tx.xsd
    
        		http://www.springframework.org/schema/context
        		http://www.springframework.org/schema/context/spring-context.xsd">
    
        	<context:component-scan base-package="org.codingpedia.demo.rest.*" />
    
        	<!-- ************ JPA configuration *********** -->
        	<tx:annotation-driven transaction-manager="transactionManager" />
            <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
                <property name="entityManagerFactory" ref="entityManagerFactory" />
            </bean>
            <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
                <property name="persistenceXmlLocation" value="classpath:config/persistence-demo.xml" />
                <property name="dataSource" ref="restDemoDS" />
                <property name="packagesToScan" value="org.codingpedia.demo.*" />
                <property name="jpaVendorAdapter">
                    <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                        <property name="showSql" value="true" />
                        <property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect" />
                    </bean>
                </property>
            </bean>
    
        	<bean id="podcastDao" class="org.codingpedia.demo.rest.dao.impl.PodcastDaoJPA2Impl"/>
            <bean id="podcastRestService" class="org.codingpedia.demo.rest.service.PodcastRestService" >
            	<property name="podcastDao" ref="podcastDao"/>
            </bean>
    
        	<bean id="restDemoDS" class="org.springframework.jndi.JndiObjectFactoryBean" scope="singleton">
        	    <property name="jndiName" value="java:comp/env/jdbc/restDemoDB" />
        	    <property name="resourceRef" value="true" />
        	</bean>
        </beans>
      
    

    Relevant JPA beans:

  • transactionManager – note that the transaction manager used is JpaTransactionManager, instead of the DataSourceTransactionManager, which was the case when building the persistence layer with MyBatis.
  • entityManagerFactory – the LocalContainerEntityManagerFactoryBean gives full control over EntityManagerFactory configuration and is appropriate for environments where fine-grained customization is required. It is a FactoryBean that creates a JPA EntityManagerFactory according to JPA’s standard container bootstrap contract. This is the most powerful way to set up a shared JPA EntityManagerFactory in a Spring application context; the EntityManagerFactory can then be passed to JPA-based DAOs via dependency injection.
    • persistenceXmlLocation – Set the location of the persistence.xml file we want to use. This is a Spring resource location. Default is classpath:META-INF/persistence.xml.
    • jpaVendorAdapter – the HibernateJpaVendorAdapter setup to recognize the MySQL dialect

    Note that switching to a JNDI lookup or to a LocalEntityManagerFactoryBean definition, which are the other two options to setup JPA in a Spring environment, is just a matter of configuration!

  • 3.2. The Data Persistence layer

    As mentioned before the data persistence layer permits CRUD operations against the database and is triggered via REST requests.

    There have been lots of discussions whether using DAOs is still relevant when using JPA – you can find some resources on this topic at the end of the post. I, for one, still employ DAOs, as I don’t like my service classes cluttered with EntityManager/JPA specific code. What if I want to use MyBatis or other persistence technology?

    So the contract between the service layer and the data persistence layer is done via the PodcastDao interface:

      
        public interface PodcastDao {
    
        	public List<Podcast> getPodcasts();
    
        	/**
        	 * Returns a podcast given its id
        	 *
        	 * @param id
        	 * @return
        	 */
        	public Podcast getPodcastById(Long id);
    
        	public Long deletePodcastById(Long id);
    
        	public Long createPodcast(Podcast podcast);
    
        	public int updatePodcast(Podcast podcast);
    
        	/** removes all podcasts */
        	public void deletePodcasts();
    
        }
      
    

    For this interface I provide a PodcastDaoJPA2Impl JPA-specific implementation class:

      
        public class PodcastDaoJPA2Impl implements PodcastDao {
    
        	@PersistenceContext
        	private EntityManager em;
    
        	.......................
    
        }
      
    

    Code alert: You can find the complete implementation of PodcastDaoJPA2Impl on GitHub – I will present the code split and give some JPA related explanations bellow.

    EntityManager

    The EntityManager API is used to access a database in a particular unit of work. It is used to create and remove persistent entity instances, to find entities by their primary key identity, and to query over all entities. This interface is similar to the Session in Hibernate.

    Persistence context

    A persistence context is a set of entity instances in which for any persistent entity identity there is a unique entity instance. Within the persistence context, the entity instances and their lifecycle is managed by a particular entity manager. The scope of this context can either be the transaction, or an extended unit of work.

    Note: When the persistence layer was implemented with MyBatis, there was no need to have an implementation class of the interface, as one was provided at runtime via the MapperFactoryBean. See my post Spring MyBatis integration example, for complete details how to integrate MyBatis in Spring.

    Now let’s see how the CRUD operations are implemented with JPA:

    3.2.1. CREATE

      
        public Long createPodcast(Podcast podcast) {
    
        	entityManager.persist(podcast);
        	entityManager.flush();//force insert to receive the id of the podcast
    
        	return podcast.getId();
        }
      
    

    To insert an entity in the database, you can use either persist or merge, whereas if persist is sufficient you should use it. There’s a nice article, JPA: persisting vs. merging entites, that explains the difference between the two. In my case persist was enough.

    I use the flush() method of the EntityManager to force the insertion of the entity and synchronize the persistence context with the underlying database, so that I can return the new id of podcast being inserted.

    Note: The transaction context is set via the @Transcational Spring annotation at the caller of the DAO class – PodcastRestService:

      
        @POST
        @Consumes({MediaType.APPLICATION_JSON})
        @Produces({MediaType.TEXT_HTML})
        @Transactional
        public Response createPodcast(Podcast podcast) {
        		podcastDao.createPodcast(podcast);
    
        		return Response.status(201).entity("A new podcast/resource has been created").build();
        }
      
    

    Please see these articles: JPA 2 | EntityManagers, Transactions and everything around it and Java Persistence/Transactions for a better understanding of the JPA mechanismus for transactions.

    3.2.2. READ

      
        public List<Podcast> getPodcasts() {
    
        	String qlString = "SELECT p FROM Podcast p";
        	TypedQuery<Podcast> query = entityManager.createQuery(qlString, Podcast.class);
    
        	return query.getResultList();
        }
    
        public Podcast getPodcastById(Long id) {
    
        	try {
        		String qlString = "SELECT p FROM Podcast p WHERE p.id = ?1";
        		TypedQuery<Podcast> query = entityManager.createQuery(qlString, Podcast.class);
        		query.setParameter(1, id);
    
        		return query.getSingleResult();
        	} catch (NoResultException e) {
        		return null;
        	}
        }
      
    

    For the reading operations I use TypedQuery, which is an extension of the java.persistence.Query, and, as the name suggets, knows the type it returns as a result of its execution.

    3.2.3. UPDATE

      
         int updatePodcast(Podcast podcast) {
    
        	entityManager.merge(podcast);
    
        	return 1;
        }
      
    

    To update the podcast I simply use the merge method of the EntityManager.

    3.2.4. DELETE

      
        public Long deletePodcastById(Long id) {
    
        	Podcast podcast = entityManager.find(Podcast.class, id);
        	entityManager.remove(podcast);
    
        	return 1L;
        }
      
    

    The deletion of an entity is executed with the remove method of the EntityManager, after the entity has been loaded into the PersistenceContext with the help of the find method.

      
        public void deletePodcasts() {
        	Query query = entityManager.createNativeQuery("TRUNCATE TABLE podcasts");
        	query.executeUpdate();
        }
      
    

    For the deletion of all podcasts, I used a TRUNCATE command against the MySQL database. Native queries are made possible via the createNativeQuery method of the EntityManager.

    Well, that’s it. You’ve seen how to configure Spring with JPA/Hibernate to build the data persistence layer of an application, and how to use simple methods of the EntityManager to execute CRUD operations against a database.

    If you’ve found some usefulness in this post this, I’d be very grateful if you’d help it spread by sharing it on Twitter, Google+ or Facebook. Thank you! Don’t forget also to check out Podcastpedia.org – you’ll find for sure interesting podcasts and episodes. We are grateful for your support.

    4. Resources

    4.1. Source Code

    4.2. JPA resources

    4.3. Rest resources

    Podcastpedia image

    Adrian Matei

    Creator of Podcastpedia.org and Codingpedia.org, computer science engineer, husband, father, curious and passionate about science, computers, software, education, economics, social equity, philosophy - but these are just outside labels and not that important, deep inside we are all just consciousness, right?

    Appendix

    A – testing the demo application with DEV HTTP Client

    Parallel calls with async-await in javascript - I promise you all performance and simplicity

    I was blown away about the simplicity and performance gain of making parallel calls with the new async-await feature in javascript. See the blog post to understand why. Continue reading