当前位置: 首页 > news >正文

《SpringBoot篇》10.JPQL超详细介绍与JPA命名规则

陈老老老板
说明:学习一些新的技术栈,边学习边总结,需要注意的地方都标红了, 一起加油。

1.JPA最牛之拼接方法名自定义SQL语句

(1)拼接实例

说明(规则表在最下面): Hibernate作为一个全自动的ORM框架,就说明不用你写SQL语句。但是说实话,大多是适用于简单的增删改查分页和排序,对于更加复杂的场景也是需要进行写SQL的这个之后介绍。
 其实实现也非常简单,就是在repository接口中按命名规则进行拼接方法名来实现。(这里用的是JPA介绍中的接口代码)

package com.example.demo.repository;

import com.example.demo.pojo.Admin;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.stereotype.Repository;

//声明为repository
@Repository
public interface AdminRepository extends PagingAndSortingRepository<Admin,Long>  {
	//解释:select ... where emailaddress = ?1 and lastname = ?2;
	//这里的? 代表占位符,1,2, 代表方法中的第几个参数。
    List<Admin> findByEmailAddressAndLastname(String emailAddress, String lastname);
    //模糊查询
	List<Admin> findAllByUsernameLike(String username);
}

(2)JPQL说明及使用语法

说明: 如果复杂业务也可以自己写JPQL语句,这里就讲使用注解的方式,这样更加简洁方便。

简介:JPQL(Java Persistence Query Language , Java 持久化查询语言)和 SQL 之间有很多相似之处 , 它们之间主要的区别在于前者处理 JPA 实体 , 而后者则直接涉及关系数据 。 JPQL 允许我们使用 SELECT 、 UPDATE 和 DELETE 语法定义查询

语法说明:

a.查询:

1.基础查询
语法: SELECT 标识符变量 FROM 实体名称 [AS] 标识符变量

示例:查询所有的雇员信息

@Query("SELECT E FROM Employee E")
List<Employee> selectExample();

查询参数规范:

JPQL 支持两种查询参数 , 它们分别是命名参数和位置参数 。

命名参数
注意!语法: : + 自定义的参数名称

示例:按性别和薪资范围查找雇员信息

@Query("SELECT E FROM Employee E WHERE E.sex = :sex AND E.salary > :salary")
List<Employee> selectExample(@Param("sex") String sex, @Param("salary") Double salary);

在方法的参数列表中 , 需要使用 @Param 注解标注每个参数的名称 , 使之与查询语句参数名称匹配 。

位置参数
注意!语法: ? + 位置编号的数值

示例:按姓名和性别查找雇员信息

@Query("SELECT E FROM Employee E WHERE E.sex = ?1 AND E.salary > ?2")
//这里不需要使用@Param注解,只需要对应好位置即可
List<Employee> selectExample(String sex, Double salary);

在方法的参数列表中 , 参数的顺序需要与查询语句中参数标注的编号依次对应起来 。

2.关联查询
通过使用关键字 [LEFT|INNER] JOIN 联接关系属性查询 。(左右中连接)

(1)单值关联查询
语法: SELECT 标识符变量 FROM 实体名称 [AS] 标识符变量 JOIN 实体名称.单值关联字段 [AS] 标识符变量2 …

示例:按部门名称查找该部门所有的雇员信息

@Query("SELECT E FROM Employee E JOIN E.department D WHERE D.name = ?1")
List<Employee> selectExample(String deptName);

(2)多值关联查询
语法: SELECT 标识符变量 FROM 实体名称 [AS] 标识符变量 JOIN 实体名称.多值关联字段 [AS] 标识符变量2 …

示例:查询薪资大于10000的所有雇员所属的部门信息

@Query("SELECT D FROM Department D JOIN D.employees E WHERE E.salary > 10000")
List<Department> selectExample();

或者: SELECT 标识符变量 FROM 实体名称 [AS] 标识符变量, IN(实体名称.多值关联字段) [AS] 标识符变量2 …

@Query("SELECT D FROM Department D, IN(D.employees) E WHERE E.salary > 10000")
List<Department> selectExample();

3.去重查询
语法: SELECT DISTINCT 标识符变量 FROM 实体名称 [AS] 标识符变量 …

示例:查询薪资大于10000的所有雇员所属的部门信息 , 并消除查询结果中的重复的部门

@Query("SELECT DISTINCT D FROM Department D JOIN D.employees E WHERE E.salary > 10000")
List<Department> selectExample();

4.字面值
JPQL 支持的字面值有以下的4种:字符串,数字,布尔,枚举,字符串

(1)语法: ‘字符串’

示例:查询给定名字的雇员信息

@Query("SELECT E FROM Employee E WHERE E.name = '张三'")
Employee selectExample();

如果字符串中含有单引号 , 则用两个单引号来表示 。 如:Li’Si -> Li’’Si

@Query("SELECT E FROM Employee E WHERE E.name = 'Li''Si'")
Employee selectExample();

