万字总结Spring Data Jpa,一发入魂。

2023-11-11 06:50

本文主要是介绍万字总结Spring Data Jpa,一发入魂。,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

        本人更推荐于学习mybatis,因为所跟的项目技术栈是JPA,所以进行JPA的学习总结,下面是mybatis学习总结,嘿嘿,开篇劝退。

两万字使用通俗语言讲解mybatis_狗头实习生的博客-CSDN博客

JPA与JDBC的关系

相同点:

        1.都跟操作数据库有关、JPA是JDBC的升级版

        2.JDBC和JPA都是一组模范接口

        3.都是由sun官方推出

不同点:

        1.JDBC是由各个关系型数据库实现的,JPA是由ORM框架实现(ORM:对象关系映射)

        2.JDBC使用SQL语句和数据库通信,JPA面向对象,通过ORM框架来生成SQL进行操作

        3.JAP是依赖于JDBC才能操作数据库的

JPA的对象四种状态

  • 临时状态:指对象刚刚创建出来,还没有与entityManager发生关系,没有持久化,可以理解为还为与数据库进行交互
  • 持久状态:与entityManager发生关系,操作了数据库,已经被持久化,比如:查询出来的数据,添加数据,修改的数据
  • 删除状态:执行了remove方法但是还为提交事务
  • 游离状态:数据提交到数据库,事务commit后,此时再对数据进行操作也不会同步到数据库

下面是JPA的一个官方文档,里面有一些协议用法,约定大于协议!!

Spring Data JPA - Reference Documentation

 下面这个就是节选于官方文档的一部分,面向方法名

引入依赖

根据官方文档,找到现在较为稳定的版本

 点开文档,找到依赖,2.6.1版本的依赖我会在下面给出,直接复制就好

 将其复制到自己的pom文件中

这个依赖就帮我们管理所有相关的依赖版本,防止依赖冲突。

继续向下翻文档,找到jpa的依赖

 这里是所需要的所有依赖

    <dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.13.2</version><scope>test</scope></dependency><dependency><groupId>org.hibernate</groupId><artifactId>hibernate-entitymanager</artifactId><version>5.4.32.Final</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.26</version></dependency><dependency><groupId>org.springframework.data</groupId><artifactId>spring-data-jpa</artifactId></dependency><!--连接池--><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.2.8</version></dependency><!--spring-test--><dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>5.3.10</version></dependency></dependencies><dependencyManagement><dependencies><dependency><groupId>org.springframework.data</groupId><artifactId>spring-data-bom</artifactId><version>2021.1.2</version><scope>import</scope><type>pom</type></dependency></dependencies></dependencyManagement>

码代码

        很多内容我会同时给出官方文档的位置以及粘贴出我自己代码,便于以后在用新的版本时也可以根据文档去找到相应的代码

实体类

package com.LL.pojo;import lombok.Data;import javax.persistence.*;
import java.lang.annotation.Target;@Entity
@Table(name = "user")
@Data
public class User {@Id@GeneratedValue(strategy = GenerationType.AUTO)@Column(name = "id")private int id;@Column(name = "name")private String name;@Column(name = "pwd")private String pwd;}

参照官方javaConfig文档,

