首页>>后端>>Spring->【SpringData&JPA从入门到精通】02

【SpringData&JPA从入门到精通】02

时间:2023-11-30 本站 点击:1

笔记来源:尚硅谷SpringData教程(springdata经典,spring data快速上手)

@Query 与 @Modifying

1、@Query 注解

1.1、自定义查询

这种查询可以声明在 Repository 方法中,摆脱像命名查询那样的约束,将查询直接在相应的接口方法中声明,结构更为清晰,这是 Spring data 的特 有实现

@Query("SELECT C FROM Customer c WHERE c.customerId=?1")Customer testGetByCustomerId2(Integer id);

测试方法

PersonRepository 类

@Query("select p from Person p where p.id=(select max(id) from Person p)")Person getMaxIdPerson();

Test 类

@Testpublic void testGetMaxIdPerson() {    Person person = repository.getMaxIdPerson();    System.out.println(person);}

日志信息

Hibernate:     select        person0_.id as id1_1_,        person0_.add_id as add_id6_1_,        person0_.address_id as address_2_1_,        person0_.birth_day as birth_da3_1_,        person0_.email as email4_1_,        person0_.last_name as last_nam5_1_     from        jpa_persons person0_     where        person0_.id=(            select                max(person1_.id)             from                jpa_persons person1_        )Person{id=27, lastName='XY', email='XY@qq.com', birthDay=2022-05-21 22:48:34.0}

结论:使用 @Query 注解可以自定义 JPQL 语句以实现更灵活的查询

1.2、索引参数与命名参数

索引参数

索引参数如下所示,索引值从 1 开始,查询中 “?X” 个数需要与方法定义的参数个数相一致,并且顺序也要一致

@Modifying@Query("update User u set u.firstname=?1 where u.lastname=?2")int setFixedFirstnameFor(String firstname,String lastname);

命名参数

命名参数(推荐使用这种方式):可以定义好参数名,赋值时采用 @Param("参数名"),而不用管顺序

@Query("select cirom customer u where c.firstname=:firstname or c.lastname=:lastname")Customer findByLastnameOrFirstname(@Param("lastname") String lastname, @Param("firstname") String firstname);

测试方法 1

PersonRepository 类

@Query("select p from Person p where p.lastName=?1 and p.email=?2")Person getByLastNameAndEmail(String lastName, String email);

Test 类

@Testpublic void testGetByLastNameAndEmail() {    Person person = repository.getByLastNameAndEmail("AA", "AA@qq.com");    System.out.println(person);}

日志信息

Hibernate:     select        person0_.id as id1_1_,        person0_.add_id as add_id6_1_,        person0_.address_id as address_2_1_,        person0_.birth_day as birth_da3_1_,        person0_.email as email4_1_,        person0_.last_name as last_nam5_1_     from        jpa_persons person0_     where        person0_.last_name=?         and person0_.email=?Person{id=1, lastName='AA', email='AA@qq.com', birthDay=2022-05-21 22:48:34.0}

测试方法 2

PersonRepository 类

@Query("select p from Person p where p.lastName=:lastName and p.email=:email")Person getByEmailAndLastName(@Param("email") String email, @Param("lastName") String lastName);

Test 类

@Query("select p from Person p where p.id=(select max(id) from Person p)")Person getMaxIdPerson();0

日志信息

@Query("select p from Person p where p.id=(select max(id) from Person p)")Person getMaxIdPerson();1

1.3、模糊查询

如果是 @Query 中有 LIKE 关键字,后面的参数需要前面或者后面加 %,这样在传递参数值的时候就可以不加 %

右模糊

@Query("select p from Person p where p.id=(select max(id) from Person p)")Person getMaxIdPerson();2

左模糊

@Query("select p from Person p where p.id=(select max(id) from Person p)")Person getMaxIdPerson();3

全模糊

@Query("select p from Person p where p.id=(select max(id) from Person p)")Person getMaxIdPerson();4

测试方法 1

PersonRepository 类

@Query("select p from Person p where p.id=(select max(id) from Person p)")Person getMaxIdPerson();5

Test 类

@Query("select p from Person p where p.id=(select max(id) from Person p)")Person getMaxIdPerson();6

日志信息

@Query("select p from Person p where p.id=(select max(id) from Person p)")Person getMaxIdPerson();7

测试方法 2

PersonRepository 类

@Query("select p from Person p where p.id=(select max(id) from Person p)")Person getMaxIdPerson();8

Test 类

@Query("select p from Person p where p.id=(select max(id) from Person p)")Person getMaxIdPerson();9

日志信息

@Testpublic void testGetMaxIdPerson() {    Person person = repository.getMaxIdPerson();    System.out.println(person);}0

1.4、本地查询

还可以使用 @Query 来指定本地查询,只要设置 nativeQuerytrue,比如:

@Testpublic void testGetMaxIdPerson() {    Person person = repository.getMaxIdPerson();    System.out.println(person);}1

测试方法

PersonRepository 类

@Testpublic void testGetMaxIdPerson() {    Person person = repository.getMaxIdPerson();    System.out.println(person);}2

Test 类

@Testpublic void testGetMaxIdPerson() {    Person person = repository.getMaxIdPerson();    System.out.println(person);}3