(2)数字
整数类型:如 24 、 +24 、 -24 、 24L , 支持 Java Long 范围的数值 。

浮点数类型:如 24. 、 24.6 、 +24.6 、 -24.6 、 24.6F 、 24.6D , 支持 Java Double 范围的数值 。

示例:查询薪资大于10000的所有雇员

@Query("SELECT E FROM Employee E WHERE E.salary > 10000.0")
List<Employee> selectExample();

(3)布尔
布尔类型的可选值为: TRUE 或 FALSE , 它们不区分大小写 。

示例:查找已婚的所有雇员

@Query("SELECT E FROM Employee E WHERE E.married = TRUE")
List<Employee> selectExample();

(4)枚举
枚举类名必须指定为完全限定类名 。

示例:查询所有女性的雇员

@Query("SELECT E FROM Employee E WHERE E.sex = org.fanlychie.enums.Sex.FEMALE")
List<Employee> selectExample();

5.模糊查询
表达式 匹配 不匹配
E.name LIKE ‘张%’ 张三 小张伟
E.name LIKE ‘张_’ 张三 张三丰
E.name LIKE ‘张_%’ 张_三 张三
示例:查询张性的所有雇员

@Query("SELECT E FROM Employee E WHERE E.name LIKE '张%'")
List<Employee> selectExample();

6.空集合查询
通过使用关键字 IS [NOT] EMPTY 来查找关联的属性集合的值为空的记录 。

示例:查找尚无雇员的所有部门

@Query("SELECT D FROM Department D WHERE D.employees IS EMPTY")
List<Department> selectExample();

7.构造器
查询结果的类型如果不是持久化的实体类 , 必须使用该类的完全限定名 。

语法: SELECT NEW 类的完全限定名(参数1, 参数2, …) …

示例:查询所有的雇员信息

package org.fanlychie.model;

public class SimpleEmployee{

 private String name;

 private Sex sex;

 public SimpleEmployee(String name, Sex sex){
 this.name = name;
 this.sex = sex;
 }

 // getters and setters
 
}
@Query("SELECT NEW org.fanlychie.model.SimpleEmployee(E.name, E.sex) FROM Employee E")
List<SimpleEmployee> selectExample();

b.更新

示例:更新某个雇员的婚姻状态和薪资信息

@Modifying
@Transactional
@Query("UPDATE Employee SET married = ?2, salary = ?3 WHERE id = ?1")
int updateExample(Long id, Boolean married, Double salary);

@Query 无法进行 DML (Data Manipulation Language 数据操控语言 , 主要语句有 INSERT 、 DELETE 、 UPDATE )操作 , 如需更新数据库表的数据需要标注 @Modifying 注解 , 并且需要事务的支持 @Transactional 。

c.删除

示例:删除没有雇员的部门信息

@Modifying
@Transactional
@Query("DELETE FROM Department D WHERE D.employees IS EMPTY")
int deleteExample();

以下是实际中举例:

package com.example.demo.repository;

import com.example.demo.pojo.Admin;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.stereotype.Repository;

//声明为repository
@Repository
public interface AdminRepository extends PagingAndSortingRepository<Admin,Long>  {
	//自定义SQL语句必须在事务环境下运行 必须有DML支持(Modifying)  
	//?1表示下面的形参的第1个位置,这里不对表进行操作,直接对实体类进行操作,然后实体类映射到表中。
	//这个注解也可以加到测试类上面 但需要跟进一个@commit提交事务的注解 因为测试类会自动回滚事务
  	@Transactional    
  	@Modifying
    @Query("update Admin set password=?1 where id=?2")
    int updatePasswordById(String newPassword,int id);

}

(3)原生SQL

说明: 如果不习惯JQPL可以使用原生SQL,这就和平时写SQL一样就不多介绍了

package com.example.demo.repository;

import com.example.demo.pojo.Admin;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.stereotype.Repository;

//声明为repository
@Repository
public interface AdminRepository extends PagingAndSortingRepository<Admin,Long>  {
	@Transactional
	@Modifying
	//唯一不同就是多了nativeQuery参数为true,开启原生SQL
    @Query(value = "update account set password=?1 where name=?2",nativeQuery = true)
    int updatePasswordByUsername(String password,String username);


}

2.命名规则表

说明: 命名规则按下面这个表就可以了

