JPA 实现增,删,改,查方案

53 篇文章 1 订阅
20 篇文章 0 订阅

方式类总:

方式一、方式二、方式五:

面向对象的查法,用JPA底层提供的方法 (不需要写SQL,JPQL)
    JPA对方式一二提供的支持有限,只能实现一些简单的CRUD;如果要实现复杂的功能,则使用方式五
    方式五的思路,类似于mybatis逆向工程。设计理念:可以让不懂SQL的人,写出复杂的SQL语句

方式三、方式四: 

自己需要写SQL,JPQL

jpa使用方式一

  dao层中自己不用写任何方法,只调用父接口中的方法。
  缺点:父接口中提供的方法有限

jpa使用方式二

可以编写自己的方法,并不写SQL。前提根据约定写方法名字

jpa使用方式三

面向对象SQL语句:JPQL

按形参位置写法

  @Query("select p from People p where id=?1 and age=?2") 
  publish List<People> findByIdAndAge(int id, int age);

具名参数写法 

  @Query("select p from People p where id=:id and age=:age") 
  publish List<People> findByIdAndAge(@Param("id") int id, @Param("age") int age);

方式三基础加分页功能:

 Pageable(PageRequest)

jpa使用方式四:

面向SQL(原生的SQL语句),推荐

原生sql增

  @Modifying
  @Query(nativeQuery=true, value="insert into tb_address(id,name) values(?,?) ")
  publish List<People> addAddress(Integer id, String name);

原生sql删 

  @Modifying
  @Query(nativeQuery=true, value="delete from tb_address where id=? ")
  publish List<People> delAddress(Integer id);

原生sql改

  @Modifying
  @Query(nativeQuery=true, value="update tb_address a set a.name=? where a.id=?")
  publish List<People> updateAddress(String name, Integer id);

原生sql查 

问号形式

  @Query(nativeQuery=true, value="select * from tb_people where name=? and age=?")
  publish List<People> findByNameAndAge(string name, int age);

具名参数形式

  @Query(nativeQuery=true, value="select * from tb_people where  age in (:ages)")
  publish List<People> findByAges(@Param("ages") int age);
  :age 具名参数,说明是一个变量而不是普通的字段

方式四基础加分页功能:

Pageable(PageRequest)

jpa使用方式五:

面向对象查法

方式五实现步骤:
    类似方式一,不用在dao中自定义任何方法(要写dao,只是不用写dao中的方法)
        如findAll(实现Specification接口)    使用Predicate构造查询条件
    实现service, controller

在动态查询Specifications有详细说明

动态查询:

QueryByExample  

QBE是一种通用的查询机制,它允许您根据示例对象的属性值进行查询。您可以创建一个示例对象,设置其中的属性值作为查询条件,然后通过执行QBE查询来获取匹配的结果。QBE机制一般是通过使用动态查询构建器(如Criteria API)或自定义查询方法实现的。

  •     只能针对字符串开头/包含/结尾/正则的匹配
  •     不支持嵌套条件 ,如 or

Example

Example是JPA的一种特定实现,它是基于JPA的标准规范的一部分。它提供了一个Example类和ExampleMatcher类,用于根据示例对象的属性创建查询条件。可以创建一个示例对象,设置其中的属性值和匹配规则,然后使用Example对象作为查询条件,执行JPA查询方法,JPA会自动生成相应的查询语句来获取匹配的结果。Example适用于简单的查询场景,对于复杂的查询需求可能不够灵活。

具体来说,JPA的Example机制提供了以下功能:

  1. 创建示例对象:您可以创建一个具有特定属性值的实体对象,作为查询的示例。
  2. 匹配规则:您可以定义属性之间的匹配规则,如忽略大小写、模糊匹配等。
  3. 查询条件:使用Example对象作为查询条件,JPA会自动生成相应的查询语句。

使用Example时,您可以根据需要设置以下内容:

  1. 示例对象:创建一个具有特定属性值的实体对象,用作查询的示例。
  2. 匹配器(ExampleMatcher):定义属性之间的匹配规则,如忽略大小写、模糊匹配等。
  3. 示例选项(ExampleOptions):定义查询选项,如是否忽略Null值属性等。

通过使用Example,您可以在不编写原生SQL或JPQL查询语句的情况下,根据实体对象的属性值进行动态查询。

以下是一个基本示例,展示了如何使用JPA的Example机制:

import org.springframework.data.domain.Example;
import org.springframework.data.domain.ExampleMatcher;
import org.springframework.data.jpa.repository.JpaRepository;

// 实体类
@Entity
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private String name;
    private String email;
    // 其他属性和方法...
}

// Repository接口
public interface UserRepository extends JpaRepository<User, Long> {
}

// 使用Example进行查询
public class ExampleUsage {
    private UserRepository userRepository;

    public List<User> findByExample(User user) {
        ExampleMatcher matcher = ExampleMatcher.matching()
                .withIgnoreCase()
                .withStringMatcher(ExampleMatcher.StringMatcher.CONTAINING);

        Example<User> example = Example.of(user, matcher);
        return userRepository.findAll(example);
    }
}

Specifications

Specification机制提供了更高级的动态查询功能,是Spring Data JPA提供的一种机制。它允许您根据特定的查询条件创建查询规范,这些查询条件可以基于实体属性、关联关系、逻辑运算符等。通过编写自定义的Specification实现类,您可以定义复杂的查询逻辑,并将其应用于JPA查询方法中。Specification提供了更大的灵活性和自定义能力,适用于更复杂的查询需求。

