集成SpringDataJpa

课程介绍                                 
1.什么是SpringDataJpa
2.SpringDataJpa的基本使用(掌握)
3.JpaSpecificationExecutor(难点,尽量理解)
4.jpa-spac框架
5.Query的抽取(思想)
6.SpringDataJpa的自定义扩展(拷备完成)
 

sssdj:SpringMVC + Spring + SpringDataJpa

-> 现在比较流行的一种设计(Spring全家桶)

从明天开始有很多代码可以是拷备:

难(可以尝试) 2.拷(自己去网上找) 3.学(如果你以前没掌握好,还是写一下)
SpringDataJpa(EASY)
创建项目
咱们可以根据昨天的方式使用IDEA创建一个PSS项目【大家可以去参见之前的文档】

集成Spring+SpringDataJpa
咱们要集成三大框架(Spring+SpringMVC+SpringDataJpa)

 

引入项目中所需要的所有包(pom.xml)
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">

  <modelVersion>4.0.0</modelVersion>

 

  <groupId>cn.itsource</groupId>

  <artifactId>yxb</artifactId>

  <version>1.0-SNAPSHOT</version>

 

  <properties>

    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

    <org.springframework.version>4.2.5.RELEASE</org.springframework.version>

    <org.hibernate.version>4.3.8.Final</org.hibernate.version>

    <spring-data-jpa.version>1.9.0.RELEASE</spring-data-jpa.version>

    <com.fasterxml.jackson.version>2.5.0</com.fasterxml.jackson.version>

    <org.slf4j.version>1.6.1</org.slf4j.version>

  </properties>

  <dependencies>

    <!-- Spring的支持包 -->

    <dependency>

      <groupId>org.springframework</groupId>

      <artifactId>spring-core</artifactId>

      <version>${org.springframework.version}</version>

    </dependency>

    <dependency>

      <groupId>org.springframework</groupId>

      <artifactId>spring-context</artifactId>

      <version>${org.springframework.version}</version>

    </dependency>

    <dependency>

      <groupId>org.springframework</groupId>

      <artifactId>spring-context-support</artifactId>

      <version>${org.springframework.version}</version>

    </dependency>

 

    <dependency>

      <groupId>org.springframework</groupId>

      <artifactId>spring-tx</artifactId>

      <version>${org.springframework.version}</version>

    </dependency>

    <dependency>

      <groupId>org.springframework</groupId>

      <artifactId>spring-jdbc</artifactId>

      <version>${org.springframework.version}</version>

    </dependency>

    <dependency>

      <groupId>org.springframework</groupId>

      <artifactId>spring-orm</artifactId>

      <version>${org.springframework.version}</version>

    </dependency>

    <dependency>

      <groupId>org.springframework</groupId>

      <artifactId>spring-aop</artifactId>

      <version>${org.springframework.version}</version>

    </dependency>

    <dependency>

      <groupId>org.springframework</groupId>

      <artifactId>spring-test</artifactId>

      <version>${org.springframework.version}</version>

      <scope>test</scope>

    </dependency>

    <!-- 引入web前端的支持 -->

    <dependency>

      <groupId>org.springframework</groupId>

      <artifactId>spring-web</artifactId>

      <version>${org.springframework.version}</version>

    </dependency>

    <dependency>

      <groupId>org.springframework</groupId>

      <artifactId>spring-webmvc</artifactId>

      <version>${org.springframework.version}</version>

    </dependency>

    <!-- SpringMCV上传需要用到io包-->

    <dependency>

      <groupId>org.apache.commons</groupId>

      <artifactId>commons-io</artifactId>

      <version>1.3.2</version>

    </dependency>

    <!-- 文件上传用到的包 -->

    <dependency>

      <groupId>commons-fileupload</groupId>

      <artifactId>commons-fileupload</artifactId>

      <version>1.2.2</version>

    </dependency>

    <!-- SpringMVC的json支持包 -->

    <dependency>

      <groupId>com.fasterxml.jackson.core</groupId>

      <artifactId>jackson-core</artifactId>

      <version>${com.fasterxml.jackson.version}</version>

    </dependency>

    <dependency>

      <groupId>com.fasterxml.jackson.core</groupId>

      <artifactId>jackson-annotations</artifactId>

      <version>${com.fasterxml.jackson.version}</version>

    </dependency>

    <dependency>

      <groupId>com.fasterxml.jackson.core</groupId>

      <artifactId>jackson-databind</artifactId>

      <version>${com.fasterxml.jackson.version}</version>

    </dependency>

    <!-- hibernate的支持包 -->

    <dependency>

      <groupId>org.hibernate</groupId>

      <artifactId>hibernate-core</artifactId>

      <version>${org.hibernate.version}</version>

    </dependency>

    <dependency>

      <groupId>org.hibernate</groupId>

      <artifactId>hibernate-entitymanager</artifactId>

      <version>${org.hibernate.version}</version>

    </dependency>

    <!-- SpringData的支持包 -->

    <dependency>

      <groupId>org.springframework.data</groupId>

      <artifactId>spring-data-jpa</artifactId>

      <version>${spring-data-jpa.version}</version>

    </dependency>

    <!-- SpringData的擴展包 -->

    <dependency>

      <groupId>com.github.wenhao</groupId>

      <artifactId>jpa-spec</artifactId>

      <version>3.1.1</version>

      <!-- 把所有的依賴都去掉 -->

      <exclusions>

        <exclusion>

          <groupId>*</groupId>

          <artifactId>*</artifactId>

        </exclusion>

      </exclusions>

    </dependency>

 

    <dependency>

      <groupId>commons-dbcp</groupId>

      <artifactId>commons-dbcp</artifactId>

      <version>1.2.2</version>

    </dependency>

 

    <dependency>

      <groupId>mysql</groupId>

      <artifactId>mysql-connector-java</artifactId>

      <version>5.1.6</version>

    </dependency>

 

    <dependency>

      <groupId>org.apache.commons</groupId>

      <artifactId>commons-lang3</artifactId>

      <version>3.5</version>

    </dependency>

    <!-- 測試包 -->

    <dependency>

      <groupId>junit</groupId>

      <artifactId>junit</artifactId>

      <version>4.12</version>

      <scope>test</scope>

    </dependency>

    <dependency>

      <groupId>javax.servlet</groupId>

      <artifactId>javax.servlet-api</artifactId>

      <version>3.1.0</version>

      <!-- 这个scope 只能作用在编译和测试时,同时没有传递性。表示在运行的时候不添加此jar文件 -->

      <scope>provided</scope>

    </dependency>

    <!-- 日志文件 -->

    <dependency>

      <groupId>org.slf4j</groupId>

      <artifactId>slf4j-api</artifactId>

      <version>${org.slf4j.version}</version>

    </dependency>

    <dependency>

      <groupId>org.slf4j</groupId>

      <artifactId>slf4j-log4j12</artifactId>

      <version>${org.slf4j.version}</version>

      <scope>runtime</scope>

    </dependency>

    <dependency>

      <groupId>log4j</groupId>

      <artifactId>log4j</artifactId>

      <version>1.2.14</version>

    </dependency>

    <!-- 代码生成器模版技术 -->

    <dependency>

      <groupId>org.apache.velocity</groupId>

      <artifactId>velocity</artifactId>

      <version>1.6</version>

    </dependency>

  <!-- shiro的支持包 -->

   <dependency>

      <groupId>org.apache.shiro</groupId>

      <artifactId>shiro-all</artifactId>

      <version>1.4.0</version>

      <type>pom</type>

  </dependency>

    <!-- shiro与Spring的集成包 -->

    <dependency>

      <groupId>org.apache.shiro</groupId>

      <artifactId>shiro-spring</artifactId>

      <version>1.4.0</version>

    </dependency>

    <!-- poi支持的jar包 -->

    <dependency>

      <groupId>org.apache.poi</groupId>

      <artifactId>poi</artifactId>

      <version>3.11</version>

    </dependency>

    <dependency>

      <groupId>org.apache.poi</groupId>

      <artifactId>poi-ooxml</artifactId>

      <version>3.11</version>

    </dependency>

    <!-- 图片压缩功能 -->

    <!-- 缩略图 -->

    <dependency>

      <groupId>net.coobird</groupId>

      <artifactId>thumbnailator</artifactId>

      <version>0.4.6</version>

    </dependency>

    <!-- 定时调度 -->

    <dependency>

      <groupId>quartz</groupId>

      <artifactId>quartz</artifactId>

      <version>1.5.2</version>

    </dependency>

    <!-- 邮件支持 -->

    <dependency>

      <groupId>javax.mail</groupId>

      <artifactId>mail</artifactId>

      <version>1.4.1</version>

    </dependency>

  </dependencies>

 

  <build>

    <finalName>yxb</finalName>

    <plugins>

      <plugin>

        <groupId>org.apache.maven.plugins</groupId>

        <artifactId>maven-compiler-plugin</artifactId>

        <configuration>

          <source>1.8</source>

          <target>1.8</target>

        </configuration>

      </plugin>

      <plugin>

        <groupId>org.mortbay.jetty</groupId>

        <artifactId>jetty-maven-plugin</artifactId>

        <version>8.1.15.v20140411</version>

        <configuration>

          <stopPort>9966</stopPort>

          <stopKey>foo</stopKey>

          <webAppConfig>

            <contextPath>/</contextPath>

          </webAppConfig>

        </configuration>

      </plugin>

    </plugins>

  </build>

