JPA学习笔记之接口JpaRepository 和 JpaSpecificationExecutor的简单使用

谈到JPA 首先是就jpa的基本原理

  1. 加载配置文件创建实体管理器工厂
    Persisitence:静态方法(根据持久化单元名称创建实体管理器工厂)
    createEntityMnagerFactory(持久化单元名称)
    作用:创建实体管理器工厂

  2. 根据实体管理器工厂,创建实体管理器
    EntityManagerFactory :获取EntityManager对象
    方法:createEntityManager
    * 内部维护的很多的内容
    内部维护了数据库信息,
    维护了缓存信息
    维护了所有的实体管理器对象
    再创建EntityManagerFactory的过程中会根据配置创建数据库表
    * EntityManagerFactory的创建过程比较浪费资源
    特点:线程安全的对象
    多个线程访问同一个EntityManagerFactory不会有线程安全问题
    * 如何解决EntityManagerFactory的创建过程浪费资源(耗时)的问题?
    思路:创建一个公共的EntityManagerFactory的对象
    * 静态代码块的形式创建EntityManagerFactory

  3. 创建事务对象,开启事务
    EntityManager对象:实体类管理器
    beginTransaction : 创建事务对象
    presist : 保存
    merge : 更新
    remove : 删除
    find/getRefrence : 根据id查询

    Transaction 对象 : 事务
    begin:开启事务
    commit:提交事务
    rollback:回滚

  4. 增删改查操作

  5. 提交事务

  6. 释放资源

了解了jpa的基本执行步骤,接下来就是我们需要了解两个重要的接口JpaRepository 和 JpaSpecificationExecutor
1.使用jpql和原生sql的基本查询方式,查询使用@Query 注解 ,注解默认使用jpql查询,添加属性nativeQuery = true 后使用sql查询
下面是我使用的实体类

package com.emon.demo.entity;

import lombok.Data;

import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;

/**
 * 1.实体类和表的映射关系
 * @Entity
 * @Table
 * 2.类中属性和标中字段的映射关系
 * @Id
 * @GeneratedValue
 * @Column
 */

@Entity
@Table(name="cst_customer")
public class Customer {
    @Id
    @GeneratedValue(strategy= GenerationType.IDENTITY)
    @Column(name="cust_id")
    private Long custId;
    @Column(name="cust_name")
    private String custName;
    @Column(name="cust_source")
    private String custSource;
    @Column(name="cust_industry")
    private String custIndustry;
    @Column(name="cust_level")
    private String custLevel;
    @Column(name="cust_address")
    private String custAddress;
    @Column(name="cust_phone")
    private String custPhone;

    /**
     * 删除主表数据:
     *
     * 	有从表数据
     *   1、在默认情况下,它会把外键字段置为null,然后删除主表数据。如果在数据库的表                结构上,外键字段有非空约束,默认情况就会报错了。
     *   2、如果配置了放弃维护关联关系的权利,则不能删除(与外键字段是否允许为null,		没有关系)因为在删除时,它根本不会去更新从表的外键字段了。
     *   3、如果还想删除,使用级联删除引用
     *
     * 	没有从表数据引用:随便删
     *
     *级联操作
     * cascade:配置级联操作
     * 		CascadeType.MERGE	级联更新
     * 		CascadeType.PERSIST	级联保存:
     * 		CascadeType.REFRESH 级联刷新:
     * 		CascadeType.REMOVE	级联删除:
     * 		CascadeType.ALL		包含所有
     */
    // 配置客户和联系人之间的关系 一对多关系
    // 放弃外键维护,参照对方来做,mappedBy填写 linkMan 的配置的对应属性名
    // fetch 配置关联对象的加载方式
    // EAGER:立即加载
    // Lazy :延迟加载
    @OneToMany(mappedBy="customer",cascade = CascadeType.ALL)
    private Set<LinkMan> linkMans = new HashSet<>();

    public Long getCustId() {
        return custId;
    }

    public void setCustId(Long custId) {
        this.custId = custId;
    }

    public String getCustName() {
        return custName;
    }

    public void setCustName(String custName) {
        this.custName = custName;
    }

    public String getCustSource() {
        return custSource;
    }

    public void setCustSource(String custSource) {
        this.custSource = custSource;
    }

    public String getCustIndustry() {
        return custIndustry;
    }

    public void setCustIndustry(String custIndustry) {
        this.custIndustry = custIndustry;
    }

