如何使用Hibernate批处理INSERT和UPDATE语句

介绍

JDBC长期以来一直为DML语句批处理提供支持。 默认情况下,所有语句都一个接一个地发送,每个语句都在单独的网络往返中发送。 批处理使我们能够一次性发送多个语句,从而节省了不必要的套接字流刷新。

Hibernate将数据库语句隐藏在事务后写抽象层的后面 。 中间层允许我们从持久层逻辑中隐藏JDBC批处理语义。 这样,我们可以更改JDBC批处理策略,而无需更改数据访问代码。

配置Hibernate来支持JDBC批处理并不是那么容易,所以我将解释为使其工作所需要做的一切。

测试时间

我们将从以下实体模型开始:

发表评论jdbcbatch

帖子Comment实体具有一对多关联:

@OneToMany(cascade = CascadeType.ALL, mappedBy = "post", orphanRemoval = true)
private List<Comment> comments = new ArrayList<>();

或者测试场景同时发出INSERTUPDATE语句,因此我们可以验证是否正在使用JDBC批处理:

LOGGER.info("Test batch insert");
long startNanos = System.nanoTime();
doInTransaction(session -> {int batchSize = batchSize();for(int i = 0; i < itemsCount(); i++) {Post post = new Post(String.format("Post no. %d", i));int j = 0;post.addComment(new Comment(String.format("Post comment %d:%d", i, j++)));post.addComment(new Comment(String.format("Post comment %d:%d", i, j++)));session.persist(post);if(i % batchSize == 0 && i > 0) {session.flush();session.clear();}}
});
LOGGER.info("{}.testInsert took {} millis",getClass().getSimpleName(),TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startNanos));LOGGER.info("Test batch update");
startNanos = System.nanoTime();doInTransaction(session -> {List<Post> posts = session.createQuery("select distinct p " +"from Post p " +"join fetch p.comments c").list();for(Post post : posts) {post.title = "Blog " + post.title;for(Comment comment : post.comments) {comment.review = "Blog " + comment.review;}}
});LOGGER.info("{}.testUpdate took {} millis",getClass().getSimpleName(),TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startNanos));

该测试将保留可配置数量的Post实体,每个实体包含两个Comment 。 为了简洁起见,我们将保留3个帖子方言的默认批处理大小:

protected int itemsCount() {return 3;
}protected int batchSize() {return Integer.valueOf(Dialect.DEFAULT_BATCH_SIZE);
}

默认批处理支持

Hibernate不会隐式使用JDBC批处理,并且每个INSERTUPDATE语句都是分别执行的:

Query:{[insert into Post (title, version, id) values (?, ?, ?)][Post no. 0,0,1]} 
Query:{[insert into Comment (post_id, review, version, id) values (?, ?, ?, ?)][1,Post comment 0:0,0,51]} 
Query:{[insert into Comment (post_id, review, version, id) values (?, ?, ?, ?)][1,Post comment 0:1,0,52]} 
Query:{[insert into Post (title, version, id) values (?, ?, ?)][Post no. 1,0,2]} 
Query:{[insert into Comment (post_id, review, version, id) values (?, ?, ?, ?)][2,Post comment 1:0,0,53]} 
Query:{[insert into Comment (post_id, review, version, id) values (?, ?, ?, ?)][2,Post comment 1:1,0,54]} 
Query:{[insert into Post (title, version, id) values (?, ?, ?)][Post no. 2,0,3]} 
Query:{[insert into Comment (post_id, review, version, id) values (?, ?, ?, ?)][3,Post comment 2:0,0,55]} 
Query:{[insert into Comment (post_id, review, version, id) values (?, ?, ?, ?)][3,Post comment 2:1,0,56]}Query:{[update Post set title=?, version=? where id=? and version=?][Blog Post no. 1,1,2,0]} 
Query:{[update Comment set post_id=?, review=?, version=? where id=? and version=?][2,Blog Post comment 1:0,1,53,0]} 
Query:{[update Post set title=?, version=? where id=? and version=?][Blog Post no. 0,1,1,0]} 
Query:{[update Comment set post_id=?, review=?, version=? where id=? and version=?][1,Blog Post comment 0:1,1,52,0]} 
Query:{[update Post set title=?, version=? where id=? and version=?][Blog Post no. 2,1,3,0]} 
Query:{[update Comment set post_id=?, review=?, version=? where id=? and version=?][3,Blog Post comment 2:0,1,55,0]} 
Query:{[update Comment set post_id=?, review=?, version=? where id=? and version=?][3,Blog Post comment 2:1,1,56,0]} 
Query:{[update Comment set post_id=?, review=?, version=? where id=? and version=?][1,Blog Post comment 0:0,1,51,0]} 
Query:{[update Comment set post_id=?, review=?, version=? where id=? and version=?][2,Blog Post comment 1:1,1,54,0]}

