一,springdata简介

1,orm思想

​ 主要的目的就是操作实体类就相当于操作数据库表
​ 实现:需要建立映射关系
​ 实体类和表的映射关系
​ 实体类中属性和表中字段的映射关系
​ 不需要重点去关注SQL语句
​ 实现了orm思想的框架: MyBatis(半自动ORM); hibernate(全自动)

2,hibernate框架

hibernate是一个开源的对象关系映射框架,对JDBC进行了非常轻量化的对象封装,使POJO和数据库表建立映射关系,可以自动生成SQL语句,自动执行

3,JPA规范

​ jpa是一套规范全称(Java Persistence API )既Java持久化操作, sun公司研发 供各大厂商实现这套规范,内部是有接口和抽象类组成

Jpa的优势:
​ 1.标准化 是一套规范
​ 2.容器级特性的支持,
​ 支持大数据集,事务,并发等容器级的事务
​ 3.

二,JPA的基本操作

1.)创建persistence.xml配置文件

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">
    <!--需要配置persistence-unit节点
        持久化单元:
            name:持久化单元名称
            transaction-type:事务管理的方式
                    JTA:分布式事务管理
                    RESOURCE_LOCAL:本地事务管理
    -->
    <persistence-unit name="myJpa" transaction-type="RESOURCE_LOCAL">
        <!--jpa的实现方式 -->
        <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>

        <!--可选配置:配置jpa实现方的配置信息-->
        <properties>
            <!-- 数据库信息
                用户名,javax.persistence.jdbc.user
                密码,  javax.persistence.jdbc.password
                驱动,  javax.persistence.jdbc.driver
                数据库地址   javax.persistence.jdbc.url
            -->
            <property name="javax.persistence.jdbc.user" value="root"/>
            <property name="javax.persistence.jdbc.password" value="980311"/>
            <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
            <property name="javax.persistence.jdbc.url" value="jdbc:mysql:///jpa"/>

            <!--配置jpa实现方(hibernate)的配置信息
                显示sql           :   false|true
                自动创建数据库表    :  hibernate.hbm2ddl.auto
                        create      : 程序运行时创建数据库表(如果有表,先删除表再创建)
                        update      :程序运行时创建表(如果有表,不会创建表)
                        none        :不会创建表
            -->
            <property name="hibernate.show_sql" value="true" />
            <property name="hibernate.hbm2ddl.auto" value="update" />
        </properties>
    </persistence-unit>
</persistence>

2.)创建实体类和映射关系

/**
 * @author 李phCode
 * @create 2020 -08 -07 13:38
 * 客户的实体类
 * 配置映射关系
 * 1.实体类和表的映射关系
 * 2.实体类中属性和表中字段的映射关系
 */
@Entity
@Table(name = "cst_customer")//标注数据库表
public class Customer {
    /*
     * @Id 声明主键的配置
     * @GeneratedValue 配置主键的生成策略
     *       GenerationType.IDENTITY 自增 适合MySQL
     *                  底层数据库必须支持自动增长
     *       GenerationType.SEQUENCE 序列 适合Oracle
     *                  底层数据库必须支持序列
     *       GenerationType.TABLE   jpa提供的一种机制,通过一张数据库表的形式帮我们完成自动增长
     *       GenerationType.AUTO    由程序自动的帮助我们选择主键的生成策略
     * */
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "cust_id")
    private Long custId;//客户主键
    @Column(name = "cust_name")
    private String custName;//客户名称