完成我们的xml配置

 下面是xml配置文件在官方文档中的位置

 根据javaConfig文档完成spring.xml配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:jpa="http://www.springframework.org/schema/data/jpa"xmlns:tx="http://www.springframework.org/schema/c"xsi:schemaLocation="http://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/data/jpahttps://www.springframework.org/schema/data/jpa/spring-jpa.xsd"><!--用于整合jpa--><jpa:repositories base-package="com.LL.repositories"entity-manager-factory-ref="entityManagerFactory"transaction-manager-ref="transactionManager"/><!--EntityManagerFactory--><bean name="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"><!--hibernate实现--><property name="JpaVendorAdapter"><bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"><!--设置是否自动生成表--><!--value为true,若没有表则创建,为false,则不会创建--><property name="generateDdl" value="true"></property><!--显示sql语句--><property name="showSql" value="true"></property></bean></property><!--设置扫描实体类的包--><property name="packagesToScan" value="com.LL.pojo"></property><property name="dataSource" ref="dataSource"></property></bean><!--数据源--><bean name="dataSource" class="com.alibaba.druid.pool.DruidDataSource"><property name="driver" value="com.mysql.cj.jdbc.Driver"></property><property name="url"value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&amp;useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=UTC"></property><property name="username" value="root"></property><property name="password" value="123456789"></property></bean><!--声明式事务--><bean class="org.springframework.orm.jpa.JpaTransactionManager" name="transactionManager"><property name="entityManagerFactory" ref="entityManagerFactory"></property></bean><!--启动注解方式的声明式事务--><tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven></beans>

建立一个新包,将xml的路径替换成新建包的路径

 

 在repositories下建接口

package com.LL.repositories;import com.LL.pojo.User;
import org.springframework.data.repository.CrudRepository;//CrudRepository第一个参数是实体类型,第二个参数是主键类型
public interface UserRepository extends CrudRepository<User,Long> {
}

编写测试类

package com.LL;import com.LL.pojo.User;
import com.LL.repositories.UserRepository;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;import java.util.Optional;//引入配置文件
@ContextConfiguration("/spring.xml")
@RunWith(SpringJUnit4ClassRunner.class)
public class jpa_Test {@AutowiredUserRepository repository;@Testpublic void test1() {//Optional防止空指针Optional<User> user = repository.findById(1);System.out.println(user.get());}@Testpublic void test2() {User user = new User();user.setName("哈利路亚");repository.save(user);}
}

测试成功

javaConfig如何来配置

建立一个config类

        直接将官方文档给的JAVAconfig配置类拿过来(拿来把你!),因为我这里用的是druid连接池,所以将DataSource做一点修改,改成自己的数据信息。将包扫描路径换成自己的路径

package com.LL.config;import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;//标记当前类为配置类
@Configuration
//启动jpa <jpa:repositories
//如果当前的配置类不是在最顶层,那么我们需要指定
@EnableJpaRepositories(basePackages = "com.LL.repositories")
//开启事务
@EnableTransactionManagement
public class SpringDataJPAConfig {@Beanpublic DataSource dataSource() {DruidDataSource druidDataSource = new DruidDataSource();druidDataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");druidDataSource.setUrl("jdbc:mysql://localhost:3306/mybatis?useSSL=true&amp;useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=UTC");druidDataSource.setUsername("root");druidDataSource.setPassword("123456789");return druidDataSource;}@Beanpublic LocalContainerEntityManagerFactoryBean entityManagerFactory() {HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();vendorAdapter.setGenerateDdl(true);LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();factory.setJpaVendorAdapter(vendorAdapter);factory.setPackagesToScan("com.acme.domain");factory.setDataSource(dataSource());return factory;}@Beanpublic PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {JpaTransactionManager txManager = new JpaTransactionManager();txManager.setEntityManagerFactory(entityManagerFactory);return txManager;}
}

CrudRepository中的方法说明

用来修改和插入 entity中有主键,则修改库中内容,如果没有主键,在会新增内容

返回结果为主键的值

<S extends T> S save(S entity);

通过集合返回保存多个实体
<S extends T> Iterable<S> saveAll(Iterable<S> entities);

通过主键查询实体

Optional<T> findById(ID id);

通过id查询是否存在,返回布尔值

boolean existsById(ID id);

查询所有

Iterable<T> findAll();

通过集合的主键,查询多个实体,返回实体集合

Iterable<T> findAllById(Iterable<ID> ids);

返回总数量

long count();

根据id删除数据

void deleteById(ID id);

根据实体进行删除

void delete(T entity);

通过id集合删除多个

void deleteAllById(Iterable<? extends ID> ids);

通过实体,删除多个

void deleteAll(Iterable<? extends T> entities);

删除所有

void deleteAll();

分页与排序 

若想增加分页和排序功能,则需要继承 PagingAndSortingRepository

PageRequest.of(0,2)第一个参数传的是查询第几页,第二个参数传的是每一页有多少的数据