配置

要启用JDBC批处理,我们必须配置hibernate.jdbc.batch_size属性:

非零值允许Hibernate使用JDBC2批处理更新(例如,建议值介于5到30之间)

我们将设置此属性并重新运行测试:

properties.put("hibernate.jdbc.batch_size", String.valueOf(batchSize()));

这次,批处理Comment INSERT语句,而UPDATE语句保持不变:

Query:{[insert into Post (title, version, id) values (?, ?, ?)][Post no. 0,0,1]} 
Query:{[insert into Comment (post_id, review, version, id) values (?, ?, ?, ?)][1,Post comment 0:0,0,51]} {[insert into Comment (post_id, review, version, id) values (?, ?, ?, ?)][1,Post comment 0:1,0,52]} 
Query:{[insert into Post (title, version, id) values (?, ?, ?)][Post no. 1,0,2]} 
Query:{[insert into Comment (post_id, review, version, id) values (?, ?, ?, ?)][2,Post comment 1:0,0,53]} {[insert into Comment (post_id, review, version, id) values (?, ?, ?, ?)][2,Post comment 1:1,0,54]} 
Query:{[insert into Post (title, version, id) values (?, ?, ?)][Post no. 2,0,3]} 
Query:{[insert into Comment (post_id, review, version, id) values (?, ?, ?, ?)][3,Post comment 2:0,0,55]} {[insert into Comment (post_id, review, version, id) values (?, ?, ?, ?)][3,Post comment 2:1,0,56]}Query:{[update Post set title=?, version=? where id=? and version=?][Blog Post no. 1,1,2,0]} 
Query:{[update Comment set post_id=?, review=?, version=? where id=? and version=?][2,Blog Post comment 1:0,1,53,0]}
Query:{[update Post set title=?, version=? where id=? and version=?][Blog Post no. 0,1,1,0]} 
Query:{[update Comment set post_id=?, review=?, version=? where id=? and version=?][1,Blog Post comment 0:1,1,52,0]}
Query:{[update Post set title=?, version=? where id=? and version=?][Blog Post no. 2,1,3,0]} 
Query:{[update Comment set post_id=?, review=?, version=? where id=? and version=?][3,Blog Post comment 2:0,1,55,0]}
Query:{[update Comment set post_id=?, review=?, version=? where id=? and version=?][3,Blog Post comment 2:1,1,56,0]}
Query:{[update Comment set post_id=?, review=?, version=? where id=? and version=?][1,Blog Post comment 0:0,1,51,0]}
Query:{[update Comment set post_id=?, review=?, version=? where id=? and version=?][2,Blog Post comment 1:1,1,54,0]}

JDBC批处理只能针对一个表,因此,针对不同表的每个新DML语句都会终止当前的批处理并启动一个新的。 因此,在使用SQL批处理时,不希望混合使用不同的表语句。

订购说明

Hibernate可以使用以下配置选项对INSERTUPDATE语句进行排序:

properties.put("hibernate.order_inserts", "true");
properties.put("hibernate.order_updates", "true");

尽管对PostComment INSERT语句进行了相应的批处理,但UPDATE语句仍单独执行:

Query:{[insert into Post (title, version, id) values (?, ?, ?)][Post no. 0,0,1]} {[insert into Post (title, version, id) values (?, ?, ?)][Post no. 1,0,2]} {[insert into Post (title, version, id) values (?, ?, ?)][Post no. 2,0,3]} 
Query:{[insert into Comment (post_id, review, version, id) values (?, ?, ?, ?)][1,Post comment 0:0,0,51]} {[insert into Comment (post_id, review, version, id) values (?, ?, ?, ?)][1,Post comment 0:1,0,52]} {[insert into Comment (post_id, review, version, id) values (?, ?, ?, ?)][2,Post comment 1:0,0,53]} {[insert into Comment (post_id, review, version, id) values (?, ?, ?, ?)][2,Post comment 1:1,0,54]} {[insert into Comment (post_id, review, version, id) values (?, ?, ?, ?)][3,Post comment 2:0,0,55]} {[insert into Comment (post_id, review, version, id) values (?, ?, ?, ?)][3,Post comment 2:1,0,56]}Query:{[update Comment set post_id=?, review=?, version=? where id=? and version=?][1,Blog Post comment 0:0,1,51,0]}
Query:{[update Comment set post_id=?, review=?, version=? where id=? and version=?][1,Blog Post comment 0:1,1,52,0]}
Query:{[update Comment set post_id=?, review=?, version=? where id=? and version=?][2,Blog Post comment 1:0,1,53,0]}
Query:{[update Comment set post_id=?, review=?, version=? where id=? and version=?][2,Blog Post comment 1:1,1,54,0]}
Query:{[update Comment set post_id=?, review=?, version=? where id=? and version=?][3,Blog Post comment 2:0,1,55,0]}
Query:{[update Comment set post_id=?, review=?, version=? where id=? and version=?][3,Blog Post comment 2:1,1,56,0]}
Query:{[update Post set title=?, version=? where id=? and version=?][Blog Post no. 0,1,1,0]} 
Query:{[update Post set title=?, version=? where id=? and version=?][Blog Post no. 1,1,2,0]} 
Query:{[update Post set title=?, version=? where id=? and version=?][Blog Post no. 2,1,3,0]}

添加版本数据批处理支持

我们需要设置hibernate.jdbc.batch_versioned_data配置属性,以启用UPDATE批处理:

如果您的JDBC驱动程序从executeBatch()返回正确的行数,则将此属性设置为true。 通常可以安全地打开此选项。 然后,Hibernate将使用批处理的DML来自动版本化数据。 默认为false。

我们也将使用此属性集重新运行测试:

properties.put("hibernate.jdbc.batch_versioned_data", "true");

现在, INSERTUPDATE语句均已正确批处理:

Query:{[insert into Post (title, version, id) values (?, ?, ?)][Post no. 0,0,1]} {[insert into Post (title, version, id) values (?, ?, ?)][Post no. 1,0,2]} {[insert into Post (title, version, id) values (?, ?, ?)][Post no. 2,0,3]} 
Query:{[insert into Comment (post_id, review, version, id) values (?, ?, ?, ?)][1,Post comment 0:0,0,51]} {[insert into Comment (post_id, review, version, id) values (?, ?, ?, ?)][1,Post comment 0:1,0,52]} {[insert into Comment (post_id, review, version, id) values (?, ?, ?, ?)][2,Post comment 1:0,0,53]} {[insert into Comment (post_id, review, version, id) values (?, ?, ?, ?)][2,Post comment 1:1,0,54]} {[insert into Comment (post_id, review, version, id) values (?, ?, ?, ?)][3,Post comment 2:0,0,55]} {[insert into Comment (post_id, review, version, id) values (?, ?, ?, ?)][3,Post comment 2:1,0,56]}Query:{[update Comment set post_id=?, review=?, version=? where id=? and version=?][1,Blog Post comment 0:0,1,51,0]} {[update Comment set post_id=?, review=?, version=? where id=? and version=?][1,Blog Post comment 0:1,1,52,0]} {[update Comment set post_id=?, review=?, version=? where id=? and version=?][2,Blog Post comment 1:0,1,53,0]} {[update Comment set post_id=?, review=?, version=? where id=? and version=?][2,Blog Post comment 1:1,1,54,0]} {[update Comment set post_id=?, review=?, version=? where id=? and version=?][3,Blog Post comment 2:0,1,55,0]} {[update Comment set post_id=?, review=?, version=? where id=? and version=?][3,Blog Post comment 2:1,1,56,0]}
Query:{[update Post set title=?, version=? where id=? and version=?][Blog Post no. 0,1,1,0]} {[update Post set title=?, version=? where id=? and version=?][Blog Post no. 1,1,2,0]} {[update Post set title=?, version=? where id=? and version=?][Blog Post no. 2,1,3,0]}

基准测试

既然我们已经为JDBC批处理配置了Hibernate,我们就可以对语句分组的性能​​提升进行基准测试。

  • 测试用例使用与当前正在运行的JVM安装在同一台机器上的PostgreSQL数据库
  • 选择了50的批量,并且每次测试迭代都会将语句计数增加一个数量级
  • 所有持续时间均以毫秒表示
报表数量 无批次插入持续时间 无批次更新持续时间 批量插入时间 批量更新持续时间
30 218 178 191 144
300 311 327 208 217
3000 1047 1089 556 478
30000 5889 6032 2640 2301
300000 51785 57869 16052 20954


