Persistence API (JPA) provides POJO (Plain Old Java Object) standard and object relational mapping (OR mapping) for data persistence among applications. Persistence, which deals with storing and retrieving of application data, can now be programmed with Java Persistence API starting from EJB 3.0 as a result of JSR 220. This API has borrowed many of the concepts and standards from leading persistence frameworks like Toplink (from Oracle) and Hibernate (from JBoss). One of the great benefits of JPA is that it is an independent API and can nicely integrate with JEE as well as J2SE applications.
The addition that is coming with Spring Data is the offering of sophisticated support for JPA by providing an easily defined Repository. Repository is the central part of abstraction for the Spring Data layer. This repository just takes the user defined repository and the type of the repository and generates the run time implementation. Developer need not write any implementation for the database operations.
Spring Data provides such a sophisticated type of abstraction, however, it also, provides you a standard mechanism to setup the EntityManagerFactory or to integrate with Spring Transaction and translate JPA-specific exceptions into Spring’s DataAccessException hierarchy.
Spring Data JPA module implements the Spring Data commons repository abstraction to ease the repository implementations even more, making a manual implementation of a repository obsolete in most cases.
Business Domain
We are using the Employee and Address entities for this tutorial. These entities are associated with a relation of @OneToOne. Take in to your consideration that the Spring Data – JPA is a layer acted on mostly low level layer that could be used for defining the entities and the relations between entities. If you are looking for more details about the complex relations, please read our previous tutorials EclipseLink – JPA.
Employee.java
package net.javabeat.springdata.jpa.data; import javax.persistence.Basic; import javax.persistence.CascadeType; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.OneToOne; @Entity public class Employee { @Id private Integer employeeId; @Basic(optional=false) private String employeeName; @OneToOne(cascade=CascadeType.ALL) @JoinColumn(name="AddressId") private Address address; public Address getAddress() { return address; } public void setAddress(Address address) { this.address = address; } public Integer getEmployeeId() { return employeeId; } public void setEmployeeId(Integer employeeId) { this.employeeId = employeeId; } public String getEmployeeName() { return employeeName; } public void setEmployeeName(String employeeName) { this.employeeName = employeeName; } }
Address.java
package net.javabeat.springdata.jpa.data; import javax.persistence.CascadeType; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.OneToOne; @Entity(name="address") public class Address { @Id private int addressId; private String addressCountry; private String addressCity; @OneToOne(cascade=CascadeType.ALL,mappedBy="address") private Employee employee; public Employee getEmployee() { return employee; } public void setEmployee(Employee employee) { this.employee = employee; } public int getAddressId() { return addressId; } public void setAddressId(int addressId) { this.addressId = addressId; } public String getAddressCountry() { return addressCountry; } public void setAddressCountry(String addressCountry) { this.addressCountry = addressCountry; } public String getAddressCity() { return addressCity; } public void setAddressCity(String addressCity) { this.addressCity = addressCity; } }
Configure Spring Container
Spring Data JPA can be configured through either Declaratively or Programmatically. Declarative configuration requires defining a XML-based document, whereas the Programmatic configuration does involve defining Java Class annotated with those required Spring annotation. Configuration of Spring Container used the Spring container bootstrapping and the required user defined Repositories, Spring Beans, DataSources, TransactionManager, and different assets for Spring Container.
SpringContext.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:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:util="http://www.springframework.org/schema/util" xmlns:jpa="http://www.springframework.org/schema/data/jpa" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd"> <!-- For consider the using of annotations foe defining Spring Bean --> <context:annotation-config /> <!-- For defining Spring Bean --> <context:component-scan base-package="net.javabeat.springdata.beans" /> <!-- For bootstrapping the Spring Repository --> <jpa:repositories base-package="net.javabeat.springdata.repo" /> <!-- Necessary to get the entity manager injected into the factory bean --> <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" /> <!-- Define EclipseLink JPA Vendor Adapter --> <bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter"> <property name="databasePlatform" value="org.eclipse.persistence.platform.database.MySQLPlatform" /> <property name="generateDdl" value="false" /> <property name="showSql" value="true" /> </bean> <!-- Entity Manager Factory --> <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean"> <property name="persistenceUnitName" value="SpringData"></property> <property name="jpaVendorAdapter" ref="jpaVendorAdapter" /> </bean> <!-- Transaction Manager --> <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory" /> </bean> <!-- Enable Transactional Manner --> <tx:annotation-driven transaction-manager="transactionManager" /> </beans>
Spring Data Repository
When it comes for saving, updating, reading and deleting the entities from the store, you have to define a Repository for achieving that. So, the Repository that you are going for use for achieving CRUD operations is as follow.
If you look at the user defined repository below, it extend the CrudRepository which is the abstract layer for the CRUD operations. By extending this interface, your repository just need declare the required operations. The actual implementations will be done by the spring container at run time.
EmployeeRepository.java
package net.javabeat.springdata.repo; import net.javabeat.springdata.jpa.data.Employee; import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Repository; @Repository public interface EmployeeRepository extends CrudRepository<Employee, Integer>{ public Employee findByEmployeeId(Integer id); }
- For defining your Repository, you have to implement one of the pre defined repositories like CrudeRepository or PagingAndSortingRepository.
- Annotate the repository using @Repository.
Injecting User Repository Into User Defined Bean
For accessing your repository, you have to define your Spring Bean and annotate the bean with @Component, after that you can inject your Repository through using of @Autowired.
RegistrationBean.java
package net.javabeat.springdata.beans; import net.javabeat.springdata.repo.EmployeeRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component public class RegistrationBean { @Autowired private EmployeeRepository employeeReposigtory; public RegistrationBean(){ } public EmployeeRepository getEmployeeReposigtory() { return employeeReposigtory; } public void setEmployeeReposigtory(EmployeeRepository employeeReposigtory) { this.employeeReposigtory = employeeReposigtory; } }
Run Spring Data JPA Example Application
Spring container can be obtained through different way, one of the most easy way for obtaining it is by using the ClassPathApplicationContext that accept the name of the XML based document that you’ve used for defining the different assets of Spring container. After that you have the ability to locate the bean that you’ve defined for injecting your repository within it. In fact, you have not created the implementation of the Repository, that’s created by the Spring Container. By calling the different operations of our Repository, you should be able to do all of the CRUD operations.
Executable.java
package net.javabeat.springdata.executable; import net.javabeat.springdata.beans.RegistrationBean; import net.javabeat.springdata.jpa.data.Address; import net.javabeat.springdata.jpa.data.Employee; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Executable { public static void main(String [] args){ // Acquire Context ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("SpringContext.xml"); // Get RegistrationBean That Defined RegistrationBean registrationBean = (RegistrationBean)context.getBean("registrationBean"); // Create Employee Employee employee = new Employee(); employee.setEmployeeId(1); employee.setEmployeeName("Susa Hurbert"); // Create Address Address address = new Address(); address.setAddressId(1); address.setAddressCountry("United Kingdom"); address.setAddressCity("London"); address.setEmployee(employee); employee.setAddress(address); // Persist Using EmployeeRepository registrationBean.getEmployeeReposigtory().save(employee); // Find By Employee Id Employee emp = registrationBean.getEmployeeReposigtory().findByEmployeeId(1); // Close context context.close(); } }
Persisted Records
Once you’ve executed the Executable application that listed above, you are getting two records persisted inside the database, one for Employee and the second for Address.
Maven Dependencies
As we’ve mentioned previously, that this tutorial is built on created maven project, so for adding the libraries for Spring Data, all what you have to do is by providing your pom.xml with the following dependencies:
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>net.javabeat.springdata</groupId> <artifactId>SpringData-JPA</artifactId> <version>1.0</version> <packaging>jar</packaging> <name>Spring Data</name> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.1</version> <configuration> <source>1.6</source> <target>1.6</target> <encoding>UTF-8</encoding> </configuration> </plugin> </plugins> </build> <dependencies> <!-- Querydsl dependencies --> <dependency> <groupId>com.mysema.querydsl</groupId> <artifactId>querydsl-core</artifactId> <version>2.8.0</version> </dependency> <dependency> <groupId>com.mysema.querydsl</groupId> <artifactId>querydsl-apt</artifactId> <version>2.8.0</version> </dependency> <dependency> <groupId>com.mysema.querydsl</groupId> <artifactId>querydsl-jpa</artifactId> <version>2.8.0</version> </dependency> <!-- SLF4J dependency --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.6.1</version> </dependency> <!-- Dependencies for Eclipse JPA Persistence API --> <dependency> <groupId>org.eclipse.persistence</groupId> <artifactId>eclipselink</artifactId> <version>2.5.0-RC1</version> <exclusions> <exclusion> <groupId>org.eclipse.persistence</groupId> <artifactId>commonj.sdo</artifactId> </exclusion> </exclusions> </dependency> <!-- Spring Data Dependency --> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-jpa</artifactId> <version>1.5.1.RELEASE</version> </dependency> <!-- Dependency for MySql Java connector --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.30</version> </dependency> </dependencies> </project>
Inquiry By Method Declaration
If you’ve defined method inside you repository such as findByEmployeeId, without any implementation. Spring Data is capable of determining the proper query and implementation for your defined method. Look at the new form of EmployeeRepository.java.
package net.javabeat.springdata.repo; import net.javabeat.springdata.jpa.data.Employee; import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Repository; @Repository public interface EmployeeRepository extends CrudRepository<Employee, Integer>{ public Employee findByEmployeeId(Integer id); }
- EmployeeRepository is capable of providing the basic CRUD.
- EmployeeRepsotiory has provided a newly added method named findByEmployeeId. Note that the Employee entity does provide attribute named EmployeeId.
- Spring Data is capable of providing the created proxy from your repository the proper implementation.
Inquiry Result
If you’ve executed the following snippet of code at the Executable application, you’ve probably got a reference of Employee entity by calling the method findByEmployeeId.
- The method had called didn’t provide any segment of code.
- Spring Data has determined the proper Query that must be executed based on the name of the defined method.
Summary
Spring Data is one of the latest technology that provided recently from SpringSource. Spring Data provides a high level of abstraction that used for implementing full-fledged application. By using of Spring Data, no need for writing a code of CRUD operations, just you have to define your own Repository with/without your custom inquiry for achieving the required operations.
[wpdm_file id=79]