    public String getCustLevel() {
        return custLevel;
    }

    public void setCustLevel(String custLevel) {
        this.custLevel = custLevel;
    }

    public String getCustAddress() {
        return custAddress;
    }

    public void setCustAddress(String custAddress) {
        this.custAddress = custAddress;
    }

    public String getCustPhone() {
        return custPhone;
    }

    public void setCustPhone(String custPhone) {
        this.custPhone = custPhone;
    }

    public Set<LinkMan> getLinkMans() {
        return linkMans;
    }

    public void setLinkMans(Set<LinkMan> linkMans) {
        this.linkMans = linkMans;
    }

    @Override
    public String toString() {
        return "Customer{" +
                "custId=" + custId +
                ", custName='" + custName + '\'' +
                ", custSource='" + custSource + '\'' +
                ", custIndustry='" + custIndustry + '\'' +
                ", custLevel='" + custLevel + '\'' +
                ", custAddress='" + custAddress + '\'' +
                ", custPhone='" + custPhone + '\'';
    }
}

以下是使用jpql定义的接口

package com.emon.demo.dao;

import com.emon.demo.entity.Customer;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import java.util.List;

/**
 * 符合SpringDataJpa的dao层接口规范
 *  JpaRepository<操作的实体类类型,实体类中主键属性的类型>
 *      *封装了基本的crud操作
 *  JpaSpecificationExecutor<操作实体类类型>、
 *      *封装了复杂的查询(分页等)
 */
public interface CustomerDao extends JpaRepository<Customer,Long>, JpaSpecificationExecutor<Customer> {

    /**
     * 使用客户名称查询客户
     * 使用jpql的形式查询
     * jpql: from Customer where cust_name = ?
     * 配置jpql语句,使用@Query注解
     */

    @Query(value="from Customer where cust_name = :cust_name")
    List<Customer> findJpql(@Param("cust_name") String cust_name);

    /**
     * 根据:客户名称和客户id查询客户
     */
    @Query(value="from Customer where cust_name = :cust_name and cust_id = :id")
    List<Customer> findNameAndId(@Param("cust_name") String cust_name,@Param("id") Long cust_id);

    /**
     * 根据:更新客户名
     * @Query;代表进行查询
     * @Modifying 代表的是当前执行的是一个更新操作
     */

    @Query(value=" update Customer set cust_name= :cust_name where cust_id = :cust_id")
    @Modifying
    void updateCustomer(@Param("cust_name") String cust_name,@Param("cust_id") Long cust_id);

    /**
    * 使用sql的形式查询
     * sql:select * from cst_customer
     * 使用原生sql查询的结构都是 List<Object[]>    </>
     */
    @Query(value=" select * from cst_customer",nativeQuery = true)
    List<Object[]> findBysql();

    @Query(value=" select * from cst_customer where cust_name like ?1%",nativeQuery = true)
    List<Object[]> findBysqlName(String name);

 /**
     * 方法名的约定
     * findBy :查询、
     * 对象中的属性名(首字母大写);查询条件
     * CustName
     * findByCustName  -- 根据客户名称查询
     * 在springdataJpa的运行阶段
     * 会根据方法名进行解析 findBy from xxx(实体类)
     *                          属性名称  where custName =
     *  1.findBy + 属性名称(根据属性名查询)
     *  2.findBy + 属性名称 + 查询方式(like | isnull) 如: findByCustNameLike
     *  3.多条件查询
     *    findBy + 属性名 + “查询方式” + "多条件的连接符(and|or)" + 属性名 + “查询方式”
     */
    Customer findByCustName(String custName);

    /**
     * 模糊查询
     * @param custName
     * @return
     */
    List<Customer> findByCustNameLike(String custName);

    /**
     * 使用客户名称模糊匹配和客户所属行业精准匹配的查询
     */
    Customer findByCustNameLikeAndCustIndustry(String custName,String custIndustry);
}