关键词样本JPQL片段
AndfindByLastnameAndFirstname… where x.lastname = ?1 and x.firstname = ?2
OrfindByLastnameOrFirstname… where x.lastname = ?1 or x.firstname = ?2
Is,EqualsfindByFirstname, findByFirstnameIs,findByFirstnameEquals… where x.firstname = ?1
BetweenfindByStartDateBetween… where x.startDate between ?1 and ?2
LessThanfindByAgeLessThan… where x.age < ?1
LessThanEqualfindByAgeLessThanEqual… where x.age <= ?1
GreaterThanfindByAgeGreaterThan… where x.age > ?1
GreaterThanEqualfindByAgeGreaterThanEqual… where x.age >= ?1
AfterfindByStartDateAfter… where x.startDate > ?1
BeforefindByStartDateBefore… where x.startDate < ?1
IsNullfindByAgeIsNull… where x.age is null
IsNotNull,NotNullfindByAge(Is)NotNull… where x.age not null
LikefindByFirstnameLike… where x.firstname like ?1
NotLikefindByFirstnameNotLike… where x.firstname not like ?1
StartingWithfindByFirstnameStartingWith… where x.firstname like ?1(与 append 绑定的参数%)
EndingWithfindByFirstnameEndingWith… where x.firstname like ?1(以 prepended 绑定的参数%)
ContainingfindByFirstnameContaining… where x.firstname like ?1(参数绑定在 中%)
OrderByfindByAgeOrderByLastnameDesc… where x.age = ?1 order by x.lastname desc
NotfindByLastnameNot… where x.lastname <> ?1
InfindByAgeIn(Collection ages)… where x.age in ?1
NotInfindByAgeNotIn(Collection ages)… where x.age not in ?1
TruefindByActiveTrue()… where x.active = true
FalsefindByActiveFalse()… where x.active = false
IgnoreCasefindByFirstnameIgnoreCase… where UPPER(x.firstame) = UPPER(?1)

总结:JPA的特长就是实现全自动ORM框架,不用动手写SQL,但是只适用于一些简单的业务,如果更复杂的情况还是Mybatis更有优势。希望对您有帮助,感谢阅读

结束语:裸体一旦成为艺术,便是最圣洁的。道德一旦沦为虚伪,便是最下流的。
勇敢去做你认为正确的事,不要被世俗的流言蜚语所困扰。

相关文章:

  • 【Android-实战】1、Room 使用 Flow 和 collect() 监听数据库的变化、动态更新页面
  • python字符串应用
  • asp.net高校网上评教信息系统VS开发sqlserver数据库web结构c#编程计算机网页项目
  • 暂退法dropout----详解与分析(多层感知机)
  • Android Tablayout样式修改
  • 朋友圈那位隐藏大佬的单片机学习心得
  • Android系统启动流程全解析--你知道Android系统启动都干了啥吗
  • openGl绘制五星红旗
  • 【数据结构】二叉树
  • HTML常用标签二
  • 高数(下) 第十二章:无穷级数
  • 【GOF】三种工厂模式~
  • 算法 |【实验5.2】1-深度优先搜索暴力求解旅行商问题
  • OpenCV-Python学习(2)—— OpenCV 图像的读取和显示
  • Unity技术手册-初识编辑器(上)
  • [PHP内核探索]PHP中的哈希表
  • [js高手之路]搞清楚面向对象,必须要理解对象在创建过程中的内存表示
  • __proto__ 和 prototype的关系
  • 002-读书笔记-JavaScript高级程序设计 在HTML中使用JavaScript
  • 2018天猫双11|这就是阿里云!不止有新技术,更有温暖的社会力量
  • Android交互
  • CSS3 变换
  • Django 博客开发教程 16 - 统计文章阅读量
  • Docker下部署自己的LNMP工作环境
  • jquery cookie
  • Logstash 参考指南(目录)
  • 程序员最讨厌的9句话,你可有补充?
  • 分享自己折腾多时的一套 vue 组件 --we-vue
  • 嵌入式文件系统
  • 线性表及其算法(java实现)
  • 用 Swift 编写面向协议的视图
  • ​​​​​​​​​​​​​​汽车网络信息安全分析方法论
  • # 计算机视觉入门
  • %check_box% in rails :coditions={:has_many , :through}
  • (+3)1.3敏捷宣言与敏捷过程的特点
  • (6)添加vue-cookie
  • (二)Linux——Linux常用指令
  • (二)学习JVM —— 垃圾回收机制
  • (附源码)计算机毕业设计SSM保险客户管理系统
  • (力扣)循环队列的实现与详解(C语言)
  • (五) 一起学 Unix 环境高级编程 (APUE) 之 进程环境
  • (一)Thymeleaf用法——Thymeleaf简介
  • (转)chrome浏览器收藏夹(书签)的导出与导入
  • (转)Oracle存储过程编写经验和优化措施
  • .Net Core缓存组件(MemoryCache)源码解析
  • .NETCORE 开发登录接口MFA谷歌多因子身份验证
  • .net下的富文本编辑器FCKeditor的配置方法
  • @transactional 方法执行完再commit_当@Transactional遇到@CacheEvict,你的代码是不是有bug!...
  • [ IOS ] iOS-控制器View的创建和生命周期
  • [ vulhub漏洞复现篇 ] Jetty WEB-INF 文件读取复现CVE-2021-34429
  • [100天算法】-实现 strStr()(day 52)
  • [④ADRV902x]: Digital Filter Configuration(发射端)
  • [AIGC] Kong:一个强大的 API 网关和服务平台
  • [Android]通过PhoneLookup读取所有电话号码
  • [Angular] 笔记 21:@ViewChild