3).创建demo测试保存

	/*
     * 测试jpa的保存
     *       保存一个客户到数据库中
     *  jpa的操作步骤
     *       1.加载配置文件创建工厂(实体类管理工厂)
     *          Persistence:静态方法(根据持久化单元名称创建实体类管理工厂)
     *           <persistence-unit name="myJpa" transaction-type="RESOURCE_LOCAL">
     *              createEntityManagerFactory(持久化单元名称)
     *              作用:创建实体管理工厂
     *       2.通过实体类管理器工厂获取实体类管理器
     *          EntityManagerFactory:获取EntityManager对象
     *          createEntityManager:维护
     *              数据库信息,缓存信息,所有实体管理对象
     *             再创建EntityManagerFactory的过程中会根据配置创建数据库表
     *            但是EntityManagerFactory创建的过程中会浪费资源(耗时,因为维护太多东西)
     *           特点:
     *              是线程安全的对象,多个线程访问同一个EntityManagerFactory不会有线程安全问题
     *           解决:
     *              创建公共的EntityManagerFactory的对象,使用静态代码块
     *       3.获取事务对象,开启事务
     *              merge(更新);
     *              remove(删除);
     *              find/getReference(根据id查询)
     *       4.完成CRUD
     *       5.提交事务(回滚事务)
     *       6.释放资源
     * */
    @Test
    public void testSave() {
        //1.加载配置文件创建工厂(实体类管理工厂)
        EntityManagerFactory factory = Persistence.createEntityManagerFactory("myJpa");
        //2.通过实体类管理器工厂获取实体类管理器
        EntityManager entityManager = factory.createEntityManager();
        //3.获取事务对象,开启事务我
        EntityTransaction transaction = entityManager.getTransaction();
        transaction.begin();//开启事务
        //4.完成CRUD	保存
        Customer customer = new Customer();
        customer.setCustName("百度");
        customer.setCustIndustry("工具");
        customer.setCustAddress("北京");
        customer.setCustSource("传真");
        customer.setCustLevel("3");
        customer.setCustPhone("34232432532");
        entityManager.persist(customer);//保存
        //5.提交事务(回滚事务)
        transaction.commit();
        //6.释放资源
        entityManager.close();
        factory.close();
    }

4.)解决EntityManagerFactory耗时

/**
 * @author 李ph Code
 * @create 2020 -08 -08 14:46
 * 通过代码快的方式,当程序第一次访问这个类的时候,会创建一个公共的实体管理工厂对象
 * 第一次访问getEntityManager方法:经过静态块创建一个factory对象,在调用方法创建一个EntityManager对象
 * 第二次访问getEntityManager方法:直接通过一个已经创建好的factory对象,创建EntityManager对象
 */
public class JpaUtils {
    private static EntityManagerFactory entityManagerFactory;

    static {
        //1.加载配置文件 创建enityManagerFactory
        entityManagerFactory = Persistence.createEntityManagerFactory("");
    }

    /*
     * 获取EntityManager对象
     * */
    public static EntityManager getEntityManager() {
        return entityManagerFactory.createEntityManager();
    }
}

5.)使用工具类

/*
     * 根据id查询
     * */
    @Test
    public void testFind() {
        //1.获取工具类的entity Manager
        EntityManager entityManager = JpaUtils.getEntityManager();
        //2.开启事务
        EntityTransaction transaction = entityManager.getTransaction();
        transaction.begin();
      
     1   //3.增删改查	根据id查询
        Customer customer = entityManager.find(Customer.class, 1l);
        System.out.println("customer = " + customer);
      
     2 	//先查询在删除
        Customer customer = entityManager.find(Customer.class, 2l);
        entityManager.remove(customer);
      
     3	//先查询在修改
        Customer customer = entityManager.find(Customer.class, 1l);
        customer.setCustName("百度u");
      
     4 	//查询全部
       	String jpql = "from org.ph.Bean.Customer";
        Query query = entityManager.createQuery(jpql);
      	List resultList = query.getResultList();
        for (Object o : resultList) {
            System.out.println("o = " + o);
        }
		
     5 	//分页
        String jpql = "from Customer";
        Query query = entityManager.createQuery(jpql);
        //起始分页
        query.setFirstResult(1);
        //每页查询的条数
        query.setMaxResults(2);
        List resultList = query.getResultList();
        for (Object o : resultList) {
            System.out.println("o = " + o);
        }
      
     6  //like 查询 
      	String jpql = "from Customer where custName like ? ";
        Query query = entityManager.createQuery(jpql);
        //占位符参数 从1开始
        query.setParameter(1, "测%"); //以北开头的
        List resultList = query.getResultList();
        for (Object o : resultList) {
            System.out.println("o = " + o);
        }
      
        //4.提交事务
        transaction.commit();
        //5.释放资源
        entityManager.close();
    }

6.Find和getReference