</project>

 

注:如果配置完后没有自动导包,办法如下:

Settings > Maven > Importing > Import maven project automatically

 

配置applicationContext.xml文件
注意:修改相应的包扫描(每个系统都会有不一样的地方)

在这里我们加上了SpringDataJpa的配置(红色部分)

<?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:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:jpa="http://www.springframework.org/schema/data/jpa"
       xsi:schemaLocation="
         http://www.springframework.org/schema/beans
         http://www.springframework.org/schema/beans/spring-beans.xsd
         http://www.springframework.org/schema/context
         http://www.springframework.org/schema/context/spring-context.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">

    <!-- 扫描service部分的包 -->
    <context:component-scan base-package="cn.itsource.aisell.service" />
    <context:property-placeholder location="classpath:jdbc.properties" />

    <!-- 配置连接池 -->
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <!--连接数据4个属性 -->
        <property name="driverClassName" value="${jdbc.driverClassName}" />
        <property name="url" value="${jdbc.url}" />
        <property name="username" value="${jdbc.username}" />
        <property name="password" value="${jdbc.password}" />
        <!--maxActive: 最大连接数量 -->
        <property name="maxActive" value="150" />
        <!--minIdle: 最小空闲连接 -->
        <property name="minIdle" value="5" />
        <!--maxIdle: 最大空闲连接 -->
        <property name="maxIdle" value="20" />
        <!--initialSize: 初始化连接 -->
        <property name="initialSize" value="30" />
        <!-- 用来配置数据库断开后自动连接的 -->
        <!-- 连接被泄露时是否打印 -->
        <property name="logAbandoned" value="true" />
        <!--removeAbandoned: 是否自动回收超时连接 -->
        <property name="removeAbandoned" value="true" />
        <!--removeAbandonedTimeout: 超时时间(以秒数为单位) -->
        <property name="removeAbandonedTimeout" value="10" />
        <!--maxWait: 超时等待时间以毫秒为单位 1000等于60秒 -->
        <property name="maxWait" value="1000" />
        <!-- 在空闲连接回收器线程运行期间休眠的时间值,以毫秒为单位. -->
        <property name="timeBetweenEvictionRunsMillis" value="10000" />
        <!-- 在每次空闲连接回收器线程(如果有)运行时检查的连接数量 -->
        <property name="numTestsPerEvictionRun" value="10" />
        <!-- 1000 * 60 * 30 连接在池中保持空闲而不被空闲连接回收器线程 -->
        <property name="minEvictableIdleTimeMillis" value="10000" />
        <property name="validationQuery" value="SELECT NOW() FROM DUAL" />
    </bean>

    <!-- 集成hibernate的jpa功能 -->
    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <!--待扫描的实体类包,不再需要persistence.xml了 -->
        <property name="packagesToScan" value="cn.itsource.aisell.domain" />
        <!-- 3.配置JPA的实现 -->
        <!-- private JpaVendorAdapter jpaVendorAdapter; -->
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                <!-- org.springframework.orm.jpa.vendor.AbstractJpaVendorAdapter -->
                <!-- private boolean showSql = false;是否显示sql语句 -->
                <property name="showSql" value="true" />
                <!-- private boolean generateDdl = false;是否建表 -->
                <property name="generateDdl" value="false" />
                <!-- private String databasePlatform;原来方言 -->
                <property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect" />
            </bean>
        </property>
    </bean>

    <!-- Jpa 事务配置 -->
    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory" />
    </bean>
    <!-- 注解声明式事务管理 -->
    <tx:annotation-driven />

    <!-- Spring Data Jpa配置 ********************************************-->
    <!-- base-package:扫描的包 -->
    <jpa:repositories base-package="cn.itsource.pss.repository" transaction-manager-ref="transactionManager"
                      entity-manager-factory-ref="entityManagerFactory" />