我们执行INSERTUPDATE的行越多,从JDBC批处理中受益越多。 对于最写的应用程序(例如企业级企业批处理程序 ),我们绝对应该启用JDBC批处理,因为其性能优势可能是惊人的 。

  • 代码可在GitHub上获得 。

翻译自: https://www.javacodegeeks.com/2015/03/how-to-batch-insert-and-update-statements-with-hibernate.html

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

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

相关文章

linux 查看系统组账号密码是什么,Linux 用户与组管理详解(system-config-users 命令行)...

用户与组管理用户相关文件组账号相关文件用户和组管理软件&#xff1a;基于命令行的用户和组管理创建用户查看用户信息删除用户修改用户信息为用户创建密码更改用户密码信息创建组删除组查看当前登录到系统的用户用户与组管理什么是用户&#xff0c;用户是人吗&#xff1f;用户…

linux没有root密码xshell,LINUX终端免密登陆(以Xshell为例)

1&#xff0c;工具-新建用户密钥生成向导linux2&#xff0c;密钥类型选择&#xff1a;RSA&#xff0c;而后下一步shell3&#xff0c;输入密钥名称和密码ssh4&#xff0c;公钥格式为SSH-OpenSSH,保存为文件(后缀为pub)(记录此文件目录)工具二&#xff0c;登陆在须要免密登陆的主…

ActionBar之style出现Cannot resolve symbol 'Theme' 错误

今天 2014/03/08 00:49 刚刚升级 android studio 到了 0.5.0 版本&#xff0c;修复了许多 bug&#xff0c;包含当前这个问题&#xff0c;之前一直困扰我很久&#xff0c;莫名奇妙的提示主题样式找不到&#xff0c;无法解析&#xff0c; 后来一直谷歌发现很多人都认为是 IDE 的b…

单片机上运行linux程序代码,在Linux下烧录51单片机

原标题&#xff1a;在Linux下烧录51单片机*本文作者&#xff1a;LEdge1&#xff0c;本文属 FreeBuf原创奖励计划&#xff0c;未经许可禁止转载。背景我一直在学习Linux 系统&#xff0c;但是最近还要学习51单片机&#xff0c;所以在Linux下给51单片机烧录程序那是非常必要的。之…

linux运行core控制台程序,VisualStudioCode创建的asp.net core控制台程序部署到linux

1、asp.net core控制台程序static void Main(string[] args){int times10;while(times>0){Console.WriteLine("Hello World!");times--;Thread.Sleep(1000);}}2、发布发布前&#xff0c;修改test2.csproj文件(项目名称为test2)Exenetcoreapp2.1centos.7-x64主要添…

wps linux版本支持vba,Wps vba安装包

wps vba是款专用于wps办公软件的宏插件&#xff0c;可以利用VBA制作Excel登录系统&#xff0c;实现一些VB无法实现的功能&#xff0c;操作界面人性化&#xff0c;方便用户的操作&#xff0c;还可以利用VBA来Excel内轻松开发出功能强大的自动化程序。软件简介&#xff1a;wps vb…

我的Dojo中有一个Mojo(如何编写Maven插件)

我一直忙于在工作中使用Maven的腋窝。 对于很多开发人员&#xff0c;我会听到&#xff1a;“那又怎样。” 不同之处在于&#xff0c;我通常在无法直接访问Internet的环境中工作。 因此&#xff0c;当我说我经常使用Maven时&#xff0c;这意味着某些事情。 依赖地狱 公平地说&a…

在linux下安装mongo数据库,Linux系统下安装MongoDB

MongoDB提供了Linux系统上32位和64位的安装包&#xff0c;你可以在官网下载安装包。下载完安装包&#xff0c;并解压 tgz(以下演示的是 64 位 Linux上的安装) 。curl-O https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-3.0.6.tgz # 下载tar-zxvf mongodb-linux-x86_64-…

Windows 8.1 新增控件之 Hyperlink

Windows 8.1 新增控件之 Hyperlink 原文:Windows 8.1 新增控件之 HyperlinkHyperlink 控件应该不用过多介绍大家肯定十分清楚其作用&#xff0c;它的功能就像HTML中的<a href””>标签一样&#xff0c;只不过是在XAML中实现。 使用Hyperlink 标记的文字在应用中会以特殊颜…

Linux的slab和nginx的区别,Nginx核心知识100讲》nginx Slab管理器

