Introduction
In this tutorial we'll convert our previous projectSpring - Hibernate: One-To-Many Association to use Spring JPA. We'll use Hibernate as the JPA provider and show the required changes to convert our project.
Spring MVC 3 and Hibernate Tutorials Series
Spring JPA: Many-To-One Association: Using Hibernate as the JPA Vendor
Spring JPA: One-To-Many Association: Using Hibernate as the JPA Vendor
Spring - Hibernate: Many-To-One Association - Explicitly Specify Join Table, Cascade, and Fetch
Spring - Hibernate: One-To-Many Association - Explicitly Specify Join Table, Cascade, and Fetch
Spring - Hibernate: Many-To-One Association
Spring - Hibernate: One-To-Many Association
Spring MVC 3, Hibernate Annotations, MySQL Integration Tutorial
Spring MVC 3, Hibernate Annotations, HSQLDB Integration Tutorial
What is Spring JPA?
The Spring JPA, available under the org.springframework.orm.jpa package, offers comprehensive support for the Java Persistence API in a similar manner to the integration with Hibernate or JDO, while being aware of the underlying implementation in order to provide additional features.
Source: Spring 3 Reference
What is JPA?
The Java Persistence API simplifies the programming model for entity persistence and adds capabilities that were not in EJB 2.1
The Java Persistence API deals with the way relational data is mapped to Java objects ("persistent entities"), the way that these objects are stored in a relational database so that they can be accessed at a later time, and the continued existence of an entity's state even after the application that uses it ends. In addition to simplifying the entity persistence model, the Java Persistence API standardizes object-relational mapping.
Source: The Java Persistence API - A Simpler Programming Model for Entity Persistence
Changes
Using a diff tool, we can visualize the changes from the original Hibernate project to the JPA project.Development
Similar with the original project, we'll split our development in three layers: Domain, Service, and Controller.Domain Layer
In the domain layer, we don't change any existing domain classes. That's because our domain is already using JPA annotation in the beginning.Service Layer
For the service classes, we will drop all Hibernate references and instead use JPA. Let's start with the CreditCardService:CreditCardService.java
package org.krams.tutorial.service; import java.util.ArrayList; import java.util.List; import javax.annotation.Resource; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import javax.persistence.Query; import org.apache.log4j.Logger; import org.krams.tutorial.domain.CreditCard; import org.krams.tutorial.domain.Person; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; /** * Service for processing Credit Cards * * @author Krams at {@link http://krams915@blogspot.com */ @Service("creditCardService") @Transactional public class CreditCardService { protected static Logger logger = Logger.getLogger("service"); @Resource(name="personService") private PersonService personService; private EntityManager entityManager; @PersistenceContext public void setEntityManager(EntityManager entityManager) { this. entityManager = entityManager; } /** * Retrieves all credit cards */ public List<CreditCard> getAll(Integer personId) { logger.debug("Retrieving all credit cards"); // Create a Hibernate query (HQL) Query query = entityManager.createQuery("FROM Person as p LEFT JOIN FETCH p.creditCards WHERE p.id="+personId); Person person = (Person) query.getSingleResult(); // Retrieve all return new ArrayList<CreditCard>(person.getCreditCards()); } /** * Retrieves all credit cards */ public List<CreditCard> getAll() { logger.debug("Retrieving all credit cards"); // Create a JPA query Query query = entityManager.createQuery("FROM CreditCard"); // Retrieve all return query.getResultList(); } /** * Retrieves a single credit card */ public CreditCard get( Integer id ) { // Retrieve existing credit card CreditCard creditCard = (CreditCard) entityManager.createQuery("FROM CreditCard p WHERE p.id = :id") .setParameter("id", id).getSingleResult(); // Persists to db return creditCard; } /** * Adds a new credit card */ public void add(Integer personId, CreditCard creditCard) { logger.debug("Adding new credit card"); // Persists to db entityManager.persist(creditCard); // Add to person as well // Retrieve existing person via id Person existingPerson = personService.get(personId); // Assign updated values to this person existingPerson.getCreditCards().add(creditCard); // Save updates personService.edit(existingPerson); } /** * Deletes an existing credit card */ public void delete(Integer id) { logger.debug("Deleting existing credit card"); // Delete reference to foreign key credit card first // We need a SQL query instead of HQL query here to access the third table Query query = entityManager.createNativeQuery("DELETE FROM PERSON_CREDIT_CARD " + "WHERE creditCards_ID="+id); query.executeUpdate(); // Retrieve existing credit card CreditCard creditCard = this.get(id); // Delete entityManager.remove(creditCard); } /** * Edits an existing credit card */ public void edit(CreditCard creditCard) { logger.debug("Editing existing creditCard"); // Retrieve existing credit card via id CreditCard existingCreditCard = this.get(creditCard.getId()); // Assign updated values to this credit card existingCreditCard.setNumber(creditCard.getNumber()); existingCreditCard.setType(creditCard.getType()); // Save updates entityManager.merge(existingCreditCard); } }
Let's make a side-by-side comparison between the original Hibernate-based implementation and the new JPA-based implementation:
SessionFactory to EntityManager
To utilize JPA we have to remove Hibernate's SessionFactory and replace it with JPA's EntityManager. Essentially the EntityManager is equivalent to Hibernate's Session object.
old code
@Resource(name="sessionFactory") private SessionFactory sessionFactory;
new code
@Resource(name="personService") private PersonService personService; private EntityManager entityManager; @PersistenceContext public void setEntityManager(EntityManager entityManager) { this. entityManager = entityManager; }
Retrieve all credit cards by person's id
old code
/** * Retrieves all credit cards */ public List<CreditCard> getAll(Integer personId) { logger.debug("Retrieving all credit cards"); // Retrieve session from Hibernate Session session = sessionFactory.getCurrentSession(); // Create a Hibernate query (HQL) Query query = session.createQuery("FROM Person as p LEFT JOIN FETCH p.creditCards WHERE p.id="+personId); Person person = (Person) query.uniqueResult(); // Retrieve all return new ArrayList<CreditCard>(person.getCreditCards()); }
new code
/** * Retrieves all credit cards */ public List<CreditCard> getAll(Integer personId) { logger.debug("Retrieving all credit cards"); // Create a Hibernate query (HQL) Query query = entityManager.createQuery("FROM Person as p LEFT JOIN FETCH p.creditCards WHERE p.id="+personId); Person person = (Person) query.getSingleResult(); // Retrieve all return new ArrayList<CreditCard>(person.getCreditCards()); }
Retrieve all credit cards
old code
/** * Retrieves all credit cards */ public List<CreditCard> getAll() { logger.debug("Retrieving all credit cards"); // Retrieve session from Hibernate Session session = sessionFactory.getCurrentSession(); // Create a Hibernate query (HQL) Query query = session.createQuery("FROM CreditCard"); // Retrieve all return query.list(); }
new code
/** * Retrieves all credit cards */ public ListgetAll() { logger.debug("Retrieving all credit cards"); // Create a JPA query Query query = entityManager.createQuery("FROM CreditCard"); // Retrieve all return query.getResultList(); }
Add new credit card
old code
/** * Adds a new credit card */ public void add(Integer personId, CreditCard creditCard) { logger.debug("Adding new credit card"); // Retrieve session from Hibernate Session session = sessionFactory.getCurrentSession(); // Persists to db session.save(creditCard); // Add to person as well // Retrieve existing person via id Person existingPerson = (Person) session.get(Person.class, personId); // Assign updated values to this person existingPerson.getCreditCards().add(creditCard); // Save updates session.save(existingPerson); }
new code
/** * Adds a new credit card */ public void add(Integer personId, CreditCard creditCard) { logger.debug("Adding new credit card"); // Persists to db entityManager.persist(creditCard); // Add to person as well // Retrieve existing person via id Person existingPerson = personService.get(personId); // Assign updated values to this person existingPerson.getCreditCards().add(creditCard); // Save updates personService.edit(existingPerson); }
Retrieve a single credit card
old code
/** * Retrieves a single credit card */ public CreditCard get( Integer id ) { // Retrieve session from Hibernate Session session = sessionFactory.getCurrentSession(); // Retrieve existing credit card CreditCard creditCard = (CreditCard) session.get(CreditCard.class, id); // Persists to db return creditCard; }
new code
/** * Retrieves a single credit card */ public CreditCard get( Integer id ) { // Retrieve existing credit card CreditCard creditCard = (CreditCard) entityManager.createQuery("FROM CreditCard p WHERE p.id = :id") .setParameter("id", id).getSingleResult(); // Persists to db return creditCard; }
Delete an existing credit card
old code
/** * Deletes an existing credit card */ public void delete(Integer id) { logger.debug("Deleting existing credit card"); // Retrieve session from Hibernate Session session = sessionFactory.getCurrentSession(); // Delete reference to foreign key credit card first // We need a SQL query instead of HQL query here to access the third table Query query = session.createSQLQuery("DELETE FROM PERSON_CREDIT_CARD " + "WHERE creditCards_ID="+id); query.executeUpdate(); // Retrieve existing credit card CreditCard creditCard = (CreditCard) session.get(CreditCard.class, id); // Delete session.delete(creditCard); }
new code
/** * Deletes an existing credit card */ public void delete(Integer id) { logger.debug("Deleting existing credit card"); // Delete reference to foreign key credit card first // We need a SQL query instead of HQL query here to access the third table Query query = entityManager.createNativeQuery("DELETE FROM PERSON_CREDIT_CARD " + "WHERE creditCards_ID="+id); query.executeUpdate(); // Retrieve existing credit card CreditCard creditCard = this.get(id); // Delete entityManager.remove(creditCard); }
Edit an existing credit card
old code
/** * Edits an existing credit card */ public void edit(CreditCard creditCard) { logger.debug("Editing existing creditCard"); // Retrieve session from Hibernate Session session = sessionFactory.getCurrentSession(); // Retrieve existing credit card via id CreditCard existingCreditCard = (CreditCard) session.get(CreditCard.class, creditCard.getId()); // Assign updated values to this credit card existingCreditCard.setNumber(creditCard.getNumber()); existingCreditCard.setType(creditCard.getType()); // Save updates session.save(existingCreditCard); }
new code
/** * Edits an existing credit card */ public void edit(CreditCard creditCard) { logger.debug("Editing existing creditCard"); // Retrieve existing credit card via id CreditCard existingCreditCard = this.get(creditCard.getId()); // Assign updated values to this credit card existingCreditCard.setNumber(creditCard.getNumber()); existingCreditCard.setType(creditCard.getType()); // Save updates entityManager.merge(existingCreditCard); }
PersonService.java
package org.krams.tutorial.service; import java.util.List; import java.util.Set; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import javax.persistence.Query; import org.apache.log4j.Logger; import org.krams.tutorial.domain.CreditCard; import org.krams.tutorial.domain.Person; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; /** * Service for processing Persons * * @author Krams at {@link http://krams915@blogspot.com */ @Service("personService") @Transactional public class PersonService { protected static Logger logger = Logger.getLogger("service"); private EntityManager entityManager; @PersistenceContext public void setEntityManager(EntityManager entityManager) { this. entityManager = entityManager; } /** * Retrieves all persons * * @return a list of persons */ public List<Person> getAll() { logger.debug("Retrieving all persons"); // Create a JPA query Query query = entityManager.createQuery("FROM Person"); // Retrieve all return query.getResultList(); } /** * Retrieves a single person */ public Person get( Integer id ) { // Retrieve existing person // Create a JPA query Query query = entityManager.createQuery("FROM Person as p LEFT JOIN FETCH p.creditCards WHERE p.id="+id); return (Person) query.getSingleResult(); } /** * Adds a new person */ public void add(Person person) { logger.debug("Adding new person"); // Persists to db entityManager.persist(person); } /** * Deletes an existing person * @param id the id of the existing person */ public void delete(Integer id) { logger.debug("Deleting existing person"); // Create a Hibernate query (HQL) Query query = entityManager.createQuery("FROM Person as p LEFT JOIN FETCH p.creditCards WHERE p.id="+id); // Retrieve record Person person = (Person) query.getSingleResult(); Set<CreditCard> creditCards =person.getCreditCards(); // Delete person entityManager.remove(person); // Delete associated credit cards for (CreditCard creditCard: creditCards) { entityManager.remove(creditCard); } } /** * Edits an existing person */ public void edit(Person person) { logger.debug("Editing existing person"); // Retrieve existing person via id Person existingPerson = this.get(person.getId()); // Assign updated values to this person existingPerson.setFirstName(person.getFirstName()); existingPerson.setLastName(person.getLastName()); existingPerson.setMoney(person.getMoney()); // Save updates entityManager.merge(existingPerson); } }
Let's make a side-by-side comparison between the original Hibernate-based implementation and the new JPA-based implementation:
SessionFactory to EntityManager
Similar with the CreditCardService, we have to remove Hibernate's SessionFactory and replace it with JPA's EntityManager.
old code
@Resource(name="sessionFactory") private SessionFactory sessionFactory;
new code
private EntityManager entityManager; @PersistenceContext public void setEntityManager(EntityManager entityManager) { this. entityManager = entityManager; }
Retrieve all persons
old code
/** * Retrieves all persons * * @return a list of persons */ public ListgetAll() { logger.debug("Retrieving all persons"); // Retrieve session from Hibernate Session session = sessionFactory.getCurrentSession(); // Create a Hibernate query (HQL) Query query = session.createQuery("FROM Person"); // Retrieve all return query.list(); }
new code
/** * Retrieves all persons * * @return a list of persons */ public ListgetAll() { logger.debug("Retrieving all persons"); // Create a JPA query Query query = entityManager.createQuery("FROM Person"); // Retrieve all return query.getResultList(); }
Retrieve a single person
old code
/** * Retrieves a single person */ public Person get( Integer id ) { // Retrieve session from Hibernate Session session = sessionFactory.getCurrentSession(); // Retrieve existing person // Create a Hibernate query (HQL) Query query = session.createQuery("FROM Person as p LEFT JOIN FETCH p.creditCards WHERE p.id="+id); return (Person) query.uniqueResult(); }
new code
/** * Retrieves a single person */ public Person get( Integer id ) { // Retrieve existing person // Create a JPA query Query query = entityManager.createQuery("FROM Person as p LEFT JOIN FETCH p.creditCards WHERE p.id="+id); return (Person) query.getSingleResult(); }
Add a new person
old code
/** * Adds a new person */ public void add(Person person) { logger.debug("Adding new person"); // Retrieve session from Hibernate Session session = sessionFactory.getCurrentSession(); // Persists to db session.save(person); }
new code
/** * Adds a new person */ public void add(Person person) { logger.debug("Adding new person"); // Persists to db entityManager.persist(person); }
Delete an existing person
old code
/** * Deletes an existing person * @param id the id of the existing person */ public void delete(Integer id) { logger.debug("Deleting existing person"); // Retrieve session from Hibernate Session session = sessionFactory.getCurrentSession(); // Create a Hibernate query (HQL) Query query = session.createQuery("FROM Person as p LEFT JOIN FETCH p.creditCards WHERE p.id="+id); // Retrieve record Person person = (Person) query.uniqueResult(); SetcreditCards =person.getCreditCards(); // Delete person session.delete(person); // Delete associated credit cards for (CreditCard creditCard: creditCards) { session.delete(creditCard); } }
new code
/** * Deletes an existing person * @param id the id of the existing person */ public void delete(Integer id) { logger.debug("Deleting existing person"); // Create a Hibernate query (HQL) Query query = entityManager.createQuery("FROM Person as p LEFT JOIN FETCH p.creditCards WHERE p.id="+id); // Retrieve record Person person = (Person) query.getSingleResult(); SetcreditCards =person.getCreditCards(); // Delete person entityManager.remove(person); // Delete associated credit cards for (CreditCard creditCard: creditCards) { entityManager.remove(creditCard); } }
Edit an existing person
old code
/** * Edits an existing person */ public void edit(Person person) { logger.debug("Editing existing person"); // Retrieve session from Hibernate Session session = sessionFactory.getCurrentSession(); // Retrieve existing person via id Person existingPerson = (Person) session.get(Person.class, person.getId()); // Assign updated values to this person existingPerson.setFirstName(person.getFirstName()); existingPerson.setLastName(person.getLastName()); existingPerson.setMoney(person.getMoney()); // Save updates session.save(existingPerson); }
new code
/** * Edits an existing person */ public void edit(Person person) { logger.debug("Editing existing person"); // Retrieve existing person via id Person existingPerson = this.get(person.getId()); // Assign updated values to this person existingPerson.setFirstName(person.getFirstName()); existingPerson.setLastName(person.getLastName()); existingPerson.setMoney(person.getMoney()); // Save updates entityManager.merge(existingPerson); }
Controller Layer
For the controller layer, we just need to fix a mapping bug when adding a new CreditCard. Everything else are the same:CreditCardController.java
package org.krams.tutorial.controller; import javax.annotation.Resource; import org.apache.log4j.Logger; import org.krams.tutorial.domain.CreditCard; import org.krams.tutorial.service.CreditCardService; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; /** * Handles credit card requests * * @author Krams at {@link http://krams915@blogspot.com */ @Controller @RequestMapping("/main/creditcard") public class CreditCardController { protected static Logger logger = Logger.getLogger("controller"); @Resource(name="creditCardService") private CreditCardService creditCardService; /** * Retrieves the "Add New Credit Card" page */ @RequestMapping(value = "/add", method = RequestMethod.GET) public String getAdd(@RequestParam("id") Integer personId, Model model) { logger.debug("Received request to show add page"); // Prepare model object CreditCard creditCard = new CreditCard(); // Add to model model.addAttribute("personId", personId); model.addAttribute("creditCardAttribute", creditCard); // This will resolve to /WEB-INF/jsp/add-credit-card.jsp return "add-credit-card"; } /** * Adds a new credit card */ @RequestMapping(value = "/add", method = RequestMethod.POST) public String postAdd(@RequestParam("pid") Integer personId, @ModelAttribute("creditCardAttribute") CreditCard creditCard) { logger.debug("Received request to add new credit card"); // Delegate to service creditCardService.add(personId, creditCard); // Redirect to url return "redirect:/krams/main/record/list"; } /** * Deletes a credit card */ @RequestMapping(value = "/delete", method = RequestMethod.GET) public String getDelete(@RequestParam("id") Integer creditCardId) { logger.debug("Received request to delete credit card"); // Delegate to service creditCardService.delete(creditCardId); // Redirect to url return "redirect:/krams/main/record/list"; } /** * Retrieves the "Edit Existing Credit Card" page */ @RequestMapping(value = "/edit", method = RequestMethod.GET) public String getEdit(@RequestParam("pid") Integer personId, @RequestParam("cid") Integer creditCardId, Model model) { logger.debug("Received request to show edit page"); // Retrieve credit card by id CreditCard existingCreditCard = creditCardService.get(creditCardId); // Add to model model.addAttribute("personId", personId); model.addAttribute("creditCardAttribute", existingCreditCard); // This will resolve to /WEB-INF/jsp/edit-credit-card.jsp return "edit-credit-card"; } /** * Edits an existing credit card */ @RequestMapping(value = "/edit", method = RequestMethod.POST) public String postEdit(@RequestParam("id") Integer creditCardId, @ModelAttribute("creditCardAttribute") CreditCard creditCard) { logger.debug("Received request to add new credit card"); // Assign id creditCard.setId(creditCardId); // Delegate to service creditCardService.edit(creditCard); // Redirect to url return "redirect:/krams/main/record/list"; } }
Here's the change we did for the CreditCardController:
Add a new credit card
We simply changed the @RequestParam("id") to @RequestParam("pid"):
old code
/** * Adds a new credit card */ @RequestMapping(value = "/add", method = RequestMethod.POST) public String postAdd(@RequestParam("id") Integer personId, @ModelAttribute("creditCardAttribute") CreditCard creditCard) { logger.debug("Received request to add new credit card"); // Delegate to service creditCardService.add(personId, creditCard); // Redirect to url return "redirect:/krams/main/record/list"; }
new code
/** * Adds a new credit card */ @RequestMapping(value = "/add", method = RequestMethod.POST) public String postAdd(@RequestParam("pid") Integer personId, @ModelAttribute("creditCardAttribute") CreditCard creditCard) { logger.debug("Received request to add new credit card"); // Delegate to service creditCardService.add(personId, creditCard); // Redirect to url return "redirect:/krams/main/record/list"; }
Since we've modified the @RequestMapping for the Add page, we have to update our add-credit-card.jsp
add-credit-card.jsp
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <%@ taglib uri="http://www.springframework.org/tags/form" prefix="form" %> <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> <h1>Add New Credit Card</h1> <c:url var="saveUrl" value="/krams/main/creditcard/add?pid=${personId}" /> <form:form modelAttribute="creditCardAttribute" method="POST" action="${saveUrl}"> <table> <tr> <td>Person Id:</td> <td><input type="text" value="${personId}" disabled="true"/> </tr> <tr> <td><form:label path="type">Type:</form:label></td> <td><form:input path="type"/></td> </tr> <tr> <td><form:label path="number">Number:</form:label></td> <td><form:input path="number"/></td> </tr> </table> <input type="submit" value="Save" /> </form:form> </body> </html>
Here's the change we did for the add-credit-card.jsp:
old
<c:url var="saveUrl" value="/krams/main/creditcard/add?id=${creditCardAttribute.person.id}" />
new
<c:url var="saveUrl" value="/krams/main/creditcard/add?pid=${creditCardAttribute.person.id}" />
Configuration
We have completed the necessary Java classes. Our next step is to update our configuration files.Here are the steps:
1. Update our hibernate-context.xml so that it uses JPA. Here's the updated config:
hibernate-context.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd "> <context:property-placeholder location="/WEB-INF/spring.properties" /> <tx:annotation-driven transaction-manager="transactionManager" /> <!-- Declare a datasource that has pooling capabilities--> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close" p:driverClass="${app.jdbc.driverClassName}" p:jdbcUrl="${app.jdbc.url}" p:user="${app.jdbc.username}" p:password="${app.jdbc.password}" p:acquireIncrement="5" p:idleConnectionTestPeriod="60" p:maxPoolSize="100" p:maxStatements="50" p:minPoolSize="10" /> <!-- Declare a JPA entityManagerFactory--> <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" > <property name="persistenceXmlLocation" value="classpath*:META-INF/persistence.xml"></property> <property name="persistenceUnitName" value="hibernatePersistenceUnit" /> <property name="dataSource" ref="dataSource"/> <property name="jpaVendorAdapter"> <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" > <property name="showSql" value="true"/> </bean> </property> </bean> <!-- Declare a transaction manager--> <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory" /> </bean> </beans>
Here's the change we did for the hibernate-context.xml:
Remove the following lines:
<!-- Declare the Hibernate SessionFactory for retrieving Hibernate sessions --> <!-- See http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/orm/hibernate3/annotation/AnnotationSessionFactoryBean.html --> <!-- See http://docs.jboss.org/hibernate/stable/core/api/index.html?org/hibernate/SessionFactory.html --> <!-- See http://docs.jboss.org/hibernate/stable/core/api/index.html?org/hibernate/Session.html --> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean" p:dataSource-ref="dataSource" p:configLocation="${hibernate.config}" p:packagesToScan="org.krams.tutorial"/> <!-- Declare a transaction manager--> <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager" p:sessionFactory-ref="sessionFactory" />
And replace it with:
<!-- Declare a JPA entityManagerFactory--> <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" > <property name="persistenceXmlLocation" value="classpath*:META-INF/persistence.xml"></property> <property name="persistenceUnitName" value="hibernatePersistenceUnit" /> <property name="dataSource" ref="dataSource"/> <property name="jpaVendorAdapter"> <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" > <property name="showSql" value="true"/> </bean> </property> </bean> <!-- Declare a transaction manager--> <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory" /> </bean> </beans>
2. Delete the hibernate.cfg.xml.
3. Declare a META-INF/persistence.xml
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0"> <persistence-unit name="hibernatePersistenceUnit" transaction-type="RESOURCE_LOCAL"> <properties> <property name="hibernate.hbm2ddl.auto" value="create" /> </properties> </persistence-unit> </persistence>
Run the Application
Setup the database
Our application uses MySQL as its database. To run the application, make sure to setup the database first.To create the database, follow these steps.
1. Open phpmyadmin (or any tool you prefer with)
2. Create a new database named mydatabase
3. Run the application to automatically create the database schema.
To populate the database with sample data, import the mydatabase.sql SQL script which is located under the WEB-INF folder of the application.
Access the main application
To access the main application, use the following URL:http://localhost:8080/spring-hibernate-jpa-one-to-many-default/krams/main/record/list
You should see the following application:
Conclusion
That's it. We've successfully updated our original Hibernate-based application to Spring JPA-based implementation. The advantage of this project is we can now switch JPA providers seamlessly without any direct dependencies with Hibernate.Download the project
You can access the project site at Google's Project Hosting at http://code.google.com/p/spring-mvc-hibernate-annotations-integration-tutorial/
You can download the project as a Maven build. Look for the spring-hibernate-jpa-one-to-many-default.zip in the Download sections.
You can run the project directly using an embedded server via Maven.
For Tomcat: mvn tomcat:run
For Jetty: mvn jetty:run
If you want to learn more about Spring MVC and integration with other technologies, feel free to read my other tutorials in the Tutorials section.
Share the joy:
|
Subscribe by reader Subscribe by email Share
Great work. Learned a lot by reading this article.
ReplyDeleteThanks
Grabczewski
Hi Krams, thanks for great tutorials. As I am new in learning Hibernate just want to know which one is better Hibernate-based implementation or JPA-based implementaion as in tutorials both looks similar
ReplyDeletehi-where can I get the sql scripts for creating the tables mentioned in the tuitorial for MySQL? The mentioned file database.sql contains only insert statement. can you please add the DDL also as pert of the zip. Thanks Arul
ReplyDeletehi-could anyone help me where the create SQLs scripts for the mysql used in the tuitorial I can found. Thanks.
ReplyDelete@Arul, it can be found under the WEB-INF folder. The name of the script is mydatabase.sql
ReplyDeletehi Krams- Thanks for your reply. The mydatabase.sql contains only insert statements there is no create sqls in it. I downloaded the zip file from the link mentioned here. Would you please check and give me the right link where sqls has it.Thanks Arul
DeleteThat's right. The app is supposed to re-create the tables. That's why the sql script only contains the insert statements.
DeleteThanks for great tutorials! I have one problem. I thought I find solution here but the problem also exists. How versioning can be done in spring mvc? I mean while user1 edits object another user (user2) can edit the object and update it. User1 will be able to update it without any messages. What's the proper way of solving this problem? Store detached objects in session?
ReplyDelete@Sergei, this is a huge topic. Basically it boils down to database locking mechanisms and data consistency. See http://en.wikipedia.org/wiki/Lock_(database)
ReplyDeleteIn regards to Spring, take a look at various isolation levels for @Transactional annotation. See http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/transaction.html
In particular, you might be interested in investigating various ISOLATION levels. See http://static.springsource.org/spring/docs/3.1.x/javadoc-api/
@krams, not sure if you understand me. I mean in your example there's transactional 'update' method in service that a) gets object, b) fills its value with updated fields, c) merges it . (I'm also not sure if merge is necessary as updated object is in managed state - not detached). So in the app no conflict occurs if the object was updated before by someone else (and isolation level won't help). We could of course make some sort of locking when edit was started (getEdit called) but it's too bad idea. I have the same architecture and that's why I'm asking you - may be there's standard approach I'm missing
ReplyDeleteI see 2 solutions : one is to store detached object in session and another is to store version number in DTO (though it's not very secure or requires additional checks)
DeleteGreat example! However, when I run it, the 'credit_card' and 'person' table lose all data at the beginning of the program. When I remove the annotation '@Table(name = 'CREDIT_CARD') on the CreditCard class, these tables do not lose their data. Any idea what's going on? Thanks.
ReplyDeleteInteresting Article
ReplyDeleteJava Online Training from India | Core Java Training Online
Java Online Training | Java EE Online Training
Dot Net Online Training | Angularjs Online Training | Java Training Institutes