</beans>

 

 

准备Domain
父类:BaseDomain

package cn.itsource.pss.domain;

import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;

@MappedSuperclass
// 在JPA里面就表示是父类,不持久化到表
public class BaseDomain {
    @Id
    @GeneratedValue
    protected Long id;
    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }
}

 

子类Employee

@Entity
@Table(name="employee")
public class Employee extends  BaseDomain {

    private String username;
    private String password;
    private String email;

    private Integer age;
   //省略getter,setter与toString(注意:Alt+Insert可以自动生成)
}

 

完成Repository的功能
package cn.itsource.pss.repository;

import cn.itsource.pss.domain.Employee;
import org.springframework.data.jpa.repository.JpaRepository;

/**
 * 必需继续JpaRepository<1v,2v>
 *     1v:代表你要操作的是哪一个domain对象
 *     2v:这个domain对象的主键的类型
 */
public interface EmployeeRepository extends JpaRepository<Employee, Long> {
}

 

测试集成是否成功
package cn.itsource.repository;

import cn.itsource.pss.domain.Employee;
...
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class EmployeeRepositoryTest  {
    @Autowired
    private EmployeeRepository employeeRepository;
    @Test
    public void testFind() throws Exception{
        List<Employee> emps = employeeRepository.findAll();
        for (Employee emp :emps){
            System.out.println(emp);
        }
    }
}

 

 

SpringDataJpa的认识与使用
ORM(对象关系映射)框架
MyBatis:Apache的一个开源项目(咱们第三个项目使用的框架),上手简单,开发灵活,现在市场占有率高; 但是开发时工作量比较大,需要做很多配置,并且自己要写SQL语句。

Hibernate:一个开放源代码的对象关系映射框架,是完全面向对象的。可以使用面向对象的思路来完成数据库操作。 Hibernate是完备的ORM框架(咱们之前学习JPA,底层就是使用Hibernate完成的)。

...

了解SpringDataJpa
它是JPA规范的再次封装抽象,底层还是使用了Hibernate的JPA技术实现,引用JPQL的查询语句 ,是属于Spring的生成体系中的一部分。

SpringDataJpa使用起来比较方便,加快了开发的效果,使开发人员不需要关心和配置更多的东西。

SpringDataJpa上手简单,开发效率高,对对象的支持非常好,还十分的灵活。

 

Spring Data项目是从2010年开发发展起来的,是一个用于简化数据库访问,并支持云服务的开源框架。其主要目标是使得对数据的访问变得方便快捷,并支持map-reduce框架和云计算数据服务。 Spring Data 包含多个子项目:

Commons - 提供共享的基础框架,适合各个子项目使用,支持跨数据库持久化

JPA - 简化创建 JPA 数据访问层和跨存储的持久层功能

Hadoop - 基于 Spring 的 Hadoop 作业配置和一个 POJO 编程模型的 MapReduce 作业

Key-Value  - 集成了 Redis 和 Riak ,提供多个常用场景下的简单封装

Document - 集成文档数据库:CouchDB 和 MongoDB 并提供基本的配置映射和资料库支持

Graph - 集成 Neo4j 提供强大的基于 POJO 的编程模型

Graph Roo AddOn - Roo support for Neo4j

JDBC Extensions - 支持 Oracle RAD、高级队列和高级数据类型

Mapping - 基于 Grails 的提供对象映射框架,支持不同的数据库

Examples - 示例程序、文档和图数据库

Guidance - 高级文档

 

SpringData的结构
Spring Data JPA的七个Repository接口:

Repository(org.springframework.data.repository.Repository)
CrudRepository(org.springframework.data.repository.CrudRepository)
PagingAndSortingRepository(org.springframework.data.repository.PagingAndSortingRepository)
JpaRepository (org.springframework.data.jpa.repository.JpaRepository)
QueryByExampleExecutor(org.springframework.data.repository.query.QueryByExampleExecutor)
JpaSpecificationExecutor (org.springframework.data.jpa.repository.JpaSpecificationExecutor)
QueryDslPredicateExecutor (org.springframework.data.querydsl.QueryDslPredicateExecutor)

 
两大Repository实现类:
SimpleJpaRepository(org.springframework.data.jpa.repository.support.SimpleJpaRepository)
QueryDslJpaRepository(org.springframework.data.jpa.repository.support.QueryDslJpaRepository)

 
结构图(通过Intellij Idea,打开SimpleJpaRepository.java,单击鼠标右键show diagrams,就可以用图表的式打开与查询类的关系层次图):

 

在这里咱们直接用的是JpaRepository这个接口,那么它又继承了PagingAndSortingRepository和CrudRepository两个接口,我们现在就来研究一下这三个接口提供了哪些功能:

 

CrudRepository:完成所有基本的增删改查的方法

其中T是要操作的实体类,ID是实体类主键的类型。该接口提供了11个常用操作方法。