极客专栏《Nginx核心知识100讲》38小节的笔记nginx 不同的worker之间需要共享信息的时候&#xff0c;只能通过共享内存。共享内存会使用链表&#xff0c;红黑树这样的数据结构。但是每个红黑树上有很多节点&#xff0c;每个节点上都需要分配内存去存放。怎样把一整块共享内存切…

睡觉时:新增的Java 8新增功能

自Java 8推出以来&#xff0c;最有趣的功能是什么&#xff1f; Java 8最近庆祝了它的第一个生日&#xff0c;而主要版本刚刚一年多前发布。 这当然值得庆祝。 自从最初的Java 8版本问世以来&#xff0c;已经发布了六个更新。 这些更新中的一些元素是次要的&#xff0c;但是如…

树莓派安装win10arm linux,在树莓派3B 上安装 Windows 10 ARM 版的方法

早先关注我们的朋友可能对《国外开发者尝试在树莓派3上运行Windows 10桌面版》有印象。本文转自 amatfan.com&#xff0c;文末视频来自 daveb778(感谢柠栀和刺分享)&#xff0c;给出了如何在树莓派3B上安装Windows10 ARM版&#xff0c;是的&#xff0c;这次并非IoT版&#xff0…

各种触摸手势

轻按(UITapGestureRecognizer) -- 用一个或多个手指在屏幕上轻按。 按住(UILongPressGestureRecognizer) -- 用一个或多个手指在屏幕上按住。 轻扫(UISwipeGestureRecognizer) -- 用一个或多个手指沿特定方向轻扫。 张合(UIPinchGestureRecognizer) -- 张合手指以缩放对象。 旋…

宝塔linux取消登录,宝塔面板如何关闭安全入口

通过 SSH 终端关闭安全入口通过 SSH 终端连接rm -f /www/server/panel/data/admin_path.pl即可关闭宝塔 Linux 面板的安全入口&#xff0c;关闭之后的面板登录地址就是&#xff1a;http://服务器 IP:8888。不过关闭这个安全入口之后很难恢复&#xff0c;所以不建议关闭宝塔面板…

[ofbiz]设置任务计划(job),提示service_item已经传递

问题描述&#xff1a;设置任务计划(job)&#xff0c;提示service_item已经传递 解决办法&#xff1a; 红色框内不要填写&#xff0c;就可以了。"已经传递"是翻译的不准确&#xff0c;应该是"已过时"&#xff0c;所以不设置开始时间&#xff0c;或者开始时间…

c支限界算法语言n皇后问题分,n皇后问题(分析)

这道题需要用到回溯算法&#xff0c;现在在这里先简单的介绍一下这个算法&#xff1a;回溯算法也叫试探法&#xff0c;它是一种系统地搜索问题的解的方法。回溯算法的基本思想是&#xff1a;从一条路往前走&#xff0c;能进则进&#xff0c;不能进则退回来&#xff0c;换一条路…

android系统相机自动录像,android 调用系统相机录像并保存

1、在AndroidManifest.xml中添加如下代码tools:ignore"ProtectedPermissions" />android:authorities"${applicationId}.provider"android:name"android.support.v4.content.FileProvider"android:exported"false"android:grantUri…

【原创】jpgraph中文乱码问题的解决

php jpgraph库非常强大&#xff0c;可以在后台生成图片 后台生成在需要导出图表型报告的时候非常有用&#xff0c;当然&#xff0c;前端的可视化还是要用highcharts/echarts/anycharts等类库 比较麻烦的是中文乱码问题&#xff0c;有3个地方乱码&#xff1a; legendsetStickLab…

getstring方法android,JSON中optString和getString方法的区别

JSON中optString和getString方法的区别更新时间&#xff1a;2017年07月07日 15:18:24 投稿&#xff1a;mrroptString方法会在对应的key中的值不存在的时候返回一个空字符串&#xff0c;但是getString会抛一个JSONException 。下面通过一段代码给大家介绍JSON中optString和get…

jpanel把原本内容覆盖掉_A5:APP关键词覆盖你该了解哪些

A5:APP关键词覆盖你该了解哪些点击上方蓝字关注我们苹果ios/安卓-各大应用商店ASO优化大全IOS关键词覆盖1、苹果AppStore关键词搜索的权重排序为app标题、副标题>app关键词>app描述>宣传文本及评论(App关键词100字符)。2、如何优化100字符关键词①、根据产品用户画像分…