前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spring JPA 自定义删改

Spring JPA 自定义删改

作者头像
Kindear
发布2020-09-14 13:56:32
1.3K0
发布2020-09-14 13:56:32
举报
Spring JPA 更新创建

​ 之前介绍的方法,基本都是只读方法,查询创建没有对数据库中存储的实体进行任何修改,但是对于更新和删除来说,如果继续保持只读属性,那么改删功能是难以完成的。通过使用@modify注释查询方法,您可以修改只需要参数绑定的查询,如下面的示例所示:

例:修改查询实例

代码语言:javascript
复制
@Modifying
@Query("update User u set u.firstname = ?1 where u.lastname = ?2")
int setFixedFirstnameFor(String firstname, String lastname);

​ 这样做被注释的方法的查询将会作为更新查询而不是选择查询,由于EntityManager在执行了修改的查询之后可能返回之前的查询结果,如果您希望EntityManager被自动清除,您可以将@ modify注释的clearautomatic属性设置为true。该注解中有两个属性:flushAutomaticallyclearAutomatically,从字面理解是自动刷新和自动清除。

  自动刷新,即执行完语句后立即将变化内容刷新到磁盘,如果是insert语句操作,则与JPA的<S extends T> S saveAndFlush(S entity);方法效果相同;

  自动清除,即执行完语句后自动清除掉已经过期的实体,比如,我们删除了一个实体,但是在还没有执行flush操作时,这个实体还存在于实体管理器EntityManager中,但这个实体已经过期没有任何用处,直到flush操作时才会被删除掉。如果希望在删除该实体时立即将该实体从实体管理器中删除,则可以将该属性设置为true,如:

代码语言:javascript
复制
@Modifying(clearAutomatically = true)
@Transactional
@Query(value = "delete from pro_user where id = ?1",nativeQuery = true)
void deleteUserById(Long id);
派生删除

Spring Data JPA还支持派生的delete查询,使您不必显式声明JPQL查询,如下面的示例所示:

例:使用派生删除查询

代码语言:javascript
复制
interface UserRepository extends Repository<User, Long> {

  void deleteByRoleId(long roleId);

  @Modifying
  @Query("delete from User u where u.role.id = ?1")
  void deleteInBulkByRoleId(long roleId);
}

​ 尽管deleteByRoleId()方法看起来基本上会产生与deleteInBulkByRoleId()相同的结果,但就执行方式而言,这两个方法声明之间有一个重要的区别。顾名思义,后一种方法对数据库发出单个JPQL查询(在注释中定义的查询)。这意味着即使当前加载的User实例也没有看到该命周期回调被触发。

​ 为了确保实际调用生命周期查询,deleteByRoleId()的调用执行一个查询,然后逐个删除返回的实例,这样持久性提供者就可以对这些实体实际调用@PreRemove回调。

​ 实际上,派生的delete查询是执行查询并在结果上调用CrudRepository.delete(Iterable<User> users)并保持行为与CrudRepository中其他delete()方法的实现同步的快捷方式。

​ 事实上,如果直接运行以上自定义的的方法,可能会出现如下错误:

代码语言:javascript
复制
org.springframework.dao.InvalidDataAccessApiUsageException: Executing an update/delete query; nested exception is javax.persistence.TransactionRequiredException: Executing an update/delete query
    at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:402)
    at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:255)
    ......
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
Caused by: javax.persistence.TransactionRequiredException: Executing an update/delete query
    at org.hibernate.internal.AbstractSharedSessionContract.checkTransactionNeededForUpdateOperation(AbstractSharedSessionContract.java:398)
    at org.hibernate.query.internal.AbstractProducedQuery.executeUpdate(AbstractProducedQuery.java:1585)
    .......

​ 这是因为,默认情况下,repository 接口中的CRUD方法都是被@Transactional注解修饰了的,对于读的操作方法,@Transactional注解的readOnly属性是被设置为true的,即只读;CRUD中的其他方法被@Transactional修饰,即非只读。如果你需要修改repository 接口中的某些方法的事务属性,可以在该方法上重新加上@Transactional注解,并设置需要的属性。

例:修改后代码

代码语言:javascript
复制
@Modifying
@Transactional
@Query("update User u set u.firstname = ?1 where u.lastname = ?2")
int setFixedFirstnameFor(String firstname, String lastname);
参考文档

[1] https://www.cnblogs.com/wuhenzhidu/p/jpa.html [2] https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.modifying-queries

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-09-10 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Spring JPA 更新创建
  • 派生删除
  • 参考文档
相关产品与服务
对象存储
对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档