/*
 * 根据id查询
 *  Find方法查询:
 *      调用fin方法的时候就会发送SQL语句到数据库
 * */
@Test
public void testFind() {
    //1.获取工具类的entity Manager
    EntityManager entityManager = JpaUtils.getEntityManager();
    //2.开启事务
    EntityTransaction transaction = entityManager.getTransaction();
    transaction.begin();
    //3.增删改查
    Customer customer = entityManager.find(Customer.class, 1l);
    System.out.println("customer = " + customer);
    //4.提交事务
    transaction.commit();
    //5.释放资源
    entityManager.close();
}

/*
 * 根据id查询
 *  getReference方法  懒加载
 *          1.这个方法会获取动态代理对象
 *          2.调用getReference方法不会立即查询SQL
 *                  当调用查询结果的时候才会查询SQL语句,也就什么时候用 什么时候查询数据库
 *
 * */
@Test
public void testReference() {
    //1.获取工具类的entity Manager
    EntityManager entityManager = JpaUtils.getEntityManager();
    //2.开启事务
    EntityTransaction transaction = entityManager.getTransaction();
    transaction.begin();
    //3.增删改查
    Customer customer = entityManager.getReference(Customer.class, 1l);
    System.out.println("customer = " + customer);
    //4.提交事务
    transaction.commit();
    //5.释放资源
    entityManager.close();
}

三,SpringDataJpa

1.创建spring-data-jpademo

1.)springdatajpa的maven依赖

<properties>
        <spring.version>4.2.4.RELEASE</spring.version>
        <hibernate.version>5.0.7.Final</hibernate.version>
        <slf4j.version>1.6.6</slf4j.version>
        <log4j.version>1.2.12</log4j.version>
        <c3p0.version>0.9.1.2</c3p0.version>
        <mysql.version>5.1.6</mysql.version>
    </properties>

    <dependencies>
        <!-- junit单元测试 -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.9</version>
            <scope>test</scope>
        </dependency>
        
        <!-- spring beg -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.6.8</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
        </dependency>
        
        <!-- spring end -->

        <!-- hibernate beg -->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>${hibernate.version}</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <version>${hibernate.version}</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>5.2.1.Final</version>
        </dependency>
        <!-- hibernate end -->

        <!-- c3p0 beg -->
        <dependency>
            <groupId>c3p0</groupId>
            <artifactId>c3p0</artifactId>
            <version>${c3p0.version}</version>
        </dependency>
        <!-- c3p0 end -->

        <!-- log end -->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>${log4j.version}</version>
        </dependency>

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>${slf4j.version}</version>
        </dependency>

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>${slf4j.version}</version>
        </dependency>
        <!-- log end -->

        
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-jpa</artifactId>
            <version>1.9.0.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>4.2.4.RELEASE</version>
        </dependency>
        
        <!-- el beg 使用spring data jpa 必须引入 -->
        <dependency>  
            <groupId>javax.el</groupId>  
            <artifactId>javax.el-api</artifactId>  
            <version>2.2.4</version>  
        </dependency>  
          
        <dependency>  
            <groupId>org.glassfish.web</groupId>  
            <artifactId>javax.el</artifactId>  
            <version>2.2.4</version>  
        </dependency> 
        <!-- el end -->
    </dependencies>

