Spring Data JPA完全指南:从入门到精通的Java持久层框架教程

Spring Data JPA详解(第1部分,共4部分)

Spring Data JPA 是 Spring Data 家族的一部分。Spring Data 使得创建使用新的数据访问方式(如非关系型数据库、映射减少框架、云服务以及高级关系型数据库支持)的基于 Spring 的应用程序变得更加容易。本文将讨论 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?

我认为,如果你需要快速创建一个主要用于CRUD操作的基于JPA的存储库层,并且不想创建抽象DAO、实现接口,那么Spring Data JPA是一个不错的选择。

Spring Data JPA示例

在我们的Spring Data JPA示例中,我们将创建一个连接到Postgresql数据库的RESTful Web服务。我们将实现基本的CRUD操作,并在我们已经创建的示例数据上进行操作。

示例数据

使用以下查询在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);

Maven 项目结构

Spring Data JPA, Spring JPA Example

Maven依赖

我们需要为我们的Spring Data JPA示例项目添加以下依赖项。

  1. PostgreSQL:PostgreSQL Java驱动程序。
  2. Spring-core,spring-context:Spring框架核心依赖。
  3. Spring-webmvc,jackson-databind:用于Spring REST应用程序。
  4. 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.Olivia</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 配置类

这是文章《春天的数据JPA》的第2部分(共4部分)。

package com.Olivia.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.Olivia.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.Olivia.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.Olivia.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和WebConfig类来配置我们的应用程序为web应用程序,而不需要使用web.xml文件。

模型类

package com.Olivia.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: 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 仓库下一步是创建JPA存储库。

package com.Olivia.spring.repository;

import org.springframework.data.repository.CrudRepository;

import com.Olivia.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 Data JPA代码已经准备就绪,下一步就是创建服务类并定义我们将用于操作数据库表的方法。

package com.Olivia.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.Olivia.spring.model.Person;
import com.Olivia.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控制器类
这是文章《Spring Data JPA入门指南》的第4部分(共4部分)。

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

package com.Olivia.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.Olivia.spring.model.Person;
import com.Olivia.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 Example Read All
通过名称获取Spring Data JPA数据
Spring JPA Read
使用Spring Data JPA进行创建
Spring Data JPA Create
Spring Data JPA 更新数据
Spring Data JPA Update
Spring Data JPA 删除数据
Spring Data JPA Example Delete

下载Spring Data JPA示例项目

参考资料:Spring官方网站

bannerAds