Spring Data JPA使用规则和审计的学习

一、引入依赖

完整的pom文件如下所示:

<?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 https://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.7.13</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>FunlyDemo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>FunlyDemo</name>
    <description>FunlyDemo</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <!--mysql-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.31</version>
        </dependency>
        <!--jpa-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </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.properties配置文件

#mysql
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/funly?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8&useSSL=false&rewriteBatchedStatements=true
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=123456

#jpa
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true

三、创建用户实体类

package com.example.funlydemo.bean;

import lombok.Data;
import lombok.ToString;

import javax.persistence.*;

/**
 * @author qx
 * @date 2023/07/19
 * @desc 用户实体类
 */
@Entity
@Table(name = "t_user")
@Data
@ToString
public class User {

    /**
     * ID
     */
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    /**
     * 姓名
     */
    private String name;
    /**
     * 年龄
     */
    private Integer age;
}

四、JPA规则认识

启动重新创建好数据表后,我们添加一些测试数据到user表。

关键字举例       JPQL片段
And        

findAllByNameAndAge

where user0_.name=? and user0_.age=?
Or

findAllByNameOrAge

where user0_.name=? or user0_.age=?
is,Equals

findAllByNameIs,findAllByNameEquals,

findAllByName

where user0_.name=?
Between

findAllByAgeBetween

where user0_.age between ? and ?

LessThan

findAllByAgeLessThan

where user0_.age<?

LessThanEqual

findAllByAgeLessThanEqual

where user0_.age<=?

GreaterThan

findAllByAgeGreaterThan

where user0_.age>?

GreaterThanEqual

findAllByAgeGreaterThanEqual

where user0_.age>=?

IsNull

findAllByAgeIsNull

where user0_.age is null

IsNotNull

findAllByAgeIsNotNull

where user0_.age is not null

Like

findAllByNameLike

where user0_.name like ? escape ?

NotLike

findAllByNameNotLike

where user0_.name not like ? escape ?

StartingWith

findAllByNameStartingWith

where user0_.name like ?(后置%) escape ?

EndingWith

findAllByNameEndingWith

where user0_.name like ?(前置%) escape ?

Containing

findAllByNameContaining

where user0_.name like ?(双%) escape ?

OrderBy

findAllByNameOrderByAgeDesc

where user0_.name=? order by user0_.age desc

Not

findAllByNameNot

where user0_.name<>?

In

findAllByAgeIn

where user0_.age in (? , ?)

NotIn

findAllByAgeNotIn

where user0_.age not in  (? , ?)

五、持久层方法编写

package com.example.funlydemo.repository;

import com.example.funlydemo.bean.User;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.List;

public interface UserRepository extends JpaRepository<User, Long> {

    List<User> findAllByNameAndAge(String name, Integer age);

    List<User> findAllByNameOrAge(String name, Integer age);

    List<User> findAllByNameIs(String name);

    List<User> findAllByNameEquals(String name);

    List<User> findAllByName(String name);


    List<User> findAllByAgeBetween(Integer age1, Integer age2);

    List<User> findAllByAgeLessThan(Integer age);

    List<User> findAllByAgeLessThanEqual(Integer age);

    List<User> findAllByAgeGreaterThan(Integer age);

    List<User> findAllByAgeGreaterThanEqual(Integer age);

    List<User> findAllByAgeIsNull();

    List<User> findAllByAgeIsNotNull();

    List<User> findAllByNameLike(String name);

    List<User> findAllByNameNotLike(String name);

    List<User> findAllByNameStartingWith(String name);

    List<User> findAllByNameEndingWith(String name);

    List<User> findAllByNameContaining(String name);

    List<User> findAllByNameOrderByAgeDesc(String name);

    List<User> findAllByNameNot(String name);

    List<User> findAllByAgeIn(List<Integer> ageList);

    List<User> findAllByAgeNotIn(List<Integer> ageList);
}

六、单元测试类

package com.example.funlydemo;

import com.example.funlydemo.bean.User;
import com.example.funlydemo.repository.UserRepository;
import org.assertj.core.util.Lists;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

@SpringBootTest
class FunlyDemoApplicationTests {

    @Autowired
    private UserRepository userRepository;

    @Test
    void testAnd() {
        List<User> userList = userRepository.findAllByNameAndAge("aa", 11);
        System.out.println(userList);
    }

    @Test
    void testOr() {
        List<User> userList = userRepository.findAllByNameOrAge("aa", 11);
        System.out.println(userList);
    }

    @Test
    void testEquals() {
        List<User> userList = userRepository.findAllByNameIs("aa");
        System.out.println(userList);

        List<User> userList1 = userRepository.findAllByNameEquals("aa");
        System.out.println(userList1);

        List<User> userList2 = userRepository.findAllByName("aa");
        System.out.println(userList2);
    }

