引言:该文档是参考尚硅谷的关于springboot教学视屏后整理而来。当然后面还加入了一些自己从网上收集整理而来的案例!

一、SpringData JPA初步使用

1. springdata简介

2. springboot整合springdata jpa(这是一个最简单的集成案例)

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> <groupId>com.atguigu</groupId>
<artifactId>spring-boot-06-data-jpa</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging> <name>spring-boot-06-data-jpa</name>
<description>Demo project for Spring Boot</description> <parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.10.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent> <properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<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-jdbc</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency> <!--lombok插件-->
<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>
</plugins>
</build> </project>

application.yml中配置如下:

spring:
datasource:
url: jdbc:mysql://192.168.15.22/jpa
username: root
password: 123456
driver-class-name: com.mysql.jdbc.Driver
jpa:
hibernate:
# 更新或者创建数据表结构
ddl-auto: update
# 控制台显示SQL
show-sql: true

建表sql:

/*
Navicat Premium Data Transfer Source Server : 47.98.202.86
Source Server Type : MySQL
Source Server Version : 50721
Source Host : 47.98.202.86:3306
Source Schema : springboot Target Server Type : MySQL
Target Server Version : 50721
File Encoding : 65001 Date: 09/04/2019 23:51:27
*/ SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0; -- ----------------------------
-- Table structure for tbl_user
-- ----------------------------
DROP TABLE IF EXISTS `tbl_user`;
CREATE TABLE `tbl_user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`last_name` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`email` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; -- ----------------------------
-- Records of tbl_user
-- ----------------------------
INSERT INTO `tbl_user` VALUES (1, '刘亦菲', '123@qq.com');
INSERT INTO `tbl_user` VALUES (2, '唐嫣', '123@qq.com');
INSERT INTO `tbl_user` VALUES (3, '??', 'aa'); SET FOREIGN_KEY_CHECKS = 1;

实体类User:

package com.atguigu.springboot.entity;

import lombok.Data;

import javax.persistence.*;

//使用JPA注解配置映射关系
@Entity //告诉JPA这是一个实体类(和数据表映射的类)
@Table(name = "tbl_user") //@Table来指定和哪个数据表对应;如果省略默认表名就是user;
@Data
public class User { @Id //这是一个主键
@GeneratedValue(strategy = GenerationType.IDENTITY)//自增主键
private Integer id; @Column(name = "last_name",length = 50) //这是和数据表对应的一个列
private String lastName;
@Column //省略默认列名就是属性名
private String email; }

数据层接口UserRepository:

package com.atguigu.springboot.repository;

import com.atguigu.springboot.entity.User;
import org.springframework.data.jpa.repository.JpaRepository; //继承JpaRepository来完成对数据库的操作
public interface UserRepository extends JpaRepository<User,Integer> {
}

Controller层UserController:这里省略了service,主要是为了测试集成springdata jpa

package com.atguigu.springboot.controller;

import com.atguigu.springboot.entity.User;
import com.atguigu.springboot.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController; @RestController
public class UserController { @Autowired
UserRepository userRepository; @GetMapping("/user/{id}")
public User getUser(@PathVariable("id") Integer id){
User user = userRepository.findOne(id);
return user;
} @GetMapping("/user")
public User insertUser(User user){
User save = userRepository.save(user);
return save;
} }

测试(这里只是通过get请求简单的测试):

  查询用户id=2的员工,访问网址:http://localhost:8080/user/2

      返回结果:{"id":2,"lastName":"唐嫣","email":"123@qq.com"}

  增加一个用户,访问网址:http://localhost:8080/user?lastName=王菲&email=aa

      返回结果为:{"id":3,"lastName":"王菲","email":"aa"}

二、springdata jpa 详解

1. springdata jpa 中的接口

 先参考【Spring Data JPA--接口方法】,后期在自己整理!

2. 实现复杂查询  参考:https://www.cnblogs.com/zjfjava/p/8456771.html

(1)基于方法名解析的概念

JpaRepository支持接口规范方法名查询。意思是如果在接口中定义的查询方法符合它的命名规则,就可以不用写实现。
  spring-data-jpa会根据方法的名字来自动生成sql语句,我们只需要按照方法定义的规则即可;

例如:findByName(String name): 这个方法表示从数据库中查询Name这个属性等于XXX的所有记录
       类似于SQL语句:select * from xxTable where name=xxx这种形式

这段话有两个重点:方法名需要在接口中设定; 必须符合一定的命名规范;

(2)方法名构造方法

      find+全局修饰+By+实体的属性名称+限定词   + 连接词+ ...(其它实体属性)+OrderBy+排序属性+排序方向
例如:find Distinct By FirstName IgnoreCase And LastName OrderBy Age Desc(String firstName,String lastName);
findDistinctByFirstNameIgnoreCaseAndLastNameOrderByAgeDesc(String firstName,String lastName)
其中:
Distinct是全局修饰(非必须),
FirstName和LastName是实体的属性名,
And是连接词,
IgnoreCase是限定词,
Age是排序属性,
Desc是排序方向,限定词和连接词统称为“关键词”。
spring-data-jpa规定,在属性后面接关键字.

(3)目前支持的关键词
  全局修饰:Distinct,Top,First
  排序方向:Asc,Desc

关键字:

And                findByLastnameAndFirstname        … where x.lastname = ?1 and x.firstname = ?2
Or findByLastnameOrFirstname … where x.lastname = ?1 or x.firstname = ?2
Is,Equals findByFirstname,findByFirstnameIs,findByFirstnameEquals … where x.firstname = ?1
Between findByStartDateBetween … where x.startDate between ?1 and ?2
LessThan findByAgeLessThan … where x.age < ?1
LessThanEqual findByAgeLessThanEqual … where x.age <= ?1
GreaterThan findByAgeGreaterThan … where x.age > ?1
GreaterThanEqual findByAgeGreaterThanEqual … where x.age >= ?1
After findByStartDateAfter … where x.startDate > ?1
Before findByStartDateBefore … where x.startDate < ?1
IsNull findByAgeIsNull … where x.age is null
IsNotNull,NotNull findByAge(Is)NotNull … where x.age not null
Like findByFirstnameLike … where x.firstname like ?1
NotLike findByFirstnameNotLike … where x.firstname not like ?1
StartingWith findByFirstnameStartingWith … where x.firstname like ?1 (parameter bound with appended %)
EndingWith findByFirstnameEndingWith … where x.firstname like ?1 (parameter bound with prepended %)
Containing findByFirstnameContaining … where x.firstname like ?1 (parameter bound wrapped in %)
OrderBy findByAgeOrderByLastnameDesc … where x.age = ?1 order by x.lastname desc
Not findByLastnameNot … where x.lastname <> ?1
In findByAgeIn(Collection<Age> ages) … where x.age in ?1
NotIn findByAgeNotIn(Collection<Age> ages) … where x.age not in ?1
TRUE findByActiveTrue() … where x.active = true
FALSE findByActiveFalse() … where x.active = false
IgnoreCase findByFirstnameIgnoreCase … where UPPER(x.firstame) = UPPER(?1)

(4)嵌套实体方法命名规则

构词法:主实体中子实体的名称+ _ +子实体的属性名称

例如:
List<Person> findByAddress_ZipCode(ZipCode zipCode)
表示查询所有 Address(地址)的zipCode(邮编)为指定值的所有Person(人员) //查询需求: 从数据库中查询电话号码(phone)以指定字符串开始(例如:136)的,并且地址(address)中包含指定字符串(例如:路)的记录; 提取前两条,降序排列
//select * from user where phone like '136%' and address like '%路%' order by phone desc limit 0,2
List<User> findTop2ByPhoneStartingWithAndAddressContainingOrderByPhoneDesc(String phone,String address);
List<User> findTop2ByPhoneStartingWithAndAddressContaining(String phone,String address,Sort sort);
//分页要用到Pageable接口
Page<User> findByPhoneStartingWithAndAddressContaining(String phone,String address,Pageable pageable);

 三、Criteria(条件)查询

转载:SpringDataJpa的Specification查询   Specification动态构建多表查询

相应的接口是JpaSpecificationExecutor,这个接口基本是围绕着Specification接口来定义的, Specification接口(JPA)中只定义了如下一个方法:

Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb); 这个方法的参数和返回值都是JPA标准里面定义的对象。

1、Criteria(条件)查询基本概念:

Root接口:代表Criteria查询的根对象,Criteria查询的查询根定义了实体类型,能为将来导航获得想要的结果,它与SQL查询中的FROM子句类似;

  (1) Root实例是类型化的,且定义了查询的FROM子句中能够出现的类型;

  (2) 查询根实例能通过传入一个实体类型给 AbstractQuery.from方法获得;

  (3) Criteria查询,可以有多个查询根;

  (4) AbstractQuery是CriteriaQuery 接口的父类,它提供得到查询根的方法;

CriteriaQuery接口:代表一个specific的顶层查询对象,它包含着查询的各个部分,比如:select 、from、where、group by、order by等;

   注意:CriteriaQuery对象只对实体类型或嵌入式类型的Criteria查询起作用;

CriteriaBuilder接口:用来构建CritiaQuery的构建器对象Predicate:一个简单或复杂的谓词类型,其实就相当于条件或者是条件组合;

2. Criteria查询基本对象的构建

(1) 通过EntityManager的getCriteriaBuilder或EntityManagerFactory的getCriteriaBuilder方法可以得到CriteriaBuilder对象;(可以构建查询条件对象)

(2) 通过调用CriteriaBuilder的createQuery或createTupleQuery方法可以得到CriteriaQuery对象;(执行查询条件对象)

(3) 通过调用CriteriaQuery的from方法可以获得Root实例过滤条件;

a. 过滤条件会被应用到SQL语句的FROM子句中。在criteria 查询中,查询条件通过Predicate或Expression实例应用到CriteriaQuery对象上;

b. 这些条件使用 CriteriaQuery .where 方法应用到CriteriaQuery 对象上;(查询条件怎么应用到顶层查询对象上)

c. CriteriaBuilder也作为Predicate实例的工厂,通过调用CriteriaBuilder 的条件方( equal,notEqual, gt, ge,lt, le,between,like等)创建Predicate对象。

d. 复合的Predicate 语句可以使用CriteriaBuilder的and, or and not 方法构建。

构建简单的Predicate示例:

Predicate p1=cb.like(root.get(“name”).as(String.class), “%”+uqm.getName()+“%”);

Predicate p2=cb.equal(root.get("uuid").as(Integer.class), uqm.getUuid());

Predicate p3=cb.gt(root.get("age").as(Integer.class), uqm.getAge());

构建组合的Predicate示例:

Predicate p = cb.and(p3,cb.or(p1,p2));

使用实例:

(1)当然也可以形如前面动态拼接查询语句的方式,比如:

/**
* 测试条件查询
* @return
*/
@GetMapping("/user/list")
public List<User> getList(){ //假设这是前端传过来的条件
User user = new User();
user.setLastName("fei");
user.setId(1); Specification<User> spec = new Specification<User>() {
public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
//用于暂时存放查询条件的集合
List<Predicate> list = new ArrayList<Predicate>();
//------------------- 查询条件示例 -------------------------
//like示例
if (user.getLastName() != null && user.getLastName().trim().length() > 0){
// Predicate lastNamePredicate = cb.like(root.get("lastName").as(String.class), "%"+user.getLastName()+"%");
Predicate lastNamePredicate = cb.like(root.get("lastName"), '%'+user.getLastName()+'%');//和上面一句等效
list.add(lastNamePredicate);
}
//equal示例
if(user.getId() >0){
// Predicate idPredicate = cb.equal(root.get("id"), user.getId());
Predicate idPredicate = cb.equal(root.get("id").as(Integer.class), user.getId());
list.add(idPredicate);
} //between示例() 以下注释的部分,自己参照修改
// if (birthday != null) {
// Predicate birthdayPredicate = cb.between(root.get("birthday"), birthday, new Date());
// predicatesList.add(birthdayPredicate);
// }
//排序示例(先根据学号升序排序,后根据姓名升序排序)
// query.orderBy(cb.asc(root.get("studentNumber")),cb.asc(root.get("name"))); //最终将查询条件拼好然后return
Predicate[] p = new Predicate[list.size()];
return cb.and(list.toArray(p));
}
}; List<User> users = userRepository.findAll(spec);
users.forEach(System.out::println);
return users;
}

说明:以下是上面sql的打印结果,打印的应该是预编译的sql,至于为啥主键id的值被替换了?以后再做探讨,如果有大神了解,补充上!

Hibernate: select user0_.id as id1_2_, user0_.email as email2_2_, user0_.last_name as last_nam3_2_ from tbl_user user0_ where (user0_.last_name like ?) and user0_.id=1;
User(id=1, lastName=liuyifei, email=123@qq.com);

注意:此处记录下我遇到的坑,由于我只是做简单的动态条件查询测试,所以就没有考虑编码的问题,原来我在数据库中存的是中文的用户名,但是这就导致我在以上测试的时候,

     尽快代码没有问题,但是死活查不出结果,我一直在纠结我预编译的那个sql,还以为是我代码或者是yml中jpa配置的有问题,导致花了很长时间,后来我将数据库中的用户 名改为英文的就可以了!(编码问题是所有中国程序员都要考虑的问题)

(2)使用CriteriaQuery来得到最后的Predicate

/**
* 测试条件查询
* @return
*/
@GetMapping("/user/list1")
public List<User> getList1(){
User user = new User();
user.setId(1);
user.setLastName("fei");
user.setEmail("123@qq.com"); Specification<User> spec = new Specification<User>() {
public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) { Predicate p1 = cb.like(root.get("lastName").as(String.class), "%"+user.getLastName()+"%");
Predicate p2 = cb.equal(root.get("email").as(String.class), user.getEmail());
Predicate p3 = cb.gt(root.get("id").as(Integer.class), user.getId());
//把Predicate应用到CriteriaQuery中去,因为还可以给CriteriaQuery添加其他的功能,比如排序、分组啥的
query.where(cb.and(p3,cb.or(p1,p2)));
//添加排序的功能
query.orderBy(cb.desc(root.get("id").as(Integer.class))); return query.getRestriction();
}
}; List<User> users = userRepository.findAll(spec);
users.forEach(System.out::println);
return users; // sql: select user0_.id as id1_2_, user0_.email as email2_2_, user0_.last_name as last_nam3_2_ from tbl_user user0_
// where user0_.id>1 and (user0_.last_name like ? or user0_.email=?) order by user0_.id desc
// User(id=2, lastName=tanying, email=123@qq.com)
}

综上所述,我们可以用Specification的toPredicate方法构建更多更复杂的查询方法。

  

6.4 SpringData JPA的使用的更多相关文章

  1. Spring、SpringMVC、SpringData + JPA 整合详解

    原创播客,如需转载请注明出处.原文地址:http://www.cnblogs.com/crawl/p/7759874.html ------------------------------------ ...

  2. 【极简版】SpringBoot+SpringData JPA 管理系统

    前言 只有光头才能变强. 文本已收录至我的GitHub仓库,欢迎Star:https://github.com/ZhongFuCheng3y/3y 在上一篇中已经讲解了如何从零搭建一个SpringBo ...

  3. 带你搭一个SpringBoot+SpringData JPA的环境

    前言 只有光头才能变强. 文本已收录至我的GitHub仓库,欢迎Star:https://github.com/ZhongFuCheng3y/3y 不知道大家对SpringBoot和Spring Da ...

  4. 尚硅谷springboot学习34-整合SpringData JPA

    SpringData简介

  5. 一篇 SpringData+JPA 总结

    概述 SpringData,Spring 的一个子项目,用于简化数据库访问,支持 NoSQL 和关系数据库存储 SpringData 项目所支持 NoSQL 存储 MongDB(文档数据库) Neo4 ...

  6. SpringBoot整合SpringData JPA入门到入坟

    首先创建一个SpringBoot项目,目录结构如下: 在pom.xml中添加jpa依赖,其它所需依赖自行添加 <dependency> <groupId>org.springf ...

  7. JPA、SpringData JPA 、Hibernate和Mybatis 的区别和联系

    一.JPA 概述 1. Java Persistence API(Java 持久层 API):用于对象持久化的 API 2. 作用:使得应用程序以统一的方式访问持久层 3. 前言中提到了 Hibern ...

  8. 第11章—使用对象关系映射持久化数据—SpringBoot+SpringData+Jpa进行查询修改数据库

    SpringBoot+SpringData+Jpa进行查询修改数据库 JPA由EJB 3.0软件专家组开发,作为JSR-220实现的一部分.但它又不限于EJB 3.0,你可以在Web应用.甚至桌面应用 ...

  9. Springboot集成SpringData JPA

    序 StringData JPA 是微服务框架下一款ORM框架,在微服务体系架构下,数据持久化框架,主要为SpringData JPA及Mybatis两种,这两者的具体比较,本文不做阐述,本文只简单阐 ...

随机推荐

  1. stm32高级定时器的应用——spwm

    用过stm32定时器的朋友都知道,定时器的CCR寄存器,可以用来配置PWM的输出,但同样也可以用来配置spwm.废话不多说,直接上代码. 首先,你得考虑一下几个因素: 1.同步调制还是异步调制.  2 ...

  2. 常见mysql的慢查询优化方式

    一,第一步.开启mysql慢查询 方式一: 修改配置文件  在 my.ini 增加几行:  主要是慢查询的定义时间(超过2秒就是慢查询),以及慢查询log日志记录( slow_query_log) 方 ...

  3. 【转】jenkins自动化部署项目7 -- 新建job(将服务代码部署在windows上)

    关于构建结束后jenkins会kill所有衍生子进程的官方解决方案:https://wiki.jenkins.io/display/JENKINS/Spawning+processes+from+bu ...

  4. SQL实现如何计算项目进度总共天数情况、已经施工天数情况、以及施工进度百分比

    SELECT DATEDIFF(DAY,e.StartDate,e.EndDate)as totaldays, (SELECT COUNT(TaskID) from ConstructionManag ...

  5. 手把手教你如何安装Pycharm

    手把手教你如何安装Pycharm——靠谱的Pycharm安装详细教程     今天小编给大家分享如何在本机上下载和安装Pycharm,具体的教程如下: 1.首先去Pycharm官网,或者直接输入网址: ...

  6. 最新QT4.8+kernel_3.2.5+uboot_2010.06+tslib移植成功-问题小结

    2012-02-19 21:34:13 都是从源码下载然后自己修改,使用与TQ2440,之前uboot其实已经完成了.但是yaffs2没带起来.现在回头看来是很简单的了.bootargs参数中我设置成 ...

  7. OO第一单元优化博客

    OO第一单元优化博客 第一次作业: 合并同类项+提正系数项+优化系数指数0/1=满分 第二次作业: 初始想法 一开始是想以\(sin(x)​\)和\(cos(x)​\)的指数作为坐标,在图上画出来就可 ...

  8. java RSA实现私钥签名、公钥验签、私钥加密数据、公钥解密数据

    通过OpenSSL生成公私钥文件(如果没有OpenSSL工具建议下载Cmder工具自带OpenSSL指令) 1.生成RSA密钥的方法 genrsa -out private-rsa.key 2048 ...

  9. Angular ( 一 ) angular的安装

    1. 全局安装angular 脚手架工具 npm install -g @angular/cli 2. 打开到创建目录: 3. 创建项目 ng new my-app 4. 打开项目 5. 安装依赖 n ...

  10. Java处理对象

    1.打印对象和toString 方法     toString() 方法是Object 类的一个实例方法,所有的Java类都是Object类的子类,因此所有的Java对象都是具有toString()方 ...