package org.springframework.data.repository;
import java.io.Serializable;
@NoRepositoryBean
public interface CrudRepository<T, ID extends Serializable> extends Repository<T, ID> {

   <S extends T> S save(S entity);
   <S extends T> Iterable<S> save(Iterable<S> entities);
   T findOne(ID id);
   boolean exists(ID id);
   Iterable<T> findAll();
   Iterable<T> findAll(Iterable<ID> ids);
   long count();
   void delete(ID id);
   void delete(T entity);
   void delete(Iterable<? extends T> entities);
   void deleteAll();
}

 

PagingAndSortingRepository:完成分页与排序功能

该接口继承了CrudRepository接口,提供了两个方法,实现了分页和排序的功能了。

package org.springframework.data.repository;

import java.io.Serializable;

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

@NoRepositoryBean
public interface PagingAndSortingRepository<T, ID extends Serializable> extends CrudRepository<T, ID> {
   Iterable<T> findAll(Sort sort);
   Page<T> findAll(Pageable pageable);
}

 

JpaRepository:

该接口继承了PagingAndSortingRepository接口。

package org.springframework.data.jpa.repository;

import java.io.Serializable;
import java.util.List;

import javax.persistence.EntityManager;

import org.springframework.data.domain.Sort;
import org.springframework.data.repository.NoRepositoryBean;
import org.springframework.data.repository.PagingAndSortingRepository;

/**
 * JPA specific extension of {@link org.springframework.data.repository.Repository}.
 *
 * @author Oliver Gierke
 */
@NoRepositoryBean
public interface JpaRepository<T, ID extends Serializable> extends PagingAndSortingRepository<T, ID> {

   List<T> findAll();
   List<T> findAll(Sort sort);
   List<T> findAll(Iterable<ID> ids);
   <S extends T> List<S> save(Iterable<S> entities);
   void flush();
   <S extends T> S saveAndFlush(S entity);
   void deleteInBatch(Iterable<T> entities);
   void deleteAllInBatch();
   T getOne(ID id);
}

 

 

 

注意与说明:

几个查询、及批量保存方法,和 CrudRepository 接口相比,返回的是 List,使用起来更方便。
增加了 InBatch 删除, 实际执行时,后台生成一条sql语句,效率更高些。相比较而言,CrudRepository 接口的删除方法,都是一条一条删除的,即便是 deleteAll 也是一条一条删除的。
增加了 getOne() 方法,切记,该方法返回的是对象引用,当查询的对象不存在时,它的值不是Null。
JpaRepository的基本功能
了解整体结构后,大家应该很清楚了,咱们这里的JpaRepository接口完成了很多重要的相应的功能。现在我们就来测试一下这些功能(项目已经搭建好,现在可以直接进行测试)

 

普通的CRUD
//获取所有数据
@Test
public void testFindAll() throws Exception{
    List<Employee> emps = employeeRepository.findAll();
    for (Employee emp :emps){
        System.out.println(emp);
    }
}
//根据id到一条数据
@Test
public void testFindOne() throws Exception{
    Employee employee = employeeRepository.findOne(1L);
    System.out.println(employee);
}

//添加与修改都使用save(主要看对象有没有id)
@Test
public void testSave() throws Exception{
    Employee employee = new Employee();
    //employee.setId(103L);
    employee.setUsername("张三");
    employee.setPassword("1234");
    employee.setEmail("zhangsha@163.com");
    employeeRepository.save(employee);
}
//删除数据
@Test
public void testDelete() throws Exception{
    employeeRepository.delete(103L);
}
//得到总条数
@Test
public void testCount(){
    System.out.println(employeeRepository.count());
}

 

分页排序功能
//进行分页功能
@Test
public void testPage() {
    //1.需要先创建一个page对象(注意:页数是从0开始计算【0就是第1页】)
    Pageable pageable = new PageRequest(0, 10);
    //2.进行查询
    Page<Employee> page = employeeRepository.findAll(pageable);
    System.out.println(page.getTotalElements()); //总条数
    System.out.println(page.getTotalPages()); //总页数
    System.out.println(page.getContent()); //当前页数据
    System.out.println(page.getNumber()); //第几页
    System.out.println(page.getNumberOfElements()); //当前页有多少个数据
    System.out.println(page.getSize()); //每页条数
}

//进行排序功能
@Test
public void testSort() {
    //排序 :第一个参数是排序的规则(DESC/ASC)  后面参数是排序的字符
    Sort sort = new Sort(Sort.Direction.DESC,"username");
    List<Employee> emps = employeeRepository.findAll(sort);
    for (Employee emp : emps) {
        System.out.println(emp);
    }
}

//分页与排序的集成
@Test
public void testPageAndSort() {
    //排序 :第一个参数是排序的规则(DESC/ASC)  后面参数是排序的字符
    Sort sort = new Sort(Sort.Direction.DESC,"username");
    Pageable pageable = new PageRequest(0, 10,sort);
    //2.进行查询
    Page<Employee> page = employeeRepository.findAll(pageable);
    for (Employee employee : page) {
        System.out.println(employee);
    }
}

 

根据条件进行查询(了解)
    按照规范创建查询方法,一般按照java驼峰式书写规范加一些特定关键字,例如我们想通过员工的名来获取到对应的员工的对象。

public interface EmployeeRepository extends JpaRepository<Employee, Long> {
    //根据名称模糊查询
    List<Employee> findByUsernameLike(String username);
    //根据名称进行查询
    List<Employee> findByUsername(String username);
}

 

规则如下:

表达式

例子

hql查询语句

And

findByLastnameAndFirstname

… where x.lastname = ?1 and x.firstname = ?2

Or

findByLastnameOrFirstname

… where x.lastname = ?1 or x.firstname = ?2

Is,Equals

findByFirstname,findByFirstnameIs,findByFirstnameEqual

… where x.firstname = 1?

Between

findByStartDateBetween

… where x.startDate between 1? and ?2

LessThan(lt)

findByAgeLessThan

… where x.age < ?1

