Spring Data JPA

Spring Data JPA是Spring Data家族的一部分。Spring Data使得创建使用新方式访问数据的Spring驱动应用程序变得更加容易,例如非关系型数据库、MapReduce框架、云服务,以及先进的关系数据库支持。本文将讨论Spring Data JPA。我们还将看一下Spring Data JPA示例应用程序。

Spring Data JPA

Spring Data JPA提供的一些很酷的功能包括:

  1. 创建并支持使用Spring和JPA创建的存储库
  2. 支持QueryDSL和JPA查询
  3. 对领域类进行审计
  4. 支持批量加载、排序、动态查询
  5. 支持实体的XML映射
  6. 通过使用CrudRepository减少通用CRUD操作的代码量

何时使用Spring Data JPA?

I would say that if you need to quickly create a JPA-based repository layer that is mainly for CRUD operations, and you do not want to create abstract DAO, implementing interfaces, Spring Data JPA is a good choice.

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示例项目添加以下依赖项。

  1. postgresql: Postgresql Java驱动程序。
  2. spring-corespring-context:Spring框架核心依赖。Spring框架核心依赖。
  3. spring-webmvcjackson-databind:用于Spring REST应用程序。
  4. spring-data-jpahibernate-entitymanager:用于Spring数据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"):表示我们的类路径中有属性文件。将从该文件中注入环境变量的值。数据库属性文件的内容如下。

    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 注解

AppInitializerWebConfig 类用于配置我们的应用程序作为 Web 应用程序,而无需使用 web.xml 文件。

模型类

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
				+ '\'' + '}';
	}
}

这里我们有一些新的注解。让我们更详细地讨论它们。

  • @Entity:此注解允许实体管理器使用此类并将其放入上下文中。
  • @Table(name = “people”): 将一个类与数据库中的表关联起来。
  • @Id:表示该字段是主键。
  • @GeneratedValue(strategy = GenerationType.IDENTITY): 定义生成主键的策略。
  • @Column(name = "age"): 表示数据库中的一列,该列将与此字段关联。

Spring Data JPA Repository

下一步是创建 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);
}

通过继承 CrudRepository,我们可以调用许多方法而无需自己实现它们。其中一些方法包括:

  • save
  • findOne
  • exists
  • findAll
  • count
  • delete
  • deleteAll

我们还可以定义自己的方法。这些方法名应该使用特殊关键字,如“find”、“order”与变量名一起。Spring Data JPA 开发人员已经尽力考虑到了您可能需要的大多数选项。在我们的例子中,findByFirstName(String firstName) 方法返回表中所有字段 first_name 等于 firstName 的条目。这是 Spring Data JPA 的最重要功能之一,因为它减少了大量样板代码。而且,出错的机会较小,因为这些 Spring 方法已经被许多项目充分测试过了。

Spring 服务类

现在我们的 Spring Data JPA 代码已经准备好了,下一步是创建服务类并定义我们将要使用的与数据库表交互的方法。

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 注解表示该方法将在事务中执行。Spring 将负责事务管理。

Spring 控制器类

最后一步是创建控制器类,将我们的 API 暴露给外部世界。

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 测试

只需构建并部署项目到您喜爱的 Servlet 容器,如 Tomcat。以下图片显示了一些 API 调用的响应。

Spring Data JPA 读取全部

Spring Data JPA 通过名称获取

Spring Data JPA 创建

Spring Data JPA 更新

Spring Data JPA 删除

这就是关于Spring Data JPA示例教程的全部内容。您可以从以下链接下载最终项目。

下载Spring Data JPA示例项目

参考:官方网站

Source:
https://www.digitalocean.com/community/tutorials/spring-data-jpa