2.)springdata jap整合创建application.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:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:jpa="http://www.springframework.org/schema/data/jpa"
       xmlns:task="http://www.springframework.org/schema/task"
       xsi:schemaLocation="
      http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
      http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
      http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
      http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
      http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
      http://www.springframework.org/schema/data/jpa
      http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">

    <!--spring 和 spring data jpa的配置-->

    <!-- 1.创建entityManagerFactory对象交给spring容器管理-->
    <bean id="entityManagerFactoty" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <!--配置的扫描的包(实体类所在的包) -->
        <property name="packagesToScan" value="org.ph.Bean"/>
        <!-- jpa的实现厂家 -->
        <property name="persistenceProvider">
            <bean class="org.hibernate.jpa.HibernatePersistenceProvider"/>
        </property>

        <!--jpa的供应商适配器 -->
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                <!--配置是否自动创建数据库表 -->
                <property name="generateDdl" value="false"/>
                <!--指定数据库类型 是枚举类型
                public enum Database {
                    DEFAULT,        DB2,        DERBY,      H2,    HSQL,
                    INFORMIX,       MYSQL,      ORACLE,     POSTGRESQL,
                    SQL_SERVER,     SYBASE;
                -->
                <property name="database" value="MYSQL"/>
                <!--数据库方言:支持的特有语法 -->
                <property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect"/>
                <!--是否显示sql -->
                <property name="showSql" value="true"/>
            </bean>
        </property>

        <!--jpa的方言 :高级的特性 -->
        <property name="jpaDialect">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect"/>
        </property>

    </bean>

    <!--2.创建数据库连接池 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="user" value="root"></property>
        <property name="password" value="980311"></property>
        <property name="jdbcUrl" value="jdbc:mysql:///jpa"></property>
        <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
    </bean>

    <!--3.整合spring dataJpa-->
    <jpa:repositories base-package="cn.itcast.dao" transaction-manager-ref="transactionManager"
                      entity-manager-factory-ref="entityManagerFactoty"></jpa:repositories>

    <!--4.配置事务管理器 -->
    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactoty"></property>
    </bean>

    <!-- 4.txAdvice-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="save*" propagation="REQUIRED"/>
            <tx:method name="insert*" propagation="REQUIRED"/>
            <tx:method name="update*" propagation="REQUIRED"/>
            <tx:method name="delete*" propagation="REQUIRED"/>
            <tx:method name="get*" read-only="true"/>
            <tx:method name="find*" read-only="true"/>
            <tx:method name="*" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>

    <!-- 5.aop-->
    <aop:config>
        <aop:pointcut id="pointcut" expression="execution(* cn.itcast.service.*.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut"/>
    </aop:config>
    <!--5.声明式事务 -->

    <!-- 6. 配置包扫描-->
    <context:component-scan base-package="cn.itcast"></context:component-scan>
</beans>

3.)实体类

/**
 * @author 李phCode
 * @create 2020 -08 -07 13:38
 * 客户的实体类
 * 配置映射关系
 * 1.实体类和表的映射关系
 * 2.实体类中属性和表中字段的映射关系
 */
@Entity
@Table(name = "cst_customer")
@Proxy(lazy = false)
public class Customer {

    /*
     * @Id 声明主键的配置
     * @GeneratedValue 配置主键的生成策略
     *       GenerationType.IDENTITY 自增 适合MySQL
     *                  底层数据库必须支持自动增长
     *       GenerationType.SEQUENCE 序列 适合Oracle
     *                  底层数据库必须支持序列
     *       GenerationType.TABLE   jpa提供的一种机制,通过一张数据库表的形式帮我们完成自动增长
     *       GenerationType.AUTO    由程序自动的帮助我们选择主键的生成策略
     * */
    @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_level")
    private String custLevel;//客户级别
    @Column(name = "cust_industry")
    private String custIndustry;//客户所属行业
    @Column(name = "cust_phone")
    private String custPhone;//客户的联系方式
    @Column(name = "cust_address")
    private String custAddress;//客户地址

 	...set get 

4.)Dao接口

springdatajpa不需要实现类,不需要定义接口 继承

/**
 * @author 李phCode
 * @create 2020 -08 -09 19:03
 * SpringDataJpa的dao接口的规范
 *  	JpaRepository<操作的实体类对象类型,实体类中主键属性的类型>
 *         		封装了基本的CRUD操作
 *  	JpaSpecificationExecutor<操作实体类类型>
 *          	封装了复杂操作(分页,,)
 */
public interface CustomerDao extends JpaRepository<Customer,Long>, JpaSpecificationExecutor<Customer> {
}

5.)测试CRUD

@RunWith(SpringJUnit4ClassRunner.class)//声明spring提供的单元测试环境
@ContextConfiguration(locations = "classpath:applicationContext.xml")//指定spring容器的配置信息
public class CustomerDaoTest {