LessThanEqual(le)

findByAgeLessThanEqual

… where x.age <= ?1

GreaterThan

findByAgeGreaterThan

… where x.age > ?1

GreaterThanEqual

findByAgeGreaterThanEqual

… where x.age >= ?1

After

findByStartDateAfter

… where x.startDate > ?1

Before

findByStartDateBefore

… where x.startDate < ?1

IsNull

findByAgeIsNull

… where x.age is null

IsNotNull,NotNull

findByAge(Is)NotNull

… where x.age not null

Like

findByFirstnameLike

… where x.firstname like ?1

NotLike

findByFirstnameNotLike

… where x.firstname not like ?1

StartingWith

findByFirstnameStartingWith

… where x.firstname like ?1 (parameter bound with appended %)

EndingWith

findByFirstnameEndingWith

… where x.firstname like ?1 (parameter bound with prepended %)

Containing

findByFirstnameContaining

… where x.firstname like ?1 (parameter bound wrapped in %)

OrderBy

findByAgeOrderByLastnameDesc

… where x.age = ?1 order by x.lastname desc

Not

findByLastnameNot

… where x.lastname <> ?1

In

findByAgeIn(Collection ages)

… where x.age in ?1

NotIn

findByAgeNotIn(Collection age)

… where x.age not in ?1

True

findByActiveTrue()

… where x.active = true

False

findByActiveFalse()

… where x.active = false

IgnoreCase

findByFirstnameIgnoreCase

… where UPPER(x.firstame) = UPPER(?1)

 

这种方案看起来有意思,但是功能它都只针对简单的单表查询(而且如果条件太多,这个名称还是比较麻烦),如果遇到复杂的查询,还有方案就显得力不从心了。

@Query注解查询
在Respository方法中一定要按照查询方法的命名规则,其实是比较麻烦的如果我们想不遵循 查询方法的命名规则,还可以使用@Query的方法进行查询。

只需要将@Query定义在Respository的方法之上即可。

 

案例一:拿到一个员工(它的Id是所有员工最大的)

@Query("select o from cn.itsource.pss.domain.Employee o where o.id=(select max(id) from cn.itsource.pss.domain.Employee e)")
Employee query01();

 

案例二:根据用户名和密码拿到相应的员工

根据参数顺序

@Query("select o from cn.itsource.pss.domain.Employee o where  o.username like ?1 and o.email like ?2")
List<Employee> query02(String username,String email);
 

根据参数名称
@Query("select o from cn.itsource.pss.domain.Employee o where  o.username like :username and o.email like :email")
List<Employee> query03(@Param("username") String username,@Param("email")  String email);

 

案例三:查询总条数(原生sql查询)

@Query(value="SELECT COUNT(*) FROM employee",nativeQuery = true)
Long queryCount();

 

Query的注解注入非常灵活,在开发中也经常使用到(只是写JPQL/SQL有点麻烦)。

 

JpaSpecification[Office1] Executor[Office2] 的认识
Specification:[ˌspɛsəfɪˈkeʃən]

Executor:[ɪgˈzekjətə(r)]

Criteria:美 [kraɪˈtɪrɪə]

JpaSpecificationExecutor(JPA规则执行者)是JPA2.0提供的Criteria [Office3] API的使用封装,可以用于动态生成Query来满足我们业务中的各种复杂场景。

Spring Data JPA为我们提供了JpaSpecificationExecutor接口,只要简单实现toPredicate方法就可以实现复杂的查询。

 

咱们先来看一下这个接口的方法(大家注意一下,所以查询都要求传入一个Specification对象):

SimpleJpaRepository也实现了这个接口

package org.springframework.data.jpa.repository;

import java.util.List;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;

public interface JpaSpecificationExecutor<T> {
   T findOne(Specification<T> spec);
   List<T> findAll(Specification<T> spec);
   Page<T> findAll(Specification<T> spec, Pageable pageable);
   List<T> findAll(Specification<T> spec, Sort sort);
   long count(Specification<T> spec);
}

 

我们要使用这个接口中的方法,首先让我们的接口也去继承这个接口

