引言:该文档是参考尚硅谷的关于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. Jenkins自动打包相关操作

    Jenkins安装 Jenkins作为一个开源的集成工具,不仅可以用来进行android打包 ,也可以用来进行ios java 服务打包 官方地址https://jenkins.io/ 选择对应的系统 ...

  2. JMeter接口自动化测试实例—JMeter引用javaScript

    Jmeter提供了JSR223 PreProcessor前置处理器,通过该工具融合了Java 8 Nashorn 脚本引擎,可以执行js脚本以便对脚本进行前置处理.其中比较典型的应用就是通过执行js脚 ...

  3. 基于FPGA的视频时序生成

    之前用FPGA做过视频时序方面的设计,现将视频时序的设计方法分享给大家,希望对大家有所帮助. 时序部分可以参考CEA-861D,VESA时序标准. 1080P一帧视频中,一行有2200个像素,其中28 ...

  4. windows10上安装mysql(详细步骤)

    2016年09月06日 08:09:34 阅读数:46198 环境:windwos 10(1511) 64bit.mysql 5.7.14 时间:2016年9月5日 一.下载mysql 1. 在浏览器 ...

  5. centos7 安装oracle 11g数据库

    1.新建oracle用户 groupadd oracle useradd -g oracle oracle .修改操作系统核心参数 在Root用户下执行以下步骤: 1)修改用户的SHELL的限制,修改 ...

  6. Objective-C RunTime 学习笔记 之 atomic/nonatomic 关键字

    atomic修饰的是变量/方法,对于可变对象的指针变量是安全的,内部实现加了锁,但是对可变对象本身没什么影响,不安全还是不安全.另外atomic仅仅对编译器生产的getter.setter有效,如果自 ...

  7. 使用Shader制作loading旋转动画

    效果图: 1.绕Z轴旋转的旋转矩阵 2.UV旋转的步骤 (1) 由于旋转矩阵是绕原点旋转的,要把要旋转的UV坐标平移到原点 i.uv -= float2(0.5, 0.5); float2 tempU ...

  8. laravel 自动加载 自定义的文件/辅助函数

    需求 在 laravel 中自定义了一些 辅助函数,想要laravel框架自动加载这些函数 实现 将自定义的辅助函数放在helpers.php文件中,如下: 在compsoer.json 的 auto ...

  9. python pprint模块

    pprint模块 提供了打印出任何python数据结构类和方法. 模块方法: 1.class pprint.PrettyPrinter(indent=1,width=80,depth=None, st ...

  10. qemu到kvm的处理,再到vm的运行

    1.QEMU创建虚拟机发起:kvm_ioctl(s, KVM_CREATE_VM, type); KVM中kvm_dev_ioctl判断参数->kvm_dev_ioctl_create_vm-& ...