SpringCloud集成Spring Data JPA
Spring Data
Spring Data是Spring家族中最重要的核心成员之一,在Spring Data中,其专门为Spring提供了用于数据访问的抽象框架,其核心理念是支持对所有的存储进行资源配置从而实现数据访问。
数据的访问,需要完成领域对象与存储数据之间的映射并对外提供访问入口。而Spring Data基于Repository模式并抽象出一套实现该模式的统一数据访问方式。
源码
springcloud-parent2父Maven模块
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>
<packaging>pom</packaging>
<modules>
<module>spring-data</module>
</modules>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.4.RELEASE</version>
</parent>
<groupId>com.lyc</groupId>
<artifactId>springcloud-parent2</artifactId>
<version>1.0-SNAPSHOT</version>
<name>springcloud-parent2</name>
<!--导入SpringCloud的依赖管理-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Dalston.SR3</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- lombok依赖 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.4</version>
</dependency>
</dependencies>
</project>
spring-data子Maven模块
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">
<parent>
<artifactId>springcloud-parent2</artifactId>
<groupId>com.lyc</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-data</artifactId>
<name>spring-data</name>
<dependencies>
<!-- mysql驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- jpa -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
</dependencies>
</project>
application.yml配置文件
# spring连接数据库驱动
spring:
datasource:
driverClassName: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/spring_data??useUnicode=true&characterEncoding=UTF-8&useSSL=false
username: root
password: root
# jpa自动创建不存在的数据表
jpa:
show-sql: true
hibernate:
ddl-auto: update
use-new-id-generator-mappings: true
jackson:
serialization:
indent_output: false
SpringDataApplication启动类
package com.lyc.springData;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @author: zhangzhenyi
* @date: 2019/3/10 15:25
* @description: SpringData启动类
**/
@SpringBootApplication
public class SpringDataApplication {
public static void main(String[] args) {
SpringApplication.run(SpringDataApplication.class,args);
}
}
PersonController类
package com.lyc.springData.controller;
import com.lyc.springData.entity.Person;
import com.lyc.springData.service.PersonRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* @author: zhengzhenyi
* @date: 2019/3/10 15:27
* @description: Person Controller
**/
@RestController
public class PersonController {
@Autowired
PersonRepository personRepository;
/**
* 保存,没有数据表时创建数据表
* @param name 姓名
* @param address 地址
* @param age 年龄
* @return
*/
@GetMapping("/save")
public Person save(String name, String address, Integer age){
return personRepository.save(new Person(name,age,address));
}
/**
* 根据地址进行信息查询
* @param address 地址
* @return
*/
@GetMapping("/address")
public List<Person> address(String address){
return personRepository.findByAddress(address);
}
/**
* 方法一
* 根据姓名与地址进行信息查询
* @param name 姓名
* @param address 地址
* @return
*/
@GetMapping("/nameAndAddress")
public Person nameAndAddress(String name,String address){
return personRepository.findByNameAndAddress(name,address);
}
/**
* 方法二
* 根据姓名与地址进行信息查询
* @param name 姓名
* @param address 地址
* @return
*/
@GetMapping("/nameAndAddressQuery")
public Person nameAndAddressQuery(String name,String address){
return personRepository.withNameAndAddressQuery(name,address);
}
/**
* 方法三
* 根据姓名与地址进行信息查询
* @param name 姓名
* @param address 地址
* @return
*/
@GetMapping("/nameAndAddressNamedQuery")
public Person nameAndAddressNamedQuery(String name,String address){
return personRepository.withNameAndAddressNamedQuery(name,address);
}
/**
* 排序
* @return
*/
@GetMapping("/sort")
public List<Person> sort(){
return personRepository.findAll(new Sort(Sort.Direction.ASC,"age"));
}
/**
* 分页
* @return
*/
@GetMapping("/page")
public Page<Person> page(){
return personRepository.findAll(new PageRequest(1,2));
}
}
PersonRepository类
package com.lyc.springData.service;
import com.lyc.springData.entity.Person;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import java.util.List;
/**
* @author: zhengzhenyi
* @date: 2019/3/10 15:27
* @description: Person Repository
**/
public interface PersonRepository extends JpaRepository<Person,Long> {
/**
* 查询地址
* @param address 地址
* @return
*/
List<Person> findByAddress(String address);
/**
* 方法一
* 根据姓名和地址查询
* @param name 姓名
* @param address 地址
* @return
*/
Person findByNameAndAddress(String name, String address);
/**
* 方法二
* 根据姓名和地址查询
* @param name 姓名
* @param address 地址
* @return
*/
@Query("select p from Person p where p.name = :name and p.address = :address")
Person withNameAndAddressQuery(@Param("name") String name, @Param("address") String address);
/**
* 方法三
* 根据姓名和地址查询
* @param name 姓名
* @param address 地址
* @return
*/
Person withNameAndAddressNamedQuery(String name, String address);
}
Person实体类
package com.lyc.springData.entity;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.NamedQuery;
/**
* @author: zhangzhenyi
* @date: 2019/3/10 11:02
* @description: Person实体类
**/
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Entity
@SuppressWarnings("JpaQlInspection")
@NamedQuery(name = "Person.withNameAndAddressNamedQuery"
,query = "select p from Person p where p.name = ?1 and p.address = ?2")
public class Person {
@Id
@GeneratedValue
private Long id; //主键id
private String name; //姓名
private Integer age; //年龄
private String address; //地址
public Person(String name, Integer age, String address) {
this.name = name;
this.age = age;
this.address = address;
}
}
运行
在Restlet中,通过输入下面的路径来进行访问:
http://localhost:8080/save?name=zhangsan&address=hebei&age=20
如下图所示,就是将Person信息进行持久化操作。
分析
在PersonRepository
中,我们可以看到下面的代码:
@Query(“select p from Person p where p.name = :name and p.address = :address”)
Person withNameAndAddressQuery(@Param(“name”) String name, @Param(“address”) String address);
这说明,在Spring Data中,除了对领域对象提供默认的CRUD操作外,还重点对查询场景做了高度的抽象。我们可以通过@Query
注解直接在代码中嵌入查询语句和条件从而完成领域对象与数据存储的自动映射,提供类似ORM(Object Relational Mapping,对象关系映射)框架所具有的强大功能。
同样在PersonRepository
中,我们可以使用方法名衍生查询,该查询也是Spring Data中的特色查询之一,如下面所示的代码:
List findByAddress(String address);
通过在方法名上直接使用查询字段和参数,Spring Data就能够自动识别相应的查询条件并组装对应的查询语句。
在Spring Data中,其还为我们提供了常见的分页与排序查询,比如说Spring Data为我们提供了Pageable和Sort抽象。通过构建Pageable分页对象和Sort查询对象,典型的查询方式如下:
Pageable分页对象
@GetMapping("/page")
public Page page(){
return personRepository.findAll(new PageRequest(1,2));
}
Sort查询对象
@GetMapping("/sort")
public List sort(){
return personRepository.findAll(new Sort(Sort.Direction.ASC,“age”));
}
在上面的代码中,我们展示了Person
这一常见的业务领域模型,在该模型中,@Entity
代表实体类的注解,同时我们也看到了用于命名查询的@NamedQuery
注解。
@NamedQuery
注解主要用于对某一个查询条件进行命名,在示例中,我们使用了Person.withNameAndAddressNamedQuery
对select p from Person p where p.name = ?1 and p.address = ?2
这一查询进行命名以方便在Repository中进行复用。
通过在application.yml
配置文件中的
# jpa自动创建不存在的数据表
jpa:
show-sql: true
hibernate:
ddl-auto: update
use-new-id-generator-mappings: true
jackson:
serialization:
indent_output: false
我们可以实现通过调用PersonController.save(String name, String address, Integer age)
方法,将我们的数据保存到数据表中。当然,如果数据表不存在,则JPA会自动帮我们先创建一张空数据表,然后再保存数据。