public interface EmployeeRepository extends JpaRepository<Employee,Long>,JpaSpecificationExecutor<Employee> {

 

单个条件的查询
@Test
public void testFind() {
    /**

*官方解释:
     * Root<T> root:代表了可以查询和操作的实体对象的根,
     *              可以通过它的 Path<Y> get(String attributeName); 这个方法拿到我们要操作的字段
     *              注意:只可以拿到对应的T的字段(Employee)
     * CriteriaQuery<?> query:代表一个specific的顶层查询对象
     *              包含查询的各个部分,比如select,from,where,group by ,order by 等
     *              简单理解 就是它提供 了查询ROOT的方法(where,select,having)
     * CriteriaBuilder cb:用来构建CriteriaQuery的构建器对象(相当于条件或者说条件组合)
     *              构造好后以Predicate的形式返回
     */

/**

* 非官方理解:
 * 查询的时候就需要给一个标准(规范)
 *  -》 根据规范(这个规范我们可以先简单理解为查询的条件)进行查询
 *
 *      Root:查询哪个表(定位到表和字段-> 用于拿到表中的字段)
 *            可以查询和操作的实体的根
 *              Root接口:代表Criteria查询的根对象,Criteria查询的查询根定义了实体类型,能为将来导航获得想要的结果,它与SQL查询中的FROM子句类似
 *             Root<Employee> 相当于 from Employee
 *             Root<Product> 相当于  from Product
 *      CriteriaQuery:查询哪些字段,排序是什么(主要是把多个查询的条件连系起来)
 *      CriteriaBuilder:字段之间是什么关系,如何生成一个查询条件,每一个查询条件都是什么方式
 *                      主要判断关系(和这个字段是相等,大于,小于like等)
 *      Predicate(Expression):单独每一条查询条件的详细描述 整个 where xxx=xx and yyy=yy ...
 */
    List<Employee> emps = employeeRepository.findAll(
            new Specification<Employee>() {
                @Override
                public Predicate toPredicate(Root<Employee> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                    Path path = root.get("username");//拿到要做查询的字段
                    Predicate p = cb.like(path, "%1%");//like代表做模糊查询,后面就是它的条件值
                    return p;
                }
            }
    );
    for (Employee emp : emps) {
        System.out.println(emp);
    }
}

 

多个条件查询
@Test
public void testFind02() {
    Specification spec = new Specification<Employee>() {
        @Override
        public Predicate toPredicate(Root root, CriteriaQuery query, CriteriaBuilder cb) {
            //加上第一个条件: username like '%1%'
            Path path1 = root.get("username");
            Predicate p1 = cb.like(path1, "%1%");
            //加上第二个条件: email like '%2%'
            Path path2 = root.get("email");
            Predicate p2 = cb.like(path2,"%2%");
            //加上第二个条件: age < 20
            Path path3 = root.get("age");
            Predicate p3 = cb.lt(path3, 20);

           //下面是加上or的条件的方案
           //Predicate p3 = cb.or(p1,p2);

            //把两个查询条件放到query对象中去(条件使用where)
            CriteriaQuery where = query.where(p1, p2, p3);
            //返回查询条件
            return where.getRestriction();
        }
    };

    List<Employee> emps = employeeRepository.findAll(spec);
    for (Employee emp : emps) {
        System.out.println(emp);
    }

}

 

条件查询+分页排序
@Test
public void testFind03() {
    Specification spec = new Specification<Employee>() {
        @Override
        public Predicate toPredicate(Root root, CriteriaQuery query, CriteriaBuilder cb) {
            //加上条件: username like '%1%'
            Path path1 = root.get("username");
            Predicate p1 = cb.and(cb.like(path1, "%1%"));
            //把两个查询条件放到query对象中去(条件使用where)
            CriteriaQuery where = query.where(p1);
            //返回查询条件
            return where.getRestriction();
        }
    };

    //排序 :第一个参数是排序的规则(DESC/ASC)  后面参数是排序的字符
    Sort sort = new Sort(Sort.Direction.DESC,"username");
    Pageable pageable = new PageRequest(0, 10,sort);

    Page<Employee> page = employeeRepository.findAll(spec, pageable);
    for (Employee emp : page) {
        System.out.println(emp);
    }
}

 

JpaSpecificationExecutor咱们已经学完了,功能也是非常强大的,可以让我们不写一句SQL即可完成相应的查询功能。在外面也很不少公司使用这种方法,然后直接可以进行功能的抽取。

不过这个方案在设计上理解不是很容易,而且代码还比较臃肿烦杂(如果写得多习惯了还好)。

 

jpa-spec插件
这是一个对于咱们刚才的动态生成Query功能的一个封装版,如果我们使用这个插件,在完成查询与分页的时候功能会简单不少。

基于Spring Data Jpa的动态查询库 https://github.com/wenhao/jpa-spec

功能介绍
兼容Spring Data Jpa 和JPA2.1接口。
Equal/NotEqual/Like/NotLike/In/NotIn支持可变参数, Equal/NotEqual 支持空(Null)值。
每个条件支持关联查询。
支持自定义条件查询。
条件构建器。
支持分页和排序。
 

在Maven中引入相应的包
pom.xml(咱们项目中已经引入):

<!--  jpa的SpecificationSpecification功能封装 -->
<dependency>
  <groupId>com.github.wenhao</groupId>
  <artifactId>jpa-spec</artifactId>
  <version>3.1.1</version>
  <!-- 把所有依赖都过滤 -->
  <exclusions>
    <exclusion>
      <groupId>*</groupId>
      <artifactId>*</artifactId>
    </exclusion>
  </exclusions>
</dependency>

 

功能测试
单个条件查询
@Test
public void testSpecFind01() {
    Specification<Employee> spec = Specifications.<Employee>and().like("username", "%1%").build();
    List<Employee> emps = employeeRepository.findAll(spec);
    for (Employee emp : emps) {
        System.out.println(emp);
    }
}

 

多个条件查询
@Test
public void testSpecFind02() {
    Specification<Employee> spec = Specifications.<Employee>and().like("username", "%1%")
            .like("email","%2%").lt("age", 20).build();
    List<Employee> emps = employeeRepository.findAll(spec);
    for (Employee emp : emps) {
        System.out.println(emp);
    }
}

 

条件+排序分页功能
//条件集成+分页
@Test
public void testSpecFind03() {
    Specification<Employee> spec = Specifications.<Employee>and().like("username", "%1%").build();
    //排序 :第一个参数是排序的规则(DESC/ASC)  后面参数是排序的字符
    Sort sort = new Sort(Sort.Direction.DESC,"username");
    Pageable pageable = new PageRequest(0, 10,sort);

    Page<Employee> page = employeeRepository.findAll(spec, pageable);
    for (Employee emp : page) {
        System.out.println(emp);
    }
}

 

Jpa-spec的功能还是比较简单实用的。其它一些功能,我们在项目用到再说相应的讲解。大家也可以去参照网络上相就的中文文档:

https://github.com/wenhao/jpa-spec/blob/master/docs/3.1.0_cn.md

https://www.w3cschool.cn/jpaspec/

 

Query查询条件
咱们每一个项目是做过高级查询与分页的,大家应该都清楚,查询的数据是从前端由客户输入(或者选择)传到后台的。那么,我们需要注意的情况有哪些呢?

1 用户传的数据有0-n个(我们需要去判断)

2 咱们必需要准备一个对象接收用户传过来的数据(使用Query对象)

3 分页的条件对我们来说也是封装到Query对象中的

接下来,我们要准备我们的Query对象:

 

BaseQuery:公共的分页条件
package cn.itsource.pss.query;
/**
 * 公共的条件与规范
 */
public abstract class BaseQuery {

    //当前页(从1开始)
    private int currentPage = 1;
    //每页条数
    private int pageSize = 10;

    //排序方式 ASC/DESC
    private String orderByType ="ASC";
    //排序字段
    private String orderByName;