2.根据方法名约定查询方式

	 /**
     * 方法名的约定
     * findBy :查询、
     * 对象中的属性名(首字母大写);查询条件
     * CustName
     * findByCustName  -- 根据客户名称查询
     * 在springdataJpa的运行阶段
     * 会根据方法名进行解析 findBy from xxx(实体类)
     *                          属性名称  where custName =
     *  1.findBy + 属性名称(根据属性名查询)
     *  2.findBy + 属性名称 + 查询方式(like | isnull) 如: findByCustNameLike
     *  3.多条件查询
     *    findBy + 属性名 + “查询方式” + "多条件的连接符(and|or)" + 属性名 + “查询方式”
     */
    Customer findByCustName(String custName);

    /**
     * 模糊查询
     * @param custName
     * @return
     */
    List<Customer> findByCustNameLike(String custName);

    /**
     * 使用客户名称模糊匹配和客户所属行业精准匹配的查询
     */
    Customer findByCustNameLikeAndCustIndustry(String custName,String custIndustry);	

3.对于以上DAO接口的使用,在这里我使用但愿测试的方式实现;

	package com.emon.demo;

import com.emon.demo.dao.CustomerDao;
import com.emon.demo.entity.Customer;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.annotation.Rollback;

import javax.transaction.Transactional;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;

@SpringBootTest
class JpqlTests {
	@Autowired
	private CustomerDao customerDao;
    /**
	 */
	@Test
	public void testGetOne(){
		List<Customer> isExit = customerDao.findJpql("emon");
		System.out.println("isExit = " + isExit);
	}
	/**
	 */
	@Test
	public void testNameAndId(){
		List<Customer> isExit = customerDao.findNameAndId("emon",2L);
		System.out.println("isExit = " + isExit);
	}

	/**
	 * 更新方法需要添加
	 * @Transactional
	 * @Rollback(value=false)
	 */
	@Test
	@Transactional
	@Rollback(value=false)
	public void testupdate(){

		customerDao.updateCustomer("唐三",3L);
//		System.out.println("isExit = " + isExit);
	}

	/**
	 */
	@Test
	public void testSqlSelect(){

		customerDao.findBysql().forEach(s -> System.out.println("s = " + Arrays.toString(s)));
//		System.out.println("isExit = " + isExit);findBysqlName
	}


	/**
	 */
	@Test
	public void findBysqlName(){
		customerDao.findBysqlName("e").forEach(s -> System.out.println("s = " + Arrays.toString(s)));
//		System.out.println("isExit = " + isExit);findBysqlName
	}
	/**
	 * 方法名的约定
	 * findBy :查询
	 * 对象中的属性名(首字母大写);查询条件
	 * CustName
	 * findByCustName  -- 根据客户名称查询
	 * 在springdataJpa的运行阶段
	 * 会根据方法名进行解析 findBy from xxx(实体类)
	 * 属性名称  where custName =
	 */
	@Test
	void findByCustName() {

		System.out.println("customerDao = " + customerDao.findByCustName("唐三"));
	}

	@Test
	void findByCustNameLink() {

		System.out.println("customerDao = " + customerDao.findByCustNameLike("%三%"));
	}

	@Test
	void findByCustNameLikeAndCustIndustry() {
		Customer c = customerDao.findByCustNameLikeAndCustIndustry("唐%","诺丁城学院");
		System.out.println("c = " + c);
	}
	/**
	 * Specification:查询条件
	 * 自定义我们自己的Specification实现类
	 *	实现
	 * root:查询的根对象
	 *
	 */
	
}

4.接下来使用介绍下JpaRepository接口的的方法和简单的使用
源码中JpaRepository接口的方法有

  List<T> findAll();

    List<T> findAll(Sort var1);

    List<T> findAllById(Iterable<ID> var1);

    <S extends T> List<S> saveAll(Iterable<S> var1);

    void flush();

    <S extends T> S saveAndFlush(S var1);

    void deleteInBatch(Iterable<T> var1);

    void deleteAllInBatch();

    T getOne(ID var1);

    <S extends T> List<S> findAll(Example<S> var1);

    <S extends T> List<S> findAll(Example<S> var1, Sort var2);

5.JpaRepository接口中方法的简使用

package com.emon.demo;

import com.emon.demo.dao.CustomerDao;
import com.emon.demo.entity.Customer;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.Example;

import javax.transaction.Transactional;
import java.util.List;
import java.util.Optional;

@SpringBootTest
class JpaRepositoryTests {

	@Autowired
	private CustomerDao customerDao;

