使用JPA和Hibernate有效删除数据

您可能会遇到必须对关系数据库中存储的大量数据集执行批量删除的情况。 如果您将JPA与Hibernate一起用作基础OR映射器,则可以尝试通过以下方式调用EntityManager的remove()方法:

public void removeById(long id) {RootEntity rootEntity = entityManager.getReference(RootEntity.class, id);entityManager.remove(rootEntity);
}

首先,我们加载要删除的实体的引用表示形式,然后将此引用传递给EntityManager。 假设上面的RootEntity与名为ChildEntity的类有子关系:

@OneToMany(mappedBy = "rootEntity", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private Set childEntities = new HashSet(0);

如果现在打开hibernate的属性show_sql,我们将想知道发出什么SQL语句:

selectrootentity0_.id as id5_1_,rootentity0_.field1 as field2_5_1_,rootentity0_.field2 as field3_5_1_,childentit1_.PARENT as PARENT5_3_,childentit1_.id as id3_,childentit1_.id as id4_0_,childentit1_.field1 as field2_4_0_,childentit1_.field2 as field3_4_0_,childentit1_.PARENT as PARENT4_0_fromROOT_ENTITY rootentity0_left outer joinCHILD_ENTITY childentit1_on rootentity0_.id=childentit1_.PARENTwhererootentity0_.id=?deletefromCHILD_ENTITYwhereid=?deletefromROOT_ENTITYwhereid=?

为什么Hibernate首先将所有数据加载到内存中以便随后立即删除该数据? 原因是JPA的生命周期要求该对象处于“托管”状态,然后才能将其删除。 仅在这种状态下,所有生命周期功能(如拦截器)才可用(请参阅此处 )。 因此,Hibernate会在删除之前发出SELECT查询,以便将RootEntity和ChildEntity都转移到“托管”状态。 但是,如果我们只想删除RootEntity和ChildEntity,并且知道RootEntity的ID,该怎么办? 答案是使用简单的DELETE查询,如下面的查询。 但是由于子表的完整性约束,我们首先必须删除所有依赖的子实体。 以下代码演示了如何:

List childIds = entityManager.createQuery("select c.id from ChildEntity c where c.rootEntity.id = :pid").setParameter("pid", id).getResultList();
for(Long childId : childIds) {entityManager.createQuery("delete from ChildEntity c where c.id = :id").setParameter("id", childId).executeUpdate();
}
entityManager.createQuery("delete from RootEntity r where r.id = :id").setParameter("id", id).executeUpdate();

上面的代码通过调用remove()产生了我们期望的三个SQL语句。 现在您可能会说,这种删除方式比仅调用EntityManager的remove()方法更为复杂。 它还会忽略我们已放置在两个实体类中的注解,例如@OneToMany和@ManyToOne。 那么,为什么不编写一些代码来使用关于两个类文件中已经存在的两个实体的知识呢? 首先,我们在RootEntity类中使用反射查找@OneToMany批注,提取子实体的类型,然后查找其后向字段,并用@ManyToOne批注。 完成此操作后,我们可以轻松地以更通用的方式编写三个SQL语句:

public void delete(EntityManager entityManager, Class parentClass, Object parentId) {Field idField = getIdField(parentClass);if (idField != null) {List oneToManyFields = getOneToManyFields(parentClass);for (Field field : oneToManyFields) {Class childClass = getFirstActualTypeArgument(field);if (childClass != null) {Field manyToOneField = getManyToOneField(childClass, parentClass);Field childClassIdField = getIdField(childClass);if (manyToOneField != null && childClassIdField != null) {List childIds = entityManager.createQuery(String.format("select c.%s from %s c where c.%s.%s = :pid", childClassIdField.getName(), childClass.getSimpleName(), manyToOneField.getName(), idField.getName())).setParameter("pid", parentId).getResultList();for (Long childId : childIds) {entityManager.createQuery(String.format("delete from %s c where c.%s = :id", childClass.getSimpleName(), childClassIdField.getName())).setParameter("id", childId).executeUpdate();}}}}entityManager.createQuery(String.format("delete from %s e where e.%s = :id", parentClass.getSimpleName(), idField.getName())).setParameter("id", parentId).executeUpdate();}
}

上面的代码中的方法getFirstActualTypeArgument(),getManyToOneField(),getIdField()和getOneToManyFields()并未在此处显示,但是听起来像它们的名字。 实施后,我们可以轻松删除所有以树的根开头的实体。

  • 可以在github上找到一个可用于检查上述行为和解决方案的简单示例应用程序。

参考:在Martin's Developer World博客上, 使用JPA和Hibernate从我们的JCG合作伙伴 Martin Mois 有效地删除了数据 。

翻译自: https://www.javacodegeeks.com/2013/11/efficiently-delete-data-with-jpa-and-hibernate.html

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java21个知识点重点_java21个知识点重点

http://blog.csdn.net/jerroluo/article/details/520025851. JVM相关(包括了各个版本的特性)对于刚刚接触Java的人来说,JVM相关的知识不一定需要理解很深,对此里面的概念有一些简单的了解即可。不过对于一个有着3年以上Java经验的资深开发者来说&#xf…

Django模型中字段属性choice使用

今天设计models时,用到了choice这个属性,用来限制用户做出选择的范围。比如说性别的选择(男或女)。 class User(AbstractUser):。。。sex models.CharField(verbose_name性别,max_length5,choi…

面试题4,打印出100-999所有的“水仙花数”。

提示:水仙花数是指一个 n 位数 ( n≥3 ),它的每个位上的数字的 n 次幂之和等于它本身。 (例如:1^3 5^3 3^3 153) package 面试;/*** 水仙花数* author liugang* create 2018/12/19 20:07**/ public class Shuixianhu…

angularjs的$http请求方式

/*$http常用的几个参数$http服务的设置对象:1、method 字符串 表示发送的请求类型 get post jsonp等等2、url 字符串 绝对或者相对的URL,请求的目标3、params 字符串或对象 会被转化成查询字符串加到URL后面,如果不是字符串会被JSON序列化4、data 字符串或者对象 这…

response对象设置返回状态_postman 设置全局变量

postman大家都知道是一个测试接口的工具,也是目前比较流行的一种测试工具,但是postman只是用来将API地址和参数填入send一下就完了吗?其实不是,关于postman其实有很多玩法,对于测试来说我觉得掌握了postman是非常有必要…

测试过大输入的代码

在编写单元测试时,我们主要关注业务的正确性。 我们将竭尽所能,开开心心地走在最前沿。 我们有时会进行微基准测试并衡量吞吐量。 但是经常遗漏的一个方面是当输入过大时我们的代码如何表现? 我们测试了如何处理正常的输入文件,格…

资源不在java项目和构建路径上_编译单元不在Java项目的构建路径上-Maven

今天,我已经在日食中导入了一个Maven项目.当我尝试自动建议时,当我添加一些代码时,它提示我“编译单元不在Java项目的构建路径上”.我没有看到解决此问题的方法,但是都没有解决.这个应该做什么?xsi:schemaLocation"http://maven.apache.org/POM/4.0.0 http://m…

Django 第八课 2.【MySQL相关软件 mysqlclient Navicat Premium】

MySQL 驱动程序安装: 我们使用 Django 来操作 MySQL,实际上底层还是通过 Python来操作的。因此我们想要用 Django 来操作 MySQL,首先还是需要安装一个驱动程序。在python3中,驱动程序有多种选择。比如pymysql 以及mysqlclient等。…

查看串口的驱动信息

1、查看串口的驱动信息 2、驱动安装文件:http://www.wch.cn/download/CH341SER_EXE.html 3、参考驱动资料:https://blog.csdn.net/jazzsoldier/article/details/70169732 转载于:https://www.cnblogs.com/qy1234/p/10146303.html

用jQuery监听浏览器窗口的变化

1 $(window).resize(function () { //当浏览器大小变化时 2 alert($(window).height()); //浏览器时下窗口可视区域高度 3 alert($(document).height()); //浏览器时下窗口文档的高度 4 alert($(document.body).height()); //浏览器时下…

java中怎么判断一段代码时线程安全还是非线程安全_Java 中的多线程你只要看这一篇就够了...

引如果对什么是线程、什么是进程仍存有疑惑,请先Google之,因为这两个概念不在本文的范围之内。用多线程只有一个目的,那就是更好的利用cpu的资源,因为所有的多线程代码都可以用单线程来实现。说这个话其实只有一半对,因…

使用Maven设置您的应用服务器

在许多情况下,无需先设置应用程序就无法部署应用程序。 在JBoss AS 7.x中,您可能需要配置例如数据库连接。 或者,您必须配置一个安全领域。 也许您还想调整SLSB池…在任何一种情况下,团队中的所有开发人员都必须共享一个共同的或至…

[洛谷P3178][HAOI2015]树上操作

题目大意:有一棵点数为 $N$ 的树,以点 1 为根。然后有 $M$ 个操作。 1. 把 $x$ 的点权增加 $a$ 。 2. 把 $x$ 为根的子树中所有点的点权都增加 $a$ 。 3. 询问 $x$ 到根的路径中所有点的点权和。 题解:树链剖分模板题 卡点:我真的…

实现 通过数据库里一个字段值相等 则把 他合为一条数据

需求: 把红色合为一条数据,绿色合为一条数据 结果: 不多说直接上代码......................................................... // 先查所有数据 const goods await service.goods.findAllGoodsWithParams({where: params,offset: ctx.p…

CSS定义字体间距 字体行与行间距

1 2     letter-spacing:像素(字母或中文字的左右间距)3 4 word-spacing:像素(两个单词之间的左右间距)5 6 line-height:像素(两行之间的间距)7 8 text-decoration:字体的装饰&am…

float与double类型参数区别_8大基本数据类型及包装类,不知道这些点别说自己是大佬...

一般地,当需要使用数字的时候,我们通常使用内置数据类型,如:byte、int、long、double 等。然而,在实际开发过程中,我们经常会遇到需要使用对象,而不是内置数据类型的情形。为了解决这个问题&…

宣布EAXY:在Java中简化XML

Java中的XML库是一个雷区。 操作和读取XML所需的代码量令人震惊,使用不同的库遇到类路径问题的风险很大,并且命名空间的处理带来了很多混乱和错误。 最糟糕的是,情况似乎并没有改善。 一位同事让我意识到JOOX库。 这是解决这些问题的一个很好…

9-客户端集成IdentityServer

1-创建客户端的webapi项目 E:\coding\netcore\IdentityServerSample>dotnet new webapi --name IdentityCredentialApi 2-在需要启用授权的方法上增加Authorize标签 3-使用nuget工具安装 IdentityServer4.AccessTokenValidation 4-启用客户端授权, 需要配置连接…

js parseInt()与Number()区别

说到转换成数字类型,我首先想到的是parseInt()方法,后来接触多了才发现还有一个Number()方法,同样是转换成数字类型,这两种方法有什么不同的呢? 1.parseInt()&#xff1a…

java大小端字节流解析_玩转socket之字节流操作--拼包、拆包

玩转socket之字节流操作--拼包、拆包我们开发中用得最多的HTTP协议及超文本传输协议,是一种基于TCP/IP的文本传输协议。基本很少碰到字节流操作。但是我过我们要用socket,实现一套基本TCP/IP协议的自定义协议,那么,对于字节流的操…