  @Testpublic void test4(){Page<User> all = repository.findAll(PageRequest.of(0, 2));for (User user : all) {System.out.println(user);}}

下面调用Page中的一些用法

   @Testpublic void test4(){Page<User> all = repository.findAll(PageRequest.of(0, 2));System.out.println("查询总页数"+all.getTotalPages());System.out.println("查询总个数"+all.getTotalElements());System.out.println("查询数据"+all.getContent());}

 结果输出正确

 根据id进行降序排序(and方法表示可以定义多种排序方式,这里并无实意)

@Testpublic void test5() {Sort sort = Sort.by("id").descending().and(Sort.by("pwd").descending());Iterable<User> all = repository.findAll(sort);for (User user : all) {System.out.println(user);}}

结果输出正确 

自定义语句

我们可以自定义方法,首先我们看看如何进行传参。

@Query注解中可以指明sql方法,如果查询实体的所有信息,则select * 可以省略掉。

向@Query传参有两种方法

        1.传参?+数字,数字指带第几个参数

        2.使用@Param注解指明传参名称,传参:+名称

@Transactional注解声明事务,通常加载业务逻辑层上

 @Modifying  通知springdatajpa是增删改的操作

  //查询//如果查询实体的所有字段,则select *可以省略,我们需要在?后面指明是第几个参数。@Query("FROM User where name = ?1")User findUserByName1( String userName);@Query("FROM User where name =:s")User findUserByName2(@Param("s") String userName);//修改@Transactional  //放在业务逻辑层上面声明@Modifying //通知springdatajpa是增删改的操作@Query("update User u set u.pwd=:password where u.id =:id ")int updateUser(@Param("password")String pass,@Param("id")int id);//删除@Transactional  //放在业务逻辑层上面声明@Modifying //通知springdatajpa是增删改的操作@Query("delete from User u where u.id =:id ")int deleteUser(@Param("id")int id);

源生方法

我们还可以自己去写sql语句进行处理。

nativeQuery默认是false,设置为true,使用源生语句。

    @Query(value = "select * from user where id=?1",nativeQuery = true)User findByIdBySql(@Param("id")int id);

测试方法

这里我使用了Optional去修饰实体类,可以防止空指针异常

   @Testpublic void test11(){Optional<User> user = Optional.ofNullable(repository.findByIdBySql(5));System.out.println(user);}

常见规范命名方法

 动态查询

1.Query by Example

1.只支持字符串 start/contains/ends/regex 匹配和其他属性配型的精准匹配

2.不支持嵌套或分组的属性约束

实例

新建一个Repository

public interface UserQBERepositoryextends PagingAndSortingRepository<User,Integer>, QueryByExampleExecutor<User> {
}

动态查询测试

        新建一个User,设置名字为张三(假设这个数据是从前端传过来的),通过 Example构建查询条件,输出查询结果。

    //动态查询@Testpublic void test1(){//查询条件User user = new User();user.setName("张三");//通过Example构建查询条件Example<User> example = Example.of(user);List<User> all = (List<User>) repository.findAll(example);System.out.println(all);}

我们还可以通过条件匹配器进行筛选

        我们声明一个ExampleMatcher匹配器,帮助我们筛选数据,从筛选来看可以看到很多with开头的方法,第一个方法就是忽略掉这个参数,查询的时候不进行匹配,第二个参数就是忽略参数的大小写我们会在下面举例子。

        下列代码中,我们查询一个名字叫张三,密码是1234的人,但实际中我们的库中并没有这个人,我们通过一个匹配器,选择忽略到名字和id,忽略密码的大小写,然后将匹配器传入到Example中,查询返回结果。