普通条件动态查询

dao层代码实现

@Repository
public interface TGtSampleDao extends JpaRepository<TGtSample, String>, JpaSpecificationExecutor<TGtSample> {

}

 service层依赖包引入

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

service层方法代码实现

public R list(TGtSampleDto dto) {
        List<TGtSample> list = dao.findAll(new Specification<TGtSample>() {
            @Override
            public Predicate toPredicate(Root<TGtSample> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                // 查询条件
                List<Predicate> predicates = new ArrayList<>();
                if(dto.getType() != null){ // 是否where子句中有id
                    predicates.add(criteriaBuilder.equal(root.get("type").as(Integer.class), dto.getType()));
                }
                if(dto.getRailwayBureau()!=null && dto.getRailwayBureau()!=""){ // 是否where子句中有railwayBureau
                    predicates.add(criteriaBuilder.like(root.get("railwayBureau").as(String.class), "%"+dto.getRailwayBureau()+"%"));
                }
                if(dto.getMinUploadTime()!=null){ // 是否where子句中有uploadTime
                    predicates.add(criteriaBuilder.greaterThanOrEqualTo(root.get("uploadTime").as(LocalDateTime.class), dto.getMinUploadTime()));
                }
                if(dto.getMaxUploadTime()!=null){ // 是否where子句中有uploadTime
                    predicates.add(criteriaBuilder.lessThanOrEqualTo(root.get("uploadTime").as(LocalDateTime.class), dto.getMaxUploadTime()));
                }
                criteriaQuery.orderBy(criteriaBuilder.desc(root.get("uploadTime").as(Date.class)));

                return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
            }
        });
        return R.ok(list);
    }
分页条件动态查询

dao层代码实现

@Repository
public interface TGtSampleDao extends JpaRepository<TGtSample, String>, JpaSpecificationExecutor<TGtSample> {

}

 service层依赖包引入

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

service层方法代码实现

public R list(TGtSampleDto dto) {
        Page<TGtSample> page = dao.findAll(new Specification<TGtSample>() {
            @Override
            public Predicate toPredicate(Root<TGtSample> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                // 查询条件
                List<Predicate> predicates = new ArrayList<>();
                if(dto.getType() != null){ // 是否where子句中有id
                    predicates.add(criteriaBuilder.equal(root.get("type").as(Integer.class), dto.getType()));
                }
                if(dto.getRailwayBureau()!=null && dto.getRailwayBureau()!=""){ // 是否where子句中有railwayBureau
                    predicates.add(criteriaBuilder.like(root.get("railwayBureau").as(String.class), "%"+dto.getRailwayBureau()+"%"));
                }
                if(dto.getMinUploadTime()!=null){ // 是否where子句中有uploadTime
                    predicates.add(criteriaBuilder.greaterThanOrEqualTo(root.get("uploadTime").as(LocalDateTime.class), dto.getMinUploadTime()));
                }
                if(dto.getMaxUploadTime()!=null){ // 是否where子句中有uploadTime
                    predicates.add(criteriaBuilder.lessThanOrEqualTo(root.get("uploadTime").as(LocalDateTime.class), dto.getMaxUploadTime()));
                }
                criteriaQuery.orderBy(criteriaBuilder.desc(root.get("uploadTime").as(Date.class)));

                return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
            }
        }, PageRequest.of(dto.getCurrentPage(), dto.getSize()));
        return R.ok(page);
    }

Querydsl

    第三方通用查询框架

获取分页查询结果参数

在Spring Data JPA中,执行分页查询时,可以通过Page对象获取分页结果参数。Page对象提供了一些方法来访问分页信息和查询结果。

以下是一些常用的Page对象的方法:

  • getContent(): 返回当前页的查询结果列表。
  • getTotalElements(): 返回查询结果的总数量。
  • getTotalPages(): 返回查询结果的总页数。
  • getNumber(): 返回当前页的页码。
  • getSize(): 返回每页的大小(每页显示的结果数量)。
  • hasNext(): 检查是否有下一页。
  • hasPrevious(): 检查是否有上一页。

下面是一个示例代码,演示如何执行分页查询并获取分页结果参数:

import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;

// 在您的Repository接口中定义方法
Pageable pageable = PageRequest.of(pageNumber, pageSize);
Page<YourEntity> page = yourRepository.findAll(specification, pageable);

// 获取分页结果参数
List<YourEntity> content = page.getContent(); // 当前页的查询结果列表
long totalElements = page.getTotalElements(); // 查询结果的总数量
int totalPages = page.getTotalPages(); // 查询结果的总页数
int currentPage = page.getNumber(); // 当前页的页码
int pageSize = page.getSize(); // 每页的大小

// 检查是否有下一页和上一页
boolean hasNextPage = page.hasNext();
boolean hasPreviousPage = page.hasPrevious();

在上述代码中,首先使用PageRequest来创建Pageable对象,然后在yourRepository上调用findAll()方法执行分页查询,传入specificationpageable作为参数。返回的Page对象可以通过调用相应的方法来获取分页结果参数。

请注意,pageNumber从0开始,表示第一页;pageSize表示每页的大小(每页显示的结果数量)。

通过使用Page对象,您可以轻松获取分页查询的结果和相关信息。

SQL小知识:

1.在使用group by时, select后的字段,要么是聚合函数,要么在group by后面

2.待更新

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值