	@Test
	public void contextLoads() {
		Customer customer = new Customer();
		customer.setCustId(1L);
		Optional<Customer> cc = customerDao.findOne(Example.of(customer));
        System.out.println("c = " + cc.get());
	}
	@Test
	public void saveTest() {
		Customer customer = new Customer();
		customer.setCustName("emon");
		customer.setCustLevel("vip");
		customer.setCustIndustry("IT教育");
		customerDao.save(customer);
	}
	@Test
	public void saveTest2() {
		Customer customer = new Customer();
//		customer.setCust_id(3L);
		customer.setCustName("emon");
		customer.setCustLevel("vip");
		customer.setCustIndustry("蓝银草武魂修炼");
		customerDao.save(customer);
	}
	// 主键已经存时,更新
	@Test
	public void saveTest3() {
		Customer customer = new Customer();
		customer.setCustId(4L);
		customer.setCustName("emon");
		customerDao.save(customer);
	}
	// 主键已经存时,更新
	@Test
	public void delTest() {
		Customer customer = new Customer();
		customer.setCustId(4L);
		customerDao.delete(customer);


	}
	// 主键已经存时,更新
	@Test
	public void findAllTest() {
		List<Customer> list = customerDao.findAll();

		list.forEach(s -> System.out.println("s = " + s));
	}
	/**
	 * 测试统计查询,查询客户的总数量
	 */
	@Test
	public void testCount(){
		long count = customerDao.count();
		System.out.println("count = " + count);
	}

	/**
	 * 查询:判断id为4的客户是否存在
	 * 		如果为空
	 */
	@Test
	public void testExit(){
		Customer customer = new Customer();
		customer.setCustId(4L);
		boolean isExit = customerDao.exists(Example.of(customer));
		System.out.println("isExit = " + isExit);
	}

	/**
	 * 根据id从数据库查询
	 * findOne: em.findOne  立即加载
	 * getOne: em.getReference  延迟加载
	 * @Transactional
	 */
	@Test
	@Transactional
	public void testGetOne(){
//		Customer customer = new Customer();
//		customer.setCust_id(4L);
		Customer isExit = customerDao.getOne(1L);
		System.out.println("isExit = " + isExit);
	}
}

6.接着再来看看JpaSpecificationExecutor接口中的基本方法

Optional<T> findOne(@Nullable Specification<T> var1);

List<T> findAll(@Nullable Specification<T> var1);

Page<T> findAll(@Nullable Specification<T> var1, Pageable var2);

List<T> findAll(@Nullable Specification<T> var1, Sort var2);

long count(@Nullable Specification<T> var1);

7.对于JpaSpecificationExecutor中的方法就是要通过构造查询条件来查询,以下是基本使用方式

package com.emon.demo;

import com.emon.demo.dao.SpecificationTest;
import com.emon.demo.entity.Customer;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;

import javax.persistence.criteria.*;
import java.util.List;

@SpringBootTest
public class SpecificationTestDemo {

    @Autowired
    private SpecificationTest specificationTest;

