Spring Data JPA简介
Spring Data JPA是Spring Data家族的一部分,可以轻松实现基于JPA的存储库。 此模块处理对基于JPA的数据访问层的增强支持。 它使构建使用数据访问技术的Spring驱动应用程序变得更加容易。
在相当长的一段时间内,实现应用程序的数据访问层一直很麻烦。 必须编写太多样板代码来执行简单查询以及执行分页和统计。 Spring Data JPA旨在通过减少实际需要的工作量来显著改善数据访问层的实现。 作为开发人员,编写repository接口,包括自定义查找器方法,Spring将自动提供实现。
Spring Data JPA 和JPA 和Hibernate之间的关系
JPA是一套规范,内部是有接口和抽象类组成的。hibernate是一套成熟的ORM框架,而且Hibernate实现了JPA规范,所以也可以称hibernate为JPA的一种实现方式,我们使用JPA的API编程,意味着站在更高的角度上看待问题(面向接口编程)
Spring Data JPA是Spring提供的一套对JPA操作更加高级的封装,是在JPA规范下的专门用来进行数据持久化的解决方案。
总的来说JPA是ORM规范,Hibernate、TopLink等是JPA规范的具体实现,这样的好处是开发者可以面向JPA规范进行持久层的开发,而底层的实现则是可以切换的。Spring Data Jpa则是在JPA之上添加另一层抽象(Repository层的实现),极大地简化持久层开发及ORM框架切换的成本。
Spring Data JPA快速入门
1. 创建SpringBoot项目,引入依赖
<?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>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.lzx.spring-data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-data-jpa</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>utf-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
</project>
2. 设置配置信息
#---------------------------------------
# db
#---------------------------------------
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/spider?serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=123
#---------------------------------------
# spring data jpa
#---------------------------------------
#设置打印sql语句
spring.jpa.show-sql=true
#设置数据库类型
spring.jpa.database=mysql
#设置打印ddl语句
spring.jpa.generate-ddl=true
#设置数据库表效验 update:每次运行程序,没有表时创建表,如果对象属性发生改变,会更新表结构,不会清空数据
spring.jpa.hibernate.ddl-auto=update
#设置命名策略
spring.jpa.hibernate.naming.physical-strategy=org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy
ddl-auto
create
:每次运行程序时,都会重新创建表,故而数据会丢失create-drop
:每次运行程序时会先创建表结构,然后待程序结束时清空表upadte
:每次运行程序,没有表时会创建表,如果对象发生改变会更新表结构,原有数据不会清空,只会更新(推荐使用)validate
:运行程序会校验数据与数据库的字段类型是否相同,字段不同会报错none
: 禁用DDL处理
3. 编写实体类,Repository接口
package com.lzx.springdata.springDataJpa.pojo;
import javax.persistence.*;
import java.util.Date;
@Entity
@Table(name = "article")
public class Article {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String title;
private String content;
private Date create_time;
private String user;
private Integer read_count;
@Override
public String toString() {
return "Article{" +
"id=" + id +
", title='" + title + '\'' +
", content='" + content + '\'' +
", create_time=" + create_time +
", user='" + user + '\'' +
", read_count=" + read_count +
'}';
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public Date getCreate_time() {
return create_time;
}
public void setCreate_time(Date create_time) {
this.create_time = create_time;
}
public String getUser() {
return user;
}
public void setUser(String user) {
this.user = user;
}
public Integer getRead_count() {
return read_count;
}
public void setRead_count(Integer read_count) {
this.read_count = read_count;
}
}
package com.lzx.springdata.springDataJpa.dao;
import com.lzx.springdata.springDataJpa.pojo.Article;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
/**
* JpaRepository<实体类类型,主键类型>:用来完成基本CRUD操作
* JpaSpecificationExecutor<实体类类型>:用于复杂查询(分页等查询操作)
*/
public interface ArticleRepository extends JpaRepository<Article,Integer>, JpaSpecificationExecutor<Article> {
}
4. 测试
package com.lzx.springdata.springDataJpa.controller;
import com.lzx.springdata.springDataJpa.dao.ArticleRepository;
import com.lzx.springdata.springDataJpa.pojo.Article;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Date;
@RestController
public class DemoController {
@Autowired
private ArticleRepository articleRepository;
@RequestMapping("/add")
public String demo1(){
Article article = new Article();
article.setContent("165161");
article.setCreate_time(new Date());
article.setUser("lzx");
article.setTitle("1");
article.setRead_count(0);
//保存该对象
articleRepository.save(article);
return "sucess";
}
/**
* 对于save方法,会先根据id进行查询 如果有该id 则进行更新操作 如果没有 则进行删除操作
* @return
*/
@RequestMapping("/update")
public String demo2(){
//根据id查询
Article article = articleRepository.getOne(1);
//修改标题
article.setTitle("111111111");
//更新数据库
articleRepository.save(article);
return "sucess";
}
@RequestMapping("/delete")
public String demo3(){
//根据id删除
articleRepository.deleteById(1);
return "sucess";
}
@RequestMapping("/query")
public String demo4(){
//根据id查询
Article one = articleRepository.getOne(1);
System.out.println(one);
return "sucess";
}
}
Spring Data JPA的查询方式
JpaRepository接口提供的方法
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package org.springframework.data.jpa.repository;
import java.util.List;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Sort;
import org.springframework.data.repository.NoRepositoryBean;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.repository.query.QueryByExampleExecutor;
@NoRepositoryBean
public interface JpaRepository<T, ID> extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {
List<T> findAll();
List<T> findAll(Sort var1);
List<T> findAllById(Iterable<ID> var1);
<S extends T> List<S> saveAll(Iterable<S> var1);
void flush();
<S extends T> S saveAndFlush(S var1);
void deleteInBatch(Iterable<T> var1);
void deleteAllInBatch();
T getOne(ID var1);
<S extends T> List<S> findAll(Example<S> var1);
<S extends T> List<S> findAll(Example<S> var1, Sort var2);
}
JPQL查询方式
使用Spring Data JPA提供的查询方法已经可以解决大部分的应用场景,但是对于某些业务来说,我们还需要灵活的构造查询条件,这时就可以使用@Query注解,结合JPQL的语句方式完成查询
@Query 注解的使用非常简单,只需在方法上面标注该注解,同时提供一个JPQL查询语句即可
public interface ArticleRepository extends JpaRepository<Article, Integer>,JpaSpecificationExecutor<Article> {
//@Query 使用jpql的方式查询。
@Query(value="from Article")
public List<Article> findAllArticle();
//@Query 使用jpql的方式查询。?1代表参数的占位符,其中1对应方法中的参数索引
@Query(value="from Article where title = ?1")
public Customer findArticle(String title);
}
此外,也可以通过使用 @Query 来执行一个更新操作,为此,我们需要在使用 @Query 的同时,用 @Modifying 来将该操作标识为修改查询,这样框架最终会生成一个更新的操作,而非查询
@Query(value="update Article set title = ?1 where id = ?2")
@Modifying
public void updateArticle(String title,Integer Id);
SQL查询方式
Spring Data JPA同样也支持sql语句的查询,如下
/**
* nativeQuery : 使用本地sql的方式查询
*/
@Query(value="select * from article",nativeQuery=true)
public void findSql();
方法命名规则查询
顾名思义,方法命名规则查询就是根据方法的名字,就能创建查询。只需要按照Spring Data JPA提供的方法命名规则定义方法的名称,就可以完成查询工作。Spring Data JPA在程序执行的时候会根据方法名称进行解析,并自动生成查询语句进行查询
按照Spring Data JPA 定义的规则,查询方法以findBy开头,涉及条件查询时,条件的属性用条件关键字连接,要注意的是:条件属性首字母需大写。框架在进行方法名解析时,会先把方法名多余的前缀截取掉,然后对剩下部分进行解析。
具体的关键字,使用方法和生产成SQL如下表所示