    @Autowired
    private CustomerDao customerDao;//获取容器中的dao
	/*更新*/
    @Test
    public void UpdaCus() {
        Customer one = customerDao.findOne(2l);	//先查询
        one.setCustName("Java");
        one.setCustAddress("上海");
        one.setCustLevel("4");
        customerDao.save(one);		
    }
    /*根据id查询*/
    @Test
    public void SeleIDOne() {
        Customer one = customerDao.getOne(1l);
        System.out.println("one = " + one);
    }
  	/*删除*/
   customerDao.delete(4l);
  
  	/*查询所有*/
  	List<Customer> all = customerDao.findAll();
        for (Customer customer : all) {
            System.out.println("customer = " + customer);
        }
  
     /*保存
      *   save:
      *       if(id!=null){
      *              query and update
      *       }else{
      *           save
      *       }
      * */
  	Customer customer = new Customer();
        customer.setCustName("Java");
        customer.setCustAddress("上海");
        customer.setCustLevel("2");
        customerDao.save(customer);

2.SpringData-Jpa的运行过程和原理

​ 1.通过的JdkDynamicAopProxy的invoke方法创建了一个动态代理对象(接口实现的那两个)
​ (SimpleJpaRepository<T, ID extends Serializable> implements JpaRepository<T, ID>, JpaSpecificationExecutor)
​ 2.SimpleJpaRepository当中封装了JPA的操作(借助jpa的api实现CURD)
​ 3.通过hibernate完成数据库的操作

3.复杂查询

/*
 * 根据id查询
 *   findOne:
 *       em.find()           :立即加载
 *   getOne:
 *       em.getReference     :延迟加载
 *       返回的是一个客户的动态代理对象
 *  @Transactional:保证正常运行
 *
 * */
@Test
@Transactional
public void GetOne() {
    Customer one = customerDao.getOne(1l);
    System.out.println("one = " + one); //使用输出的时候在查询数据库:延迟加载
}

1.借助接口的定义好的方法完成查询

2.jpql的查询(jpa query language)
​ 语法类似SQL语句,但是jpql查询的是类的属性字段
用法:
​ 需要在接口上配置jpql语句,使用注解@query

/*
 * 根据客户名称和id查询
 *   jpql: from Customer where custName= ? nad custid= ?
 *	@Query(value = "from Customer where custName= ?1 and custId= ?2")
 *	还可以根据坐标指定下标
 * */
@Query(value = "from Customer where custName= ? and custId= ?")
Customer FindCustNameAndId(String name, Long id);

 /*更新语句*/
 @Query(value = "update Customer set custName= ? ,custAddress = ? where custId=?")
 @Modifying
 int CustUpda(String name, String address, Long id);

4.SQL语句的查询

使用:

​ 1.在dao接口上配置方法
​ 2.只用注解配置SQL语句
​ 3.使用@Query
​ value:jpql语句
​ nativeQuery: false(使用jpql语句)/ true(使用本地查询:SQL语句)

	/*使用SQL语句查询*/
    @Query(value ="select * from cst_customer" ,nativeQuery = true)
    List<Customer> Finfall();	
	
	/*使用SQL语句模糊查询*/
    @Query(value = "select * from cst_customer where cust_name like ?", nativeQuery = true)
    List<Customer> FindLike(String name);

5.方法名规则查询

是对jpql更深一层的封装
​ 只需要按照springdataJpa 提供的方法名规则定义方法不需要在配置jpql语句
用法规则:
​ findBy开头代表查询
​ 对象属性名首字母大写 查询的条件

/*使用SpringDataJpa的方法名约定
*   findBy :查询
*       对象名首字母大写,查询的条件
*        CustName
*          默认情况使用等于查询
*    finByCUstName
*           根据客户的名称查询
*   1.findBy + 属性名称 (根据属性名称进行完成匹配的查询)
*   2.findBy + 属性名称 + 查询方式 (like IsNull)
*   3.多条件查询
*       finBY + 属性名 + 查询方式 + 多条件的连接符(and or )+ 属性名 + 查询方式
* */

6.Specifications动态查询

1.)Specifications动态查询

public interface JpaSpecificationExecutor<T> {
	//查询单个对象
	T findOne(Specification<T> spec);
	//查询全部
	List<T> findAll(Specification<T> spec);
	//查询分页 Pageable 分页参数
 	//Page 返回值 分页PageBean(page是springdatajpa提供的内置对象)
	Page<T> findAll(Specification<T> spec, Pageable pageable);
  	//查询全部 Sort 排序参数
	List<T> findAll(Specification<T> spec, Sort sort);
	//统计数量
	long count(Specification<T> spec);
  