    /**
     * 根据条件查询单个对象
     * 自定义查询条件
     *  1.实现Specification接口(提供泛型,查询的条件对象类型)
     *  2.实现toPredicate方法(构造查询条件)
     *  3.借助方法参数中的两个参数(
     *      root:获取需要查询的对象属性
     *      CriteriaBuilder:构造查询条件,内部封装了很多的查询条件(模糊匹配,精准匹配)
     *  )
     * 根据客户名称查询
     */
    @Test
    public void test1(){
        Specification<Customer> spec = new Specification<Customer>() {
            @Override
            public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                // 1.获取比较属性
                Path<Object> custName = root.get("custName");
                //2.构造查询条件
                Predicate predicate = criteriaBuilder.equal(custName,"唐三"); // 进行精准匹配(属性,属性的值)
                return predicate;
            }
        };
        Customer customer = specificationTest.findOne(spec).get();
        System.out.println("customer = " + customer);
    }
    // jdk8改写
    @Test
    public void test1_jdk8(){
        Customer customer = specificationTest.findOne((root,criteriaQuery,criteriaBuilder)
                ->criteriaBuilder.equal(root.get("custName"),"唐三"))
                .get();
        System.out.println("customer = " + customer);
    }

    /**
     * 多条件查询
     *   案例:根据客户名和客户所属行业查询
     *
     */
    @Test
    public void testSpec1(){
        /**
         * root:获取属性
         *  客户名
         *  所属行业
         * criteriaBuilder:构造查询
         *  1.构造客户名的精准查询
         *  2.构造所属行业的精准匹配查询
         *  3.将以上两个查询联合起来
         */
        Specification<Customer> spec = new Specification<Customer>() {
            @Override
            public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                Path<Object> custName = root.get("custName");
                Path<Object> custIndustry = root.get("custIndustry");
                // 构造查询
                // 1.构造客户名的精准匹配查询
                Predicate p1 = criteriaBuilder.equal(custName,"唐三");
                Predicate p2 = criteriaBuilder.equal(custIndustry,"诺丁城学院");
                // 将多个查询条件组合到一起,组合(满足条件1并且满足条件二,)
                Predicate predicate =  criteriaBuilder.and(p1,p2);  // 以于的方式拼接多个查询条件
                // criteriaBuilder.or(p1,p2); // 以或的方式拼接多个查询条件
                return predicate;
            }
        };
        Customer customer = specificationTest.findOne(spec).get();
        System.out.println("customer = " + customer);
    }
    // jdk8改写 testSpec1
    @Test
    public void testSpec1_jdk8(){
        Customer customer = specificationTest.findOne((root,cquery,cb)
                -> cb.and(cb.equal(root.get("custName"),"唐三")
                 ,cb.equal(root.get("custIndustry"),"诺丁城学院")
        )).get();
        System.out.println("customer = " + customer);
    }
    /**
     *  模糊查询
     *   equal:直接到path对象(属性),然后比较即可
     *   gt,lt,ge,le,like:得到path对象,根据path 指定path 指定比较的参数类型,再去进行比较
     *   指定参数类型:path.as(类型的字节码对象)
     */
    @Test
    public void testSpec2(){
        /**
         *构造查询条件
         */
        Specification<Customer> spec = new Specification<Customer>() {
            @Override
            public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                Path<String> custName = root.get("custName");
                Path<String> custIndustry = root.get("custIndustry");
                // 构造查询
                // 1.构造客户名的精准匹配查询
                Predicate p1 = criteriaBuilder.like(custName,"_三");
                Predicate p2 = criteriaBuilder.like(custIndustry,"%学院");
                // 将多个查询条件组合到一起,组合(满足条件1并且满足条件二,)
//                Predicate predicate =  criteriaBuilder.and(p1,p2);  // 以于的方式拼接多个查询条件
                Predicate predicate =  criteriaBuilder.or(p1,p2); // 以或的方式拼接多个查询条件
                return predicate;
            }
        };
        List<Customer> customer = specificationTest.findAll(spec);
        System.out.println("customer = " + customer);
    }
    // jdk8改写 testSpec2
    @Test
    public void testSpec2_jdk8(){
        Customer customer = specificationTest.findOne((root,cquery,cb)
                -> cb.or(cb.like(root.get("custName"),"唐三")
                ,cb.like(root.get("custIndustry"),"诺丁城学院")
        )).get();
        System.out.println("customer = " + customer);
    }
    /**
     *  模糊查询 排序
     *   equal:直接到path对象(属性),然后比较即可
     *   gt,lt,ge,le,like:得到path对象,根据path 指定path 指定比较的参数类型,再去进行比较
     *   指定参数类型:path.as(类型的字节码对象)
     */
    @Test
    public void testSpec3(){
        /**
         *构造查询条件
         */
        Specification<Customer> spec = new Specification<Customer>() {
            @Override
            public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                Path<Object> custName = root.get("custName");
                Path<Object> custIndustry = root.get("custIndustry");
                // 构造查询
                // 1.构造客户名的精准匹配查询
                Predicate p1 = criteriaBuilder.like(custName.as(String.class),"_三");
                Predicate p2 = criteriaBuilder.like(custIndustry.as(String.class),"%学院");
                // 将多个查询条件组合到一起,组合(满足条件1并且满足条件二,)
//                Predicate predicate =  criteriaBuilder.and(p1,p2);  // 以于的方式拼接多个查询条件
                Predicate predicate =  criteriaBuilder.or(p1,p2); // 以或的方式拼接多个查询条件
                return predicate;
            }
        };
