• spring data jpa 的简单使用


    先说简单一下JPA

    概念:JPA(Java Persistence API)是Sun官方提出的Java持久化规范。它为Java开发人员提供了一种对象/关联映射工具来管理Java应用中的关系数据。

    影响他的出现主要是为了简化现有的持久化开发工作和整合ORM技术,结束现在Hibernate,TopLink,JDO等ORM框架各自为营的局面

    好处:spring data jpa让我们解脱了DAO层的操作,基本上所有CRUD都可以依赖于它来实现

    进入正题

    Spring DATA JPA

      1、引入

     maven引入:

    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>

     gradle引入:

    compile('org.springframework.boot:spring-boot-starter-data-jpa')

      实现:创建一个接口继承下面的任何一个接口都可以

      3.1:Repository

      概述:仅仅是一个标识,表明任何继承它的均为仓库接口类,方便Spring自动扫描识别 。这个接口是最基础的接口,只是一个标志性的接口,没有定义任何的方法。

      它是最顶层的接口,是一个空接口,目的是为了统一所有的Repository的类型,且能让组件扫描的时候自动识别。

      好处:例如,我们有一部分方法是不想对外提供的,比如我们只想提供增加和修改方法,不提供删除方法,那么下面介绍的几个接口都是做不到的,这个时候,我们就可以继承这个接口,然后将CrudRepository接口里面相应的方法拷贝到Repository接口就可以了。

     3.2:CrudRepository

       概述:Repository的子接口,提供CRUD相关的方法 

     主要方法:

    保存
        <S extends T> S save(S entity);
    批量保存
        <S extends T> Iterable<S> save(Iterable<S> entities);
    根据id查询一个对象
        T findOne(ID id)
    判断对象是否存在
        boolean exists(ID id)
    查询所有的对象
        Iterable<T> findAll()
    根据id列表查询所有的对象
        Iterable<T> findAll(Iterable<ID> ids)
    计算对象的总个数
        long count()
    根据id删除
        void delete(ID id)
    删除对象
        void delete(T entity);
    批量删除
        void delete(Iterable<? extends T> entities);
    删除所有
        void deleteAll()

     3.3:PagingAndSortingRepository

      概述:CrudRepository的子接口,添加一组分页排序相关的方法 

    主要方法:

    不带分页的排序
        Iterable<T> findAll(Sort sort)
    带分页的排序
        Page<T> findAll(Pageable pageable)

     3.4:JpaRepository

      概述:PagingAndSortingRepository的子接口,增加一组JPA规范相关的方法 

     主要方法:

    查询所有对象,不排序
        List<T> findAll()
    查询所有对象,并排序
        List<T> findAll(Sort sort)
    批量保存
        <S extends T> List<S> save(Iterable<S> entities);
    强制缓存与数据库同步
        void flush()
    保存并强制同步
        T saveAndFlush(T entity)
    批量删除
        void deleteInBatch(Iterable<T> entities)
    删除所有
        void deleteAllInBatch();

        3.5:JpaSpecificationExecutor

          概述:这个比较特殊,不属于Repository体系,它实现一组JPA Criteria查询相关的方法,主要是用来做复杂的查询的接口(辅助接口)。

          注意事项:这个接口很特殊,不属于Repository体系,而Spring data JPA不会自动扫描识别,所以会报找不到对应的Bean,我们只需要继承任意一个继承了Repository的子接口或直接继承Repository接口,Spring data JPA就会自动扫描识别,进行统一的管理

      4、自定义方法:

      前提:实现上面的任何一个接口

      4.1:使用 @Query 创建查询

       4.1.1:用法

       @Query 注解的使用非常简单,只需在声明的方法上面标注该注解,同时提供一个 JP QL 查询语句即可

     例如:

    @Query("select u from User u where u.name = :name")
    User findUserByName(@Param("name") String name);

     4.1.2:参数

     4.1.2.1:命名参数

    描述:推荐使用这种方法,可以不用管参数的位置

    @Query("select u from User u where u.name = :name")
    User findUserByName(@Param("name") String name);

     4.1.2.2:索引参数

     描述:使用?占位符

    @Query("select u from User u where u.email = ?1")// 1表示第一个参数
    User findUserByEmail(String email);

     4.1.2.3: SPEL表达式(这里只是简单的写了一下,有兴趣可以去文档看一下)

       描述:从Spring Data JPA版本1.4开始,我们支持通过手动定义的查询来使用受限制的SpEL模板表达式@Query 

    @Query("select u from User u where u.name = :name")
    User findUserByName(@Param("name") String name);

      基于SpEL的查询模板中支持的变量

    变量
        entityName
    用法
        select x from #{#entityName} x
    描述
        插入entityName与给定存储库关联的域类型。该entityName解决如下:如果域类型已设置的name属性@Entity注解那么它将被使用。否则,将使用域类型的简单类名称。
    注意
        该entityName可以通过自定义@Entity的注释。orm.xmlSpEL表达式不支持自定义。
        引用#entityName将会把用户类的潜在的未来重映射转换成一个不同的实体名称(例如通过使用@Entity(name = "MyUser")

     4.1.3:分类 

       4.1.3.1:QUERY

     例如:

    @Query("select u from User u where u.name = :name")
    User findUserByName(@Param("name") String name);

     注意:

      1、使用@Query来指定本地查询,只要设置nativeQuery为true,比如:

    比如:
    @Query(value="select * from tbl_user where name like %?1" ,nativeQuery=true)
    public List<UserModel> findByUuidOrAge(String name);

      2、当前版本的本地查询不支持翻页和动态的排序

     分类(在Query中也分很多中查询)

      1、使用@Query在查询方法中声明查询

     @Query("select u from User u where u.emailAddress = ?1")
      User findByEmailAddress(String emailAddress);

      2、使用高级LIKE表达式

    @Query("select u from User u where u.firstname like %?1")
      List<User> findByFirstnameEndsWith(String firstname);

      3、使用@Query在查询方法中声明本地计数查询以进行分页

     @Query(value = "SELECT * FROM USERS WHERE LASTNAME = ?1",
        countQuery = "SELECT count(*) FROM USERS WHERE LASTNAME = ?1",
        nativeQuery = true)
      Page<User> findByLastname(String lastname, Pageable pageable);

     4.1.3.1:修改查询

      比如:

    @Modifying
    @Query(value="update UserModel o set o.name=:newName where o.name like %:nn")
    public int findByUuidOrAge(@Param("nn") String name,@Param("newName") String newName);

      注意:可以通过使用 @Query 来执行一个更新操作,为此,我们需要在使用 @Query 的同时,* 用 @Modifying 来将该操作标识为修改查询,这样框架最终会生成一个更新的操作,而非查询操作。

      

      4.2:@NamedQueries创建查询

      概念:命名查询是 JPA 提供的一种将查询语句从方法体中独立出来,以供多个方法共用的功能

      用法:用户只需要按照 JPA 规范在 orm.xml 文件或者在代码中使用 @NamedQuery(或 @NamedNativeQuery)定义好查询语句,唯一要做的就是为该语句命名时,需要满足”DomainClass.methodName()”的 命名规则

      比如:

    编写接口:
    public interface FindUserByNamedQueryRepository extends JpaRepository<User, Integer> {
    User findUserWithName(@Param("name") String name);
    }
    编写类:
    @Entity
    @NamedQueries(value={
    @NamedQuery(name="User.findUserWithName",query="select u from User u where u.name = :name")
    })
    以下是实体类
    ......

      注意:

      1、@NamedQuery中的name属性的值要和接口中的方法名称一样。

      2、此处如果是多个方法,那么需要使用@NamedQueries,如果只有一个方法,则可以使用@NamedQuery,写法如下:

    @NamedQuery(name="User.findUserWithName",query="select u from User u where u.name = :name")

      4.3:通过解析方法名创建查询

      概念:顾名思义,就是根据方法的名字,就能创建查询

      定义规则:

       说明:按照Spring data 定义的规则,查询方法以find|read|get开头涉及条件查询时,条件的属性用条件关键字连接,要注意的是:条件属性首字母需大写(参数名大写,条件名首字母大写,并且接口名中参数出现的顺序必须和参数列表中的参数顺序一致)

       例如:

    
    
    //参数名大写,条件名首字母大写,并且接口名中参数出现的顺序必须和参数列表中的参数顺序一致
    User findByNameAndEmail(String name, String email);  //相当于发送了一条SQL:select u from User u where u.name = :name and u.email = :email
      
    List<User> findByNameOrPassword(String name, String password);  //相当于发送了一条SQL:select u from User u where u.name = ?1 or u.password = ?2
    List<User> findByNameOrPassword(String name, String password);  //相当于发送了一条SQL:select u from User u where u.name = ?1 or u.password = ?2
    List<User> findByIdBetween(Integer start, Integer end);  //相当于发送了一条SQL:select u from User u where u.id between ?1 and ?2
    List<User> findByIdLessThan(Integer end);  //相当于发送了一条SQL:select u from User u where u.id < ?1 ...

      解析:框架在进行方法名解析时,会先把方法名多余的前缀截取掉,比如 find、findBy、read、readBy、get、getBy,然后对剩下部分进行解析。并且如果方法的最后一个参数是 Sort 或者 Pageable 类型,也会提取相关的信息,以便按规则进行排序或者分页查询。在创建查询时,我们通过在方法名中使用属性名称来表达,比如 findByIdIn()。框架在解析该方法时,首先剔除 findBy,然后对剩下的属性进行解析

       一些条件查询的关键字:

       

    框架在进行方法名解析时,会先把方法名多余的前缀截取掉,比如 find、findBy、read、readBy、get、getBy,然后对剩下部分进行解析。
    并且如果方法的最后一个参数是 Sort 或者 Pageable 类型,也会提取相关的信息,以便按规则进行排序或者分页查询。在创建查询时,我们通过在方法名中使用属性名称来表达
    ,比如 findByIdIn()。框架在解析该方法时,首先剔除 findBy,然后对剩下的属性进行解析
    And
    --- 等价于 SQL 中的 and 关键字,比如 findByUsernameAndPassword(String user, Striang pwd)
    Or
    --- 等价于 SQL 中的 or 关键字,比如 findByUsernameOrAddress(String user, String addr)
    Between
    --- 等价于 SQL 中的 between 关键字,比如 findBySalaryBetween(int max, int min)
    LessThan
    --- 等价于 SQL 中的 "<",比如 findBySalaryLessThan(int max)
    GreaterThan
    --- 等价于 SQL 中的">",比如 findBySalaryGreaterThan(int min)
    IsNull
    --- 等价于 SQL 中的 "is null",比如 findByUsernameIsNull()
    IsNotNull
    --- 等价于 SQL 中的 "is not null",比如 findByUsernameIsNotNull()
    NotNull
    --- 与 IsNotNull 等价
    Like
    --- 等价于 SQL 中的 "like",比如 findByUsernameLike(String user)
    NotLike
    --- 等价于 SQL 中的 "not like",比如 findByUsernameNotLike(String user)
    OrderBy
    ---等价于 SQL 中的 "order by",比如 findByUsernameOrderBySalaryAsc(String user)
    Not
    --- 等价于 SQL 中的 "! =",比如 findByUsernameNot(String user)
    In
    --- 等价于 SQL 中的 "in",比如 findByUsernameIn(Collection<String> userList) ,方法的参数可以是 Collection 类型,也可以是数组或者不定长参数
    NotIn
    --- 等价于 SQL 中的 "not in",比如 findByUsernameNotIn(Collection<String> userList) ,方法的参数可以是 Collection 类型,也可以是数组或者不定长参数
  • 相关阅读:
    Java多线程(二)关于多线程的CPU密集型和IO密集型这件事
    Java 过一下基础
    日历打印用java实现
    DAY8-打卡第八天-2018-1-18
    web-day1-初识标识符
    DAY7-图形界面第一弹-2018-1-17
    四种排序方法用java实现
    DAY6-小变化(java提示框)-2018-1-16
    DAY5-小别-2018-1-15
    DAY4-打卡第四天-2018-1-12
  • 原文地址:https://www.cnblogs.com/xiluonanfeng/p/9640490.html
Copyright © 2020-2023  润新知