Spring Data JPA
Spring Data JPA 是 Spring Data 家族的一部分。Spring Data 使创建使用新方式访问数据的 Spring 驱动应用程序变得更加容易,例如非关系数据库、地图缩减框架、云服务以及先进的关系数据库支持。本文将讨论 Spring Data JPA。我们还将研究 Spring Data JPA 示例应用程序。
Spring Data JPA
Spring Data JPA 提供的一些很酷的功能包括:
- 创建并支持使用 Spring 和 JPA 创建的存储库
- 支持QueryDSL和JPA查询
- 领域类别审计
- 支持批量加载、排序、动态查询
- 支持实体的 XML 映射
- 使用 CrudRepository 减少通用 CRUD 操作的代码大小
何时使用 Spring Data JPA?
我想说,如果您需要快速创建一个基于 JPA 的存储库层,主要用于 CRUD 操作,并且不想创建抽象DAO、实现接口,那么 Spring Data JPA 是一个不错的选择。
Spring Data JPA 示例
对于我们的 Spring Data JPA 示例,我们将创建一个连接到 Postgresql 数据库的RESTful Web 服务。我们将实现基本的 CRUD 操作并处理我们已经创建的示例数据。
Spring JAP 示例样本数据
使用以下查询在 Postgresql 数据库中创建表并添加一些测试数据。
create table people (
id serial not null primary key,
first_name varchar(20) not null,
last_name varchar(20) not null,
age integer not null
);
insert into people (id, first_name, last_name, age) values
(1, 'Vlad', 'Boyarskiy', 21),
(2,'Oksi', ' Bahatskaya', 30),
(3,'Vadim', ' Vadimich', 32);
Spring Data JPA Maven 项目结构
下图显示了最终的 Spring JPA 项目结构。稍后我们将详细研究每个组件。
Spring Data JPA Maven 依赖项
我们需要为我们的 Spring Data JPA 示例项目添加以下依赖项。
postgresql
:Postgresql java 驱动程序。spring-core
,spring-context
:Spring 框架核心依赖项。spring-webmvc
,jackson-databind
:适用于Spring REST应用程序。spring-data-jpa
,hibernate-entitymanager
:用于 Spring Data JPA 和Hibernate支持。
以下是最终 pom.xml 构建文件的内容。
<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.journaldev</groupId>
<artifactId>springData</artifactId>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>
<name>Spring Data JPA Maven Webapp</name>
<url>https://maven.apache.org</url>
<properties>
<spring.framework>4.3.0.RELEASE</spring.framework>
<postgres.version>42.1.4</postgres.version>
<serializer.version>2.8.1</serializer.version>
<spring.data>1.3.4.RELEASE</spring.data>
<hibernate.manager>4.2.5.Final</hibernate.manager>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.framework}</version>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>${postgres.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.framework}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.framework}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>${spring.data}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>${hibernate.manager}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${serializer.version}</version>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
</build>
</project>
Spring 配置类
package com.journaldev.spring.config;
import java.util.Properties;
import javax.sql.DataSource;
import org.hibernate.ejb.HibernatePersistence;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories("com.journaldev.spring.repository")
@PropertySource("classpath:database.properties")
public class DataConfig {
private final String PROPERTY_DRIVER = "driver";
private final String PROPERTY_URL = "url";
private final String PROPERTY_USERNAME = "user";
private final String PROPERTY_PASSWORD = "password";
private final String PROPERTY_SHOW_SQL = "hibernate.show_sql";
private final String PROPERTY_DIALECT = "hibernate.dialect";
@Autowired
Environment environment;
@Bean
LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean lfb = new LocalContainerEntityManagerFactoryBean();
lfb.setDataSource(dataSource());
lfb.setPersistenceProviderClass(HibernatePersistence.class);
lfb.setPackagesToScan("com.journaldev.spring.model");
lfb.setJpaProperties(hibernateProps());
return lfb;
}
@Bean
DataSource dataSource() {
DriverManagerDataSource ds = new DriverManagerDataSource();
ds.setUrl(environment.getProperty(PROPERTY_URL));
ds.setUsername(environment.getProperty(PROPERTY_USERNAME));
ds.setPassword(environment.getProperty(PROPERTY_PASSWORD));
ds.setDriverClassName(environment.getProperty(PROPERTY_DRIVER));
return ds;
}
Properties hibernateProps() {
Properties properties = new Properties();
properties.setProperty(PROPERTY_DIALECT, environment.getProperty(PROPERTY_DIALECT));
properties.setProperty(PROPERTY_SHOW_SQL, environment.getProperty(PROPERTY_SHOW_SQL));
return properties;
}
@Bean
JpaTransactionManager transactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
return transactionManager;
}
}
-
@Configuration
:这个spring注解说的是,它是配置类。 -
@EnableTransactionManagement
:此注解允许用户在应用程序中使用事务管理。 -
@EnableJpaRepositories("com.journaldev.spring.repository")
:表示存储库类所在的位置。 -
@PropertySource("classpath:database.properties")
:表示我们的类路径中有属性文件。此文件中的值将被注入到环境变量中。database.properties 文件的内容如下所示。driver=org.postgresql.Driver url=jdbc:postgresql://127.0.0.1:5432/postgres user=postgres password=postgres hibernate.dialect=org.hibernate.dialect.PostgreSQL82Dialect hibernate.show_sql=true
-
要使用 Spring Data,首先我们必须配置
DataSource
bean。然后我们需要配置LocalContainerEntityManagerFactoryBean
bean。我们需要这个 bean 来控制实体。在这个 bean 中,您必须指定持久性提供程序,即HibernatePersistence
在我们的例子中。 -
下一步是配置 bean 进行事务管理。在我们的示例中是
JpaTransactionManager
。请注意,如果不配置事务管理器,我们就无法使用@Transactional
注释。
AppInitializer
and WebConfig
classes are to configure our application as web application without using web.xml file.
Model Class
package com.journaldev.spring.model;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name = "people")
public class Person {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "age")
private Integer age;
@Column(name = "first_name")
private String firstName;
@Column(name = "last_name")
private String lastName;
public Person() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
@Override
public String toString() {
return "Person{" + "id=" + id + ", age=" + age + ", firstName='" + firstName + '\'' + ", lastName='" + lastName
+ '\'' + '}';
}
}
Here we have a few new annotations. Let’s talk about them in more detail.
- @Entity: This annotation allows entity manager to use this class and puts it in context.
- @Table(name = “people”): associates a class with a table in the database.
@Id
: says that this field is the primary key.@GeneratedValue(strategy = GenerationType.IDENTITY)
: Defines the strategy for generating the primary key.@Column(name = "age")
: denotes a column in the database with which this field will be associated.
Spring Data JPA Repository
Next step is to create the JPA repository.
package com.journaldev.spring.repository;
import org.springframework.data.repository.CrudRepository;
import com.journaldev.spring.model.Person;
import java.util.List;
public interface PersonRepository<P> extends CrudRepository<Person, Long> {
List<Person> findByFirstName(String firstName);
}
By inheriting from CrudRepository
, we can call many methods without the need to implement them ourself. Some of these methods are:
- save
- findOne
- exists
- findAll
- count
- delete
- deleteAll
We can also define our own methods. These method names should use special keywords such as “find”, “order” with the name of the variables. Spring Data JPA developers have tried to take into account the majority of possible options that you might need. In our example findByFirstName(String firstName)
method returns all entries from table where field first_name
equals to firstName
. This is one of the most important feature of Spring Data JPA because it reduces a lot of boiler plate code. Also the chances of errors are less because these Spring methods are well tested by many projects already using them.
Spring Service Class
Now that our Spring Data JPA code is ready, next step is to create service class and define methods that we will have to work with database table.
package com.journaldev.spring.services;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.journaldev.spring.model.Person;
import com.journaldev.spring.repository.PersonRepository;
@Service
public class PersonService {
@Autowired
PersonRepository<Person> personRepository;
@Transactional
public List<Person> getAllPersons() {
return (List<Person>) personRepository.findAll();
}
@Transactional
public List<Person> findByName(String name) {
return personRepository.findByFirstName(name);
}
@Transactional
public Person getById(Long id) {
return personRepository.findOne(id);
}
@Transactional
public void deletePerson(Long personId) {
personRepository.delete(personId);
}
@Transactional
public boolean addPerson(Person person) {
return personRepository.save(person) != null;
}
@Transactional
public boolean updatePerson(Person person) {
return personRepository.save(person) != null;
}
}
@Transactional
annotation indicates that the method will be executed in the transaction. Spring will take care of transaction management.
Spring Controller Class
Final step is to create the controller class to expose our APIs to outer world.
package com.journaldev.spring.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import com.journaldev.spring.model.Person;
import com.journaldev.spring.services.PersonService;
@RestController
public class PersonController {
@Autowired
PersonService personService;
@RequestMapping(value = "/person/{id}", method = RequestMethod.GET)
public @ResponseBody Person getAllUsers(@PathVariable Long id) {
return personService.getById(id);
}
@RequestMapping(value = "/personByName/{name}", method = RequestMethod.GET)
public List<Person> getPersoneByName(@PathVariable String name) {
return personService.findByName(name);
}
@RequestMapping(value = "/person", method = RequestMethod.GET)
public List<Person> getAll() {
return personService.getAllPersons();
}
@RequestMapping(value = "/person/{id}", method = RequestMethod.DELETE)
public HttpStatus deletePersnone(@PathVariable Long id) {
personService.deletePerson(id);
return HttpStatus.NO_CONTENT;
}
@RequestMapping(value = "/person", method = RequestMethod.POST)
public HttpStatus insertPersone(@RequestBody Person person) {
return personService.addPerson(person) ? HttpStatus.CREATED : HttpStatus.BAD_REQUEST;
}
@RequestMapping(value = "/person", method = RequestMethod.PUT)
public HttpStatus updatePerson(@RequestBody Person person) {
return personService.updatePerson(person) ? HttpStatus.ACCEPTED : HttpStatus.BAD_REQUEST;
}
}
Spring Data JPA Testing
Just build and deploy the project into your favorite servlet container such as Tomcat. Below images show the response for some of the API calls.
Spring Data JPA Read All
Spring Data JPA Get By Name
Spring Data JPA Create
Spring Data JPA Update
Spring Data JPA Delete
That’s all for Spring Data JPA example tutorial. You can download the final project from below link.
Download Spring Data JPA Example Project
Reference: Official Website