//        List<String> list = new ArrayList<>();
//        list.add("custId");
        List<Customer> customer = specificationTest.findAll(spec, Sort.by(Sort.Direction.DESC,"custId"));
        System.out.println("customer = " + customer);
    }
    // jdk8改写 testSpec3
    @Test
    public void testSpec3_jdk8(){
        List<Customer> customers = specificationTest.findAll((root,cquery,cb) ->
                 cb.or(cb.like(root.get("custName"),"_三")
                ,cb.like(root.get("custIndustry"),"%学院")
        ),Sort.by(Sort.Direction.DESC,"custId"));

        System.out.println("customer = " + customers);
    }



    /**
     * // 分页查询
     * findAll(Specification,Pageable)
     * Pageable:分页参数,查询的页码,每页查询的条件
     * 返回  Page(springDataJpa为我们封装好的pageBean对象,数据列表,工条件)
     */
    @Test
    public void testSpec4(){
        Specification spec = null;
        /**
         * pageRequest对象是Pageable接口的实现类
         * 创建pageRequest的过程中,需要调用他的构造方法传入两个参数
         * 第一个参数:当前查询的页数(从0开始)
         * 第二个参数:每页查询的数量
         */
        Pageable pageable = PageRequest.of(0,2, Sort.by(Sort.Direction.DESC,"custId"));
        Page<Customer> cs =  specificationTest.findAll(spec,pageable);
        long eles = cs.getTotalElements();
        System.out.println("eles = " + eles);
        int pages = cs.getTotalPages();
        System.out.println("pages = " + pages);
        List<Customer> c =  cs.getContent();
        System.out.println("c = " + c);
    }
    // jdk8改写 testSpec4
    @Test
    public void testSpec4_jdk8(){
        Page<Customer> pages = specificationTest.findAll((root,cquery,cb) ->
                cb.or(cb.like(root.get("custName"),"_三")
                        ,cb.like(root.get("custIndustry"),"%学院")
                ),
                PageRequest.of(0,2,Sort.by(Sort.Direction.DESC,"custId")));

        System.out.println("customer = " + pages.getContent()); // 内容

        System.out.println("pages.getTotalElements() = " + pages.getTotalElements()); // 共多少条

        System.out.println("pages.getTotalPages() = " + pages.getTotalPages()); // 有多少页

        System.out.println("pages.getNumberOfElements() = " + pages.getNumberOfElements());
    }
    /**
     * 根据条件统计个数
     */
    @Test
    public void testCount(){
        /**
         *构造查询条件
         */
        Specification<Customer> spec = new Specification<Customer>() {
            @Override
            public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                Path<Object> custName = root.get("custName");
                Path<Object> custIndustry = root.get("custIndustry");
                // 构造查询
                // 1.构造客户名的精准匹配查询
                Predicate p1 = criteriaBuilder.like(custName.as(String.class),"_三");
                Predicate p2 = criteriaBuilder.like(custIndustry.as(String.class),"%学院");
                // 将多个查询条件组合到一起,组合(满足条件1并且满足条件二,)
//                Predicate predicate =  criteriaBuilder.and(p1,p2);  // 以于的方式拼接多个查询条件
                Predicate predicate =  criteriaBuilder.or(p1,p2); // 以或的方式拼接多个查询条件
                return predicate;
            }
        };
        long count = specificationTest.count(spec);
        System.out.println("count = " + count);
    }

    // jdk8改写 testCount
    @Test
    public void testCount_jdk8(){
        long count = specificationTest.count((root,cquery,cb) ->
                        cb.or(
                                cb.like(root.get("custName"),"_三")
                                ,cb.like(root.get("custIndustry"),"%学院")
                        ));

        System.out.println("count = " + count); //
    }

}

点击链接查看源码

  • 0
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
回答: 在使用JPA编写Repository接口方法时,可以按照以下几种方式进行编写。首先,可以直接继承JpaRepository接口,然后调用对应的save方法来实现数据的保存。其次,可以在dao层中实现Repository接口的方法,方法名需要符合规范。\[1\]JpaRepository继承了PagingAndSortingRepository接口,并添加了一组JPA规范相关的方法。在JpaRepository中,直接返回了List,省去了我们进行强制类型转换的步骤。在开发中,最常用的是JpaRepositoryJpaSpecificationExecutor接口。\[2\]如果需要了解更多关于JpaRepository使用方法,可以参考相关的文章,如《JpaRepository数据层 Spring Data JPA 提供的各种Repository接口》和《一步一步学SpringDataJpa——JpaRepository查询功能》。\[3\] #### 引用[.reference_title] - *1* [spring jpa基础:使用repository接口](https://blog.csdn.net/Dumb_Brother/article/details/127449008)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [JPA的Repository详解](https://blog.csdn.net/xfx_1994/article/details/104921234)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值