    @Test
    void testBetween() {
        List<User> userList = userRepository.findAllByAgeBetween(12, 13);
        System.out.println(userList);
    }

    @Test
    void testLessThan() {
        List<User> userList = userRepository.findAllByAgeLessThan(12);
        System.out.println(userList);
    }

    @Test
    void testLessThanEqual() {
        List<User> userList = userRepository.findAllByAgeLessThanEqual(12);
        System.out.println(userList);
    }

    @Test
    void testGreaterThan() {
        List<User> userList = userRepository.findAllByAgeGreaterThan(12);
        System.out.println(userList);
    }

    @Test
    void testGreaterThanEqual() {
        List<User> userList = userRepository.findAllByAgeGreaterThanEqual(12);
        System.out.println(userList);
    }

    @Test
    void testIsNull() {
        List<User> userList = userRepository.findAllByAgeIsNull();
        System.out.println(userList);
    }

    @Test
    void testIsNotNull() {
        List<User> userList = userRepository.findAllByAgeIsNotNull();
        System.out.println(userList);
    }

    @Test
    void testLike() {
        List<User> userList = userRepository.findAllByNameLike("b%");
        System.out.println(userList);
    }

    @Test
    void testNotLike() {
        List<User> userList = userRepository.findAllByNameNotLike("b%");
        System.out.println(userList);
    }

    @Test
    void testStartingWith() {
        List<User> userList = userRepository.findAllByNameStartingWith("b");
        System.out.println(userList);
    }

    @Test
    void testEndingWith() {
        List<User> userList = userRepository.findAllByNameEndingWith("x");
        System.out.println(userList);
    }

    @Test
    void testContaining() {
        List<User> userList = userRepository.findAllByNameContaining("a");
        System.out.println(userList);
    }

    @Test
    void testOrderBy() {
        List<User> userList = userRepository.findAllByNameOrderByAgeDesc("aa");
        System.out.println(userList);
    }

    @Test
    void testNot() {
        List<User> userList = userRepository.findAllByNameNot("aa");
        System.out.println(userList);
    }

    @Test
    void testIn() {
        List<User> userList = userRepository.findAllByAgeIn(Lists.newArrayList(11, 12));
        System.out.println(userList);
    }

    @Test
    void testNotIn() {
        List<User> userList = userRepository.findAllByAgeNotIn(Lists.newArrayList(11, 12));
        System.out.println(userList);
    }
}

七、自定义规则

我们可以使用JPQL和书写原生SQL的方式实现自定义的规则。JPQL最突出的特点就是以Java Bean为操作对象,遵循JPA规范屏蔽了数据库 之间的差异,使同一套代码可以用在任意数据库上;而SQL方式是以表为操作 对象的,因此可以使用某种数据库特有的功能,比如某个MySQL独有的功能, 但是切换到Oracle时就不能使用了。

JPQL使用示例代码如下:

   @Query("select u from User u where u.name=?1")
    List<User> getDataByName(String name);

原生SQL使用示例代码如下:

 @Query(value = "select * from t_user where name=?1",nativeQuery = true)
    List<User> getUserFromName(String name);
}

设置nativeQuery属性为true,说明使用原生SQL。

八、审计

业务数据的插入时间、最后更新时间、创建人及最后更新人的记录对每个 系统都很重要,但如果每次操作时都需要手动记录这些信息,就会非常枯燥且 烦琐。作为一个成熟的持久层框架,Spring Data JPA应该学会自己审计了。
1.启动类开启审计
package com.example.funlydemo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;

@SpringBootApplication
// 开启审计
@EnableJpaAuditing
public class FunlyDemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(FunlyDemoApplication.class, args);
    }

}

2.把审计需要的属性封装到一个公共类

package com.example.funlydemo.bean;

import lombok.Getter;
import lombok.Setter;
import org.springframework.data.annotation.CreatedBy;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedBy;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import javax.persistence.Column;
import javax.persistence.EntityListeners;
import javax.persistence.MappedSuperclass;
import java.time.LocalDateTime;

/**
 * @author qx
 * @date 2023/07/19
 * @desc
 */
@Getter
@Setter
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public class BaseEntity {

    @CreatedBy
    @Column(updatable = false)
    private String creater;

    @LastModifiedBy
    private String modifier;

    @CreatedDate
    @Column(updatable = false)
    private LocalDateTime createTime;

    @LastModifiedDate
    private LocalDateTime updateTime;


}

@Column(updatable=false)将字段设置不可修改,只允许一次赋值。创建者和创建时间只需要插入一次,不需要更新。

3.用户类继承公共基类

package com.example.funlydemo.bean;

import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;

import javax.persistence.*;

/**
 * @author qx
 * @date 2023/07/19
 * @desc 用户实体类
 */
@EqualsAndHashCode(callSuper = true)
@Entity
@Table(name = "t_user")
@Data
@ToString
public class User extends BaseEntity {

    /**
     * ID
     */
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    /**
     * 姓名
     */
    private String name;
    /**
     * 年龄
     */
    private Integer age;
}

4.创建一个获取当前操作人的接口实现类

package com.example.funlydemo.uti;

import org.springframework.data.domain.AuditorAware;
import org.springframework.stereotype.Component;

import java.util.Optional;

/**
 * @author qx
 * @date 2023/07/19
 * @desc 获取当前操作人的接口
 */
@Component
public class AuditorImpl implements AuditorAware<String> {
    @Override
    public Optional<String> getCurrentAuditor() {
        return Optional.of("admin->" + (int) (Math.random() * 10));
    }
}

5.测试审计

我们在单元测试中,测试添加用户

  @Test
    void testAddUser() {
        User user = new User();
        user.setName("qq");
        user.setAge(20);
        userRepository.save(user);
    }

执行方法后,我们查看数据表,发现自动添加上了创建者和创建时间。

 接下来我们测试修改用户的方法

  @Test
    void testUpdateUser(){
        Optional<User> optional = userRepository.findById(2L);
        User user = optional.get();
        user.setAge(22);
        userRepository.save(user);
    }

执行方法后,我们查看数据表,发现自动修改了更新时间和修改操作人。

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/39344.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

css3的新特性

动画效果 过渡 transition 鼠标放上去瞬间变大 过渡是变大的过程慢慢变化 第一个参数&#xff1a;对哪些值进行过渡。all为hover中所有&#xff0c;也可以指定属性 第二个参数&#xff1a;让动画过渡多长时间。要添加单位&#xff08;s秒&#xff09; 第三个参数&#xff1…

Chat GPT是什么,初学者怎么使用Chat GPT,需要注意些什么

目录 Chat GPT是什么 初学者怎么使用Chat GPT 使用Chat GPT需要注意什么 一些简单的prompt示例 Chat GPT是什么 Chat GPT是由OpenAI开发的一种大型语言模型&#xff0c;它基于GPT&#xff08;Generative Pre-trained Transformer&#xff09;架构。GPT是一种基于深度学习的…

微信小程序音频播放失败:TypeError: Cannot read property ‘duration‘ of undefined

报错截图 最下面这个this.setData()报错可不用理会&#xff0c;是this取值的问题 解决 需要播放和暂停功能时&#xff0c;需要把audio以及他的src放在Page外面。不能缺少 audioCtx.onPlay() 和 audioCtx.onError()两个方法&#xff0c;且需要放在play()方法之前如果在wx.crea…

ChatGPT助力DevOps的优势与局限

一、前言 DevOps 是一种方法论&#xff0c;旨在提高软件开发和 IT 运营团队的协作和效率。DevOps 涉及各种任务和流程的自动化&#xff0c;例如规划、编码、测试、部署、监控和故障排除。然而&#xff0c;其中一些任务和流程仍然有大量任务需要人工手动处理&#xff0c;而这会…

关于WIN10创建系统映像时D盘为系统盘的解决方案

文章目录 问题&#xff1a;使用WIN10自带备份工具时&#xff0c;创建系统映像时&#xff0c;D盘被识别为系统盘的解决方案。方法一&#xff08;传统方法&#xff0c;删盘符&#xff09;方法二&#xff08;对症下药&#xff0c;找原因&#xff09;第一个选项是暂时将服务的Image…

广西学子复读15年,不服从分配。网友:完全是浪费时间

广西学子复读15年&#xff0c;不服从分配。网友&#xff1a;完全是浪费时间 唐尚珺的复读行为引起了网友们的不同解读。有人认为他是一个执念深重的人&#xff0c;目标是考上清华北大&#xff0c;但这个说法是否真实&#xff0c;我们无法确定。无论如何&#xff0c;我们必须认识…

DBeaver连接华为高斯数据库 DBeaver连接Gaussdb数据库 DBeaver connect Gaussdb

DBeaver连接华为高斯数据库 DBeaver连接Gaussdb数据库 DBeaver connect Gaussdb 一、概述 华为GaussDB出来已经有一段时间&#xff0c;最近工作中刚到Gauss数据库。作为coder&#xff0c;那么如何通过可视化工具来操作Gauss呢&#xff1f; 本文将记录使用免费、开源的DBeaver来…

ARM 架构是什么?

ARM&#xff08;Advanced RISC Machines&#xff09;架构是一种处理器架构&#xff0c;它是一种精简指令集计算机&#xff08;RISC&#xff09;架构。ARM架构最初由ARM Holdings&#xff08;现在是SoftBank Group的子公司&#xff09;开发&#xff0c;并在1980年代末和1990年代…

MySQL 第七天作业 nosql作业

作业一&#xff1a;string list hash结构中&#xff0c;每个至少完成5个命令&#xff0c;包含插入 修改 删除 查询&#xff0c;list 和hash还需要增加遍历的操作命令 1、 string类型数据的命令操作&#xff1a; &#xff08;1&#xff09; 设置键值&#xff1a; set key1 re…

存储服务的演化与MySQL分库分表

文章目录 一、存储服务的演化1.单体结构2.单表单库的数据量膨胀 -> 分库分表3.单个MySQL的读写压力过大 -> MySQL索引优化4.进一步缓解MySQL读写压力 -> 读写分离5.冷热数据分离 -> 使用Redis缓存 二、MySQL分库分表1.策略2.需要注意的问题 一、存储服务的演化 1.…

基于单片机汽车防盗报警的设计与实现

功能介绍 以STM32单片机作为主控系统&#xff1b;LCD1602液晶显示当前温度信息和参数等功能&#xff1b;3个LED指示灯表示&#xff1a;震动指示灯、人体感应指示灯、防盗模式开启指示灯&#xff1b;按键用来开启防盗模式&#xff0c;设置温度上下限&#xff1b;开启防盗后检测到…

T5模型: Transfer Text-to-Text Transformer(谷歌)

&#x1f525; T5由谷歌发表于2019&#xff0c;《Exploring the Limits of Transfer Learning with a Unified Text-to-Text Transformer》&#xff0c;最终版本发布在&#xff1a;JMLR。 一句话总结T5: 大一统模型&#xff0c;seq2seq形式完成各类nlp任务&#xff0c;大数据集…

uni-app image加载错误 404 替换为默认图片

双层v-for 使用item修改 aitem.cat_icon || defaultPic绑定图片src属性为aitem.cat_icon 如果aitem.cat_icon的值为空字符串或undefined&#xff0c;那么默认图片defaultPic被显示出来当图片加载错误时,触发handleImageError方法,将aitem传进去 <!-- 页面--><view …

小程序首页轮播图设计

效果图 微信小程序的数据详解 indicator-dots&#xff1a;是否显示面板指示点【默认false 】 indicator-color&#xff1a;指示点颜色【默认rgba(0, 0, 0, .3)】 indicator-active-color&#xff1a;当前选中的指示点颜色【默认#000000】 autoplay&#xff1a;是否自动切换…

Appium python 框架

目录 前言 流程 结构 具体说说 run.py 思路 其他模块 前言 Appium是一个开源的移动应用自动化测试框架&#xff0c;它允许开发人员使用多种编程语言&#xff08;包括Python&#xff09;来编写自动化测试脚本。Appium框架提供了一套API和工具&#xff0c;可以与移动设备进…

【Docker】Docker基本概念

Docker基本概念 1.Docker概述1.1 Docker是什么&#xff1f;1.2 Docker的宗旨1.3 容器的优点1.4 Docker与虚拟机的区别1.5 容器在内核中支持的两种技术1.6 namespace的六大类型 2.Docker核心概念2.1 镜像2.2 容器2.3 仓库 3. 知识点总结3.1 Docker是什么&#xff1f;3.2 容器和虚…

【Express.js】evp-express-cli

evp-express-cli evp-express-cli 是笔者结合自己的实践经验编写的一款 express 手脚架&#xff0c;以一种比较合适的流程构建的 express 架构。 文档 安装用法 命令新建项目运行模板 验证数据库RedisAuthRabbitMQSocketIONacos 开发工具 BabelEsintJestPkgPM2 资源配置日志异…

200行代码写一个简易的C++小黑窗贪吃蛇游戏

分享一个简易的小黑窗贪吃蛇,一共就两百行代码左右(包含注释),很适合初学者巩固语法来练练手. 如果后续需要其他功能也可以再添加. 先小小展示一下: 源码在文末免费领取. 使用工具: VS2019(不是用VS的也可以直接找出cpp和h文件复制到你们用的IDE,甚至是记事本都可以) 闲话…

基于linux下的高并发服务器开发(第二章)- 2.13 匿名管道通信案例

实现 ps aux | grep xxx 父子进程间通信 子进程&#xff1a; ps aux, 子进程结束后&#xff0c;将数据发送给父进程 父进程&#xff1a;获取到数据&#xff0c;过滤 pipe() execlp() 子进程将标准输出 stdout_fileno 重定向到管道的写端。 dup2 07 / 匿名管道…

【代码随想录 | Leetcode | 第七天】链表 | 链表相交 | 环形链表 II

前言 欢迎来到小K的Leetcode|代码随想录|专题化专栏&#xff0c;今天将为大家带来链表相交和环形链表 II的分享✨ 目录 前言面试题 02.07. 链表相交142. 环形链表 II总结 面试题 02.07. 链表相交 ✨题目链接点这里 给你两个单链表的头节点 headA 和 headB &#xff0c;请你找…