 //条件匹配器@Testpublic void test2(){//查询条件User user = new User();user.setName("张三");user.setPwd("1234");//通过匹配器 对条件进行蛇者ExampleMatcher matcher = ExampleMatcher.matching().withIgnorePaths("name")    //设置忽略的值.withIgnorePaths("id")      //设置忽略的值.withIgnoreCase("pwd");     //设置忽略大小写Example<User> example = Example.of(user,matcher);List<User> all = (List<User>) repository.findAll(example);System.out.println(all);}

 下面是根据密码模糊查询的例子,查询出以4结尾的密码记录。

    //条件匹配器@Testpublic void test3(){//查询条件User user = new User();user.setPwd("4");//通过匹配器 对条件进行蛇者ExampleMatcher matcher = ExampleMatcher.matching().withIgnorePaths("id")      //设置忽略的值.withIgnoreCase("pwd")      //设置忽略大小写//.withStringMatcher(ExampleMatcher.StringMatcher.ENDING);    //根据结尾模糊查询.withMatcher("pwd",m ->m.endsWith()  );     //对单个参数有效,结尾模糊查询询Example<User> example = Example.of(user,matcher);List<User> all = (List<User>) repository.findAll(example);System.out.println(all);}

小结:

1.withIgnorePaths等with开头的方法可以帮助我们设置查询条件。

2.withStringMatcher方法是匹配我们实体中的所有数据,对所有属性都有效

3.withMatcher对单个参数有效

2.Specification

可以实现范围查询!

虽然代码看起来很复杂,但是实际上很好理解。

Specification中的三个参数

1.root 获取属性列 

2.CriteriaBuilder 设置各种条件(大于,小于,在...范围内。。。。)

3.CriteriaQuery 组合

下列代码中,通过root去获取实体的三个属性参数,没有啥好解释的。。。

cb呢就是为我们的参数设置条件,比如

         cb.equal(pwd, "1234");就是设置密码为1234

         cb.greaterThan(id, 2);就是设置id大于2

         cb.in(id);in.value(3).value(4).value(5);就是设置id的值可以是3、4、5

         cb.and(equal,predicate, in);就是使这三个条件同时成立(and是同时成立,or是或者)

然后返回查询条件,查看查询结果。