    public int getCurrentPage() {
        return currentPage;
    }
    /**
     * 专门准备的方法,因为前台用户传的是从第1页开始,而我们后台分页又是从0开的
     * @return
     */
    public int getJpaPage() {
        return currentPage - 1;
    }

    public void setCurrentPage(int currentPage) {
        this.currentPage = currentPage;
    }
    public int getPageSize() {
        return pageSize;
    }

    public void setPageSize(int pageSize) {
        this.pageSize = pageSize;
    }
    public String getOrderByType() {
        return orderByType;
    }

    public void setOrderByType(String orderByType) {
        this.orderByType = orderByType;
    }

    public String getOrderByName() {
        return orderByName;
    }

    public void setOrderByName(String orderByName) {
        this.orderByName = orderByName;
    }
}

 

EmployeeQuery:Employee特有的一些条件
package cn.itsource.pss.query;

public class EmployeeQuery extends BaseQuery {

    private String username;//姓名
    private String email;//邮件
    private Integer age;//年龄

    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getEmail() {
        return email;
    }
    public void setEmail(String email) {
        this.email = email;
    }
    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
}

 

功能测试
//根据Query对象进行查询
@Test
public void testSpecFindByQuery() {
    //创建模块一个Query对象
    EmployeeQuery baseQuery = new EmployeeQuery();

//下面的都是测试的条件,可以任何放开进行测试
    //baseQuery.setUsername("1");
    //baseQuery.setAge(20);
    //baseQuery.setEmail("2");
    //baseQuery.setOrderByName("username");
    //baseQuery.setOrderByType("DESC");
    //baseQuery.setCurrentPage(2);
    //baseQuery.setPageSize(5);

         //like(条件boolean值,字段,值)
    Specification<Employee> spec = Specifications.<Employee>and()
            .like(StringUtils.isNotBlank(baseQuery.getUsername()), "username","%"+baseQuery.getUsername()+"%")
            .like(StringUtils.isNotBlank(baseQuery.getEmail()), "email","%"+baseQuery.getEmail()+"%")
            .lt(baseQuery.getAge()!=null, "age",baseQuery.getAge())
            .build();


    //这里确定是否需要排序
    Sort sort = null;
    if(baseQuery.getOrderByName()!=null){
        Sort.Direction desc = "DESC".equals(baseQuery.getOrderByType())?Sort.Direction.DESC:Sort.Direction.ASC;
        sort = new Sort(desc,baseQuery.getOrderByName());
    }
    Pageable pageable = new PageRequest(baseQuery.getJpaPage(), baseQuery.getPageSize(),sort);

    Page<Employee> page = employeeRepository.findAll(spec, pageable);
    for (Employee emp : page) {
        System.out.println(emp);
    }
}

 

通过上面的功能测试,我们已经知道如果前台传数据过来,后面的查询应该怎么处理了。但是大家也应该发现了,除了创建Specification对象这一,分页排序的部分每次查询的代码都应该是一样的,所以我们现在需要做的就是把代码开始进行功能抽取。

 

6.4 创建Specification的流程放到Query里
BaseQuery中添加抽象方法

public abstract class BaseQuery {

...

//拿到查询的条件对象(由子类实现)

         public abstract Specification createSpecification();

//拿到排序的数据
         public Sort createSort() {
             Sort sort = null;
             if (StringUtils.isNotBlank(orderByName)) {
                    Sort.Direction type=  "ASC".equals(orderByType.toUpperCase())? Sort.Direction.ASC:Sort.Direction.DESC;
                      sort = new Sort(type,orderByName);
             }
             return sort;
         }

...

}

 

EmployeeQuery中实现相应方法

(以后每一个Query要做高级查询都写在这个位置)

public class EmployeeQuery extends BaseQuery {

    ...

@Override
         public Specification createSpecification() {
    //根据条件把数据返回即可
      return  Specifications.<Employee>and()
            .like(StringUtils.isNotBlank(username), "username","%"+username+"%")
            .like(StringUtils.isNotBlank(email), "email","%"+email+"%")
            .lt(age!=null, "age",age)
            .build();
         }

...

}

 

Spring Data Jpa扩展(非常难)
Spring Data Jpa功能虽然已经非常强大,但是它依然满足不了咱们的需要,在很多时候,我们需要自己去对SpringDataJpa的功能进行相应的扩展(即:自定义Repository)。

注:扩展部分的代码现在对大家来说难度太大,我们直接拷备过来使用即可(能看懂尽量把它看懂,如果实在看不懂,最少要先把这个代码用起来)

BaseRepository接口
 直接创建BaseRepository来继承JpaRepository接口

package cn.itsource.pss.repository;

import cn.itsource.pss.query.BaseQuery;
import org.springframework.data.domain.Page;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.repository.NoRepositoryBean;

import java.io.Serializable;
import java.util.List;

/**
 * 自定义一个Repository,它是JpaRepository的功能基础上继承增强
 * 在上面添加@NoRepositoryBean标注,这样Spring Data Jpa在启动时就不会去实例化BaseRepository这个接口
 * @param <T>
 * @param <ID>
 */
@NoRepositoryBean
public interface BaseRepository<T,ID extends Serializable> extends JpaRepository<T,ID>,JpaSpecificationExecutor<T>{
    //根据Query拿到分页对象(分页)
    Page findPageByQuery(BaseQuery baseQuery);

    //根据Query拿到对应的所有数据(不分页)
    List<T> findByQuery(BaseQuery baseQuery);

    //根据jpql与对应的参数拿到数据
    List findByJpql(String jpql,Object... values);
}

 

 

BaseRepositoryImpl功能实现
定义好自定义的方法后,我们现在通过一个基本的Repository类来实现该方法:

首先添加BaseRepositoryImpl类,继承SimpleJpaRepository类,使其拥有Jpa Repository的基本方法。

我们发现Repository有两个构造函数:

SimpleJpaRepository(JpaEntityInformation entityInformation, EntityManager entityManager)
SimpleJpaRepository(Class domainClass, EntityManager em)
这里我们实现第二个构造函数,拿到domainClass和EntityManager两个对象。

 

package cn.itsource.pss.repository;

import cn.itsource.pss.query.BaseQuery;
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 org.springframework.data.jpa.repository.support.SimpleJpaRepository;

import javax.persistence.EntityManager;
import javax.persistence.Query;
import java.io.Serializable;
import java.util.List;

/**
 * 实现父类中的三个方法
 * @param <T>
 * @param <ID>
 */
public class BaseRepositoryImpl<T,ID extends Serializable> extends SimpleJpaRepository<T,ID> implements BaseRepository<T,ID> {