  Specification://查询条件
    	//需要我们自己定义Specification实现类
    	//Root:查询的根对象(查询的任何属性都可以在跟对象内获取)
    	//CriteriaQuery:顶层查询对象,自定义的查询方式
    	//CriteriaBuilder:查询的构造器,封装了很多的查询条件
  	Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb);
  
  实现简单的单字段查询
    @Test
    public void testSpe() {
        /*构建查询条件
         *  new 匿名内部类
         *     自定义查询条件
         *          1/实现Specification接口(提供泛型:查询的对象类型)
         *          2/实现toPredicate方法(构造查询条件)
         *          3/需要借助方法参数中的两个对象属性
         *              Root:获取所需要的对象属性
         *              CriteriaQuery:构造查询条件的,内部封装了很多的查询条件
         *
         *   实现根据客户名查询
         *      查询条件
         *          1.查询方式
         *                CriteriaQuery对象
         *          2.比较的属性名称
         *                  Root对象
         * */
        Specification<Customer> specification = new Specification<Customer>() {
            public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> query, CriteriaBuilder cb) 	{
                //1.获取比较的属性s
                Path<Object> custName = root.get("custName");
                //2.构造查询条件:select *from cst_customer where  cust_name = '百度'
                /*
                 * 第一个参数:需要比较的属性(path对象)
                 * 第二个参数:当前需要比较的值
                 * */
                Predicate 百度 = cb.equal(custName, "百度u");
                return 百度;
            }
        };
        Customer one = customerDao.findOne(specification);
        System.out.println("one = " + one);
    }
  
  //多字段的查询
  @Test
    public void testSpec1(){
        Specification<Customer> specification=new Specification<Customer>() {
            /*
            * root 获取属性
            *       客户名
            *        所属行业
            *  cb  构造查询
            *       1.构造客户名的精准匹配
            *       2.构造所属行业的精准匹配查询
            *       3.将以上的两个查询联系起来
            *
            * */
            public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                Path<Object> custName = root.get("custName");
                Path<Object> custIndustry = root.get("custIndustry");

                //1.构造客户的精准匹配查询
                Predicate n1 = cb.equal(custName, "测试");
                //2.构造所属行业的精准匹配查询
                Predicate n2 = cb.equal(custIndustry, "test");
                //3.将多个查询条件组合到一起
                Predicate and = cb.and(n1, n2);
                return and;
            }
        };
        Customer one = customerDao.findOne(specification);
        System.out.println("one = " + one);
    }

2.)多表之间的关系和操作多表的操作步骤

​ 一对多

​ 多对多

// 创建分页对象
PageRequest page = PageSort.pageRequest(Sort.Direction.ASC);
return employeeRepository.findAll(new Specification<Employee>() {

    @Override
    public Predicate toPredicate(Root<Employee> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder cd) {
        List<Predicate> employeeList = new ArrayList<>();
        if (employee.getName() != null) {
            employeeList.add(cd.equal(root.get("name").as(Long.class), employee.getName()));
        }
        if (employee.getStatus() != null) {
            employeeList.add(cd.equal(root.get("status").as(Byte.class), employee.getStatus()));
        }
        if (employee.getDept() != null) {
            Dept dept = employee.getDept();
            List<Long> deprIn = new ArrayList<>();
            deprIn.add(dept.getId());
            List<Dept> deptList = deptService.getListByPidLikeOk(dept.getId());
            deptList.forEach(item -> deprIn.add(item.getId()));

            Join<Employee, Dept> employeeDeptJoin = root.join("dept", JoinType.INNER);
            CriteriaBuilder.In<Long> in = cd.in(employeeDeptJoin.get("id").as(Long.class));
            deprIn.forEach(in::value);
            employeeList.add(in);
        }

        Predicate[] pres = new Predicate[employeeList.size()];
        return criteriaQuery.where(employeeList.toArray(pres)).getRestriction();
    }
}, page);