日志信息

@Testpublic void testGetMaxIdPerson() {    Person person = repository.getMaxIdPerson();    System.out.println(person);}4

2、@Modifying 注解

2.1、执行更新操作

@Query@Modifying 这两个 annotation 一起声明,可定义个性化更新操作,例如只涉及某些字段更新时最为常用,示例如下:

@Testpublic void testGetMaxIdPerson() {    Person person = repository.getMaxIdPerson();    System.out.println(person);}5

注意:

方法的返回值应该是 int,表示更新语句所影响的行数

在调用的地方必须加事务,没有事务不能正常执行

测试方法 1

不加 @Modifying 注解会怎么样?

PersonRepository 类

@Testpublic void testGetMaxIdPerson() {    Person person = repository.getMaxIdPerson();    System.out.println(person);}6

Test 类

@Testpublic void testGetMaxIdPerson() {    Person person = repository.getMaxIdPerson();    System.out.println(person);}7

日志信息

@Testpublic void testGetMaxIdPerson() {    Person person = repository.getMaxIdPerson();    System.out.println(person);}8

报错抛出了 QueryExecutionRequestException 异常,提示 Query 不支持 DML 更新操作

测试方法 2

仅仅加 @Modifying 注解会怎么样?

PersonRepository 类:唯一区别就是加上 @Modifying 注解

@Modifying@Testpublic void testGetMaxIdPerson() {    Person person = repository.getMaxIdPerson();    System.out.println(person);}6

日志信息

Hibernate:     select        person0_.id as id1_1_,        person0_.add_id as add_id6_1_,        person0_.address_id as address_2_1_,        person0_.birth_day as birth_da3_1_,        person0_.email as email4_1_,        person0_.last_name as last_nam5_1_     from        jpa_persons person0_     where        person0_.id=(            select                max(person1_.id)             from                jpa_persons person1_        )Person{id=27, lastName='XY', email='XY@qq.com', birthDay=2022-05-21 22:48:34.0}0

报错抛出了 TransactionRequiredException 异常,表明更新或删除操作必须要有一个事务

2.2、事务

Spring Data 提供了默认的事务处理方式,即所有的查询均声明为 只读事务

对于自定义的方法,如需改变 Spring Data 提供的事务默认方式,可以在方法上注解 @Transactional 声明

进行多个 Repository 操作时,也应该使它们在同一个事务中处理,按照分层架构的思想,这部分属于业务逻辑层。因此,需要在 Service 层实现对多个 Repository 的调用,并在相应的方法上声明事务

测试方法 3

@Modifying@Transactional 注解都加上

PersonService 类

Hibernate:     select        person0_.id as id1_1_,        person0_.add_id as add_id6_1_,        person0_.address_id as address_2_1_,        person0_.birth_day as birth_da3_1_,        person0_.email as email4_1_,        person0_.last_name as last_nam5_1_     from        jpa_persons person0_     where        person0_.id=(            select                max(person1_.id)             from                jpa_persons person1_        )Person{id=27, lastName='XY', email='XY@qq.com', birthDay=2022-05-21 22:48:34.0}1

Test 类

Hibernate:     select        person0_.id as id1_1_,        person0_.add_id as add_id6_1_,        person0_.address_id as address_2_1_,        person0_.birth_day as birth_da3_1_,        person0_.email as email4_1_,        person0_.last_name as last_nam5_1_     from        jpa_persons person0_     where        person0_.id=(            select                max(person1_.id)             from                jpa_persons person1_        )Person{id=27, lastName='XY', email='XY@qq.com', birthDay=2022-05-21 22:48:34.0}2

日志信息

Hibernate:     select        person0_.id as id1_1_,        person0_.add_id as add_id6_1_,        person0_.address_id as address_2_1_,        person0_.birth_day as birth_da3_1_,        person0_.email as email4_1_,        person0_.last_name as last_nam5_1_     from        jpa_persons person0_     where        person0_.id=(            select                max(person1_.id)             from                jpa_persons person1_        )Person{id=27, lastName='XY', email='XY@qq.com', birthDay=2022-05-21 22:48:34.0}3

数据表 JPA_PERSONS 数据

结论:

1、可以通过自定义的 JPQL 完成 UPDATE 和 DELETE 操作。注意:JPQL 不支持使用 INSERT

2、在 @Query 注解中编写 JPQL 语句,但必须使用 @Modifying 进行修饰。以通知 SpringData 这是一个 UPDATE 或 DELETE 操作

3、UPDATE 或 DELETE 操作需要使用事务,此时需要定义 Service 层。在 Service 层的方法上添加事务操作

4、默认情况下,SpringData 的每个方法上有事务,但都是一个只读事务。他们不能完成修改操作!

总结

本节主要掌握 @Query@Modifying 两个注解:

@Query 注解支持索引参数、命名参数、模糊查询和本地查询

@Modifying 注解支持更新操作,如 update 和 delete,但不支持 insert(准确来说,JPQL 不支持 insert);需要结合 @Query@Transactional 注解使用

附上导图,仅供参考

原文:https://juejin.cn/post/7101675736704450568


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:/Spring/4512.html