    private final EntityManager entityManager;

    //必需要实现父类的这个构造器
    public BaseRepositoryImpl(Class<T> domainClass, EntityManager em) {
        super(domainClass, em);
        this.entityManager = em;
    }

    @Override
    public Page findPageByQuery(BaseQuery baseQuery) {
        //第一步:拿到所有高级查询条件
        Specification spec = baseQuery.createSpecification();
        //第二步:拿到排序的值
        Sort sort = baseQuery.createSort();
        //第三步:根据条件查询分页数据并且返回
        Pageable pageable = new PageRequest(baseQuery.getJpaPage(), baseQuery.getPageSize(),sort);
        Page<T> page = super.findAll(spec, pageable);
        return page;
    }

    @Override
    public List<T> findByQuery(BaseQuery baseQuery) {
        //第一步:拿到所有高级查询条件
        Specification spec = baseQuery.createSpecification();
        //第二步:拿到排序的值
        Sort sort = baseQuery.createSort();
        //第三步:拿到数据返回
        return findAll(spec, sort);
    }

    @Override
    public List findByJpql(String jpql, Object... values) {
        //第一步:创建Query对象
        Query query = entityManager.createQuery(jpql);
        //第二步:把值设置到Query对象中去
        if (values!=null) {
            for (int i = 0; i < values.length; i++) {
                query.setParameter(i + 1, values[i]);
            }
        }
        //第三步:返回数据
        return query.getResultList();
    }
}

 

 

创建自定义创建自定义RepositoryFactoryBean
接下来我们来创建一个自定义的RepositoryFactoryBean来代替默认的RepositoryFactoryBean。

RepositoryFactoryBean负责返回一个RepositoryFactory,Spring Data Jpa 将使用RepositoryFactory来创建Repository具体实现,这里我们用BaseRepositoryImpl代替SimpleJpaRepository作为Repository接口的实现。这样我们就能够达到为所有Repository添加自定义方法的目的。

我们需要覆写创建RepositoryFactory的方法:createRepositoryFactory

 

 
package cn.itsource.pss.repository;

import org.springframework.data.jpa.repository.support.JpaRepositoryFactory;
import org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
import org.springframework.data.repository.Repository;
import org.springframework.data.repository.core.RepositoryInformation;
import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.data.repository.core.support.RepositoryFactorySupport;

import javax.persistence.EntityManager;
import java.io.Serializable;

public class BaseRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extends Serializable> extends JpaRepositoryFactoryBean<T,S,ID> {

    @Override
    protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager) {
          return new MyRepositoryFactory<T,ID>(entityManager); //注:这里创建是我们的自定义类
    }

    //继承JpaRepositoryFactory后,把返回的对象修改成我们自己的实现
    private static  class MyRepositoryFactory<T,ID extends Serializable>   extends JpaRepositoryFactory{
        private final EntityManager entityManager;
        /**
         * Creates a new {@link JpaRepositoryFactory}.
         *
         * @param entityManager must not be {@literal null}
         */
        public MyRepositoryFactory(EntityManager entityManager) {
            super(entityManager);
            this.entityManager = entityManager;
        }
            //这里返回最后的功能对象
        @Override
        protected Object getTargetRepository(RepositoryInformation information) {
            return new BaseRepositoryImpl<T,ID>((Class<T>)information.getDomainType(),entityManager);
        }
            //确定功能对象的类型
        @Override
        protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
            return BaseRepositoryImpl.class;
        }
    }

}


 
功能完善
applicationContext.xml 中修改配置
<!-- Spring Data Jpa配置 ********************************************-->
<!-- base-package:扫描的包 -->
<jpa:repositories base-package="cn.itsource.pss.repository" transaction-manager-ref="transactionManager"
                  entity-manager-factory-ref="entityManagerFactory"
                  factory-class="cn.itsource.pss.repository.BaseRepositoryFactoryBean"
/>

 

继承BaseRepository
public interface EmployeeRepository extends BaseRepository<Employee,Long>{
}

 

 测试扩展功能
//测试分页查询
@Test
public void testFindPageByQuery() {
    EmployeeQuery baseQuery = new EmployeeQuery();
    baseQuery.setUsername("1");
    //baseQuery.setAge(20);
    //baseQuery.setEmail("2");
    baseQuery.setOrderByName("username");
    baseQuery.setOrderByType("DESC");
    //baseQuery.setCurrentPage(2);
    baseQuery.setPageSize(5);
    Page<Employee> page = employeeRepository.findPageByQuery(baseQuery);
    for (Employee employee : page) {
        System.out.println(employee);
    }
}

//测试单独查询
@Test
public void findByQuery() {
    EmployeeQuery baseQuery = new EmployeeQuery();
    baseQuery.setUsername("1");
    //baseQuery.setAge(20);
    //baseQuery.setEmail("2");
    baseQuery.setOrderByName("username");
    baseQuery.setOrderByType("DESC");
    List<Employee> emps = employeeRepository.findByQuery(baseQuery);
    for (Employee employee : emps) {
        System.out.println(employee);
    }
}

//测试自定义JPQL
@Test
public void findByJpql() {
    List<Employee> emps = employeeRepository.findByJpql("select o from Employee o where username = ? and password = ?","admin","admin");
    for (Employee emp : emps) {
        System.out.println(emp);
    }
}

 


规则,说明书的意思


执行者; 实行者


(批评、判断等的) 标准,准则( criterion的名词复数 )

Criteria 查询:是一种类型安全和更面向对象的查询 。


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值