  @Testpublic void test2() {List<User> all = repository.findAll(new Specification<User>() {@Overridepublic Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) {Path<Integer> id = root.get("id");Path<String> name = root.get("name");Path<String> pwd = root.get("pwd");//参数1:为那个字段设置条件 参数2:Predicate equal = cb.equal(pwd, "1234");Predicate predicate = cb.greaterThan(id, 2);CriteriaBuilder.In<Integer> in = cb.in(id);in.value(3).value(4).value(5);Predicate and = cb.and(equal,predicate, in);return and;}});System.out.println(all);}

3.QueryDSL查询框架

首先引入依赖

    <build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin><!--添加QueryDSL插件支持--><plugin><groupId>com.mysema.maven</groupId><artifactId>apt-maven-plugin</artifactId><version>1.1.3</version><dependencies><dependency><groupId>com.querydsl</groupId><artifactId>querydsl-apt</artifactId><version>4.4.0</version></dependency></dependencies><executions><execution><phase>generate-sources</phase><goals><goal>process</goal></goals><configuration><outputDirectory>target/generated-sources/queries</outputDirectory><processor>com.querydsl.apt.jpa.JPAAnnotationProcessor</processor><logOnlyOnError>true</logOnlyOnError></configuration></execution></executions></plugin></plugins></build>

代码示例,我们使用Ql类成功获取调用对象方法

    @Testpublic void test1() {QUser user = QUser.user;BooleanExpression eq = user.id.eq(12);System.out.println(repository.findOne(eq));}

 下列查询的条件是,名字在张三、李四、王五中并且id大于1

  /*** 查询客户范围(in)* id >大于*/@Testpublic void test2() {QUser user = QUser.user;BooleanExpression and = user.name.in("张三", "李四", "王五").and(user.id.gt(1));System.out.println(repository.findAll(and));}

方法简写对应

这篇关于万字总结Spring Data Jpa,一发入魂。的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/388286

相关文章

Spring @Scheduled注解及工作原理

《Spring@Scheduled注解及工作原理》Spring的@Scheduled注解用于标记定时任务,无需额外库,需配置@EnableScheduling,设置fixedRate、fixedDe... 目录1.@Scheduled注解定义2.配置 @Scheduled2.1 开启定时任务支持2.2 创建

SpringBoot中使用Flux实现流式返回的方法小结

《SpringBoot中使用Flux实现流式返回的方法小结》文章介绍流式返回(StreamingResponse)在SpringBoot中通过Flux实现,优势包括提升用户体验、降低内存消耗、支持长连... 目录背景流式返回的核心概念与优势1. 提升用户体验2. 降低内存消耗3. 支持长连接与实时通信在Sp

Spring Boot 实现 IP 限流的原理、实践与利弊解析

《SpringBoot实现IP限流的原理、实践与利弊解析》在SpringBoot中实现IP限流是一种简单而有效的方式来保障系统的稳定性和可用性,本文给大家介绍SpringBoot实现IP限... 目录一、引言二、IP 限流原理2.1 令牌桶算法2.2 漏桶算法三、使用场景3.1 防止恶意攻击3.2 控制资源

Mac系统下卸载JAVA和JDK的步骤

《Mac系统下卸载JAVA和JDK的步骤》JDK是Java语言的软件开发工具包,它提供了开发和运行Java应用程序所需的工具、库和资源,:本文主要介绍Mac系统下卸载JAVA和JDK的相关资料,需... 目录1. 卸载系统自带的 Java 版本检查当前 Java 版本通过命令卸载系统 Java2. 卸载自定

springboot下载接口限速功能实现

《springboot下载接口限速功能实现》通过Redis统计并发数动态调整每个用户带宽,核心逻辑为每秒读取并发送限定数据量,防止单用户占用过多资源,确保整体下载均衡且高效,本文给大家介绍spring... 目录 一、整体目标 二、涉及的主要类/方法✅ 三、核心流程图解(简化) 四、关键代码详解1️⃣ 设置

Java Spring ApplicationEvent 代码示例解析

《JavaSpringApplicationEvent代码示例解析》本文解析了Spring事件机制,涵盖核心概念(发布-订阅/观察者模式)、代码实现(事件定义、发布、监听)及高级应用(异步处理、... 目录一、Spring 事件机制核心概念1. 事件驱动架构模型2. 核心组件二、代码示例解析1. 事件定义

SpringMVC高效获取JavaBean对象指南

《SpringMVC高效获取JavaBean对象指南》SpringMVC通过数据绑定自动将请求参数映射到JavaBean,支持表单、URL及JSON数据,需用@ModelAttribute、@Requ... 目录Spring MVC 获取 JavaBean 对象指南核心机制:数据绑定实现步骤1. 定义 Ja

javax.net.ssl.SSLHandshakeException:异常原因及解决方案

《javax.net.ssl.SSLHandshakeException:异常原因及解决方案》javax.net.ssl.SSLHandshakeException是一个SSL握手异常,通常在建立SS... 目录报错原因在程序中绕过服务器的安全验证注意点最后多说一句报错原因一般出现这种问题是因为目标服务器

Java实现删除文件中的指定内容

《Java实现删除文件中的指定内容》在日常开发中,经常需要对文本文件进行批量处理,其中,删除文件中指定内容是最常见的需求之一,下面我们就来看看如何使用java实现删除文件中的指定内容吧... 目录1. 项目背景详细介绍2. 项目需求详细介绍2.1 功能需求2.2 非功能需求3. 相关技术详细介绍3.1 Ja

springboot项目中整合高德地图的实践

《springboot项目中整合高德地图的实践》:本文主要介绍springboot项目中整合高德地图的实践,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一:高德开放平台的使用二:创建数据库(我是用的是mysql)三:Springboot所需的依赖(根据你的需求再