如何使用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,一经查实,立即删除!

相关文章

【ASP.NET Web API教程】5.4 ASP.NET Web API批处理器

【ASP.NET Web API教程】5.4 ASP.NET Web API批处理器 原文:【ASP.NET Web API教程】5.4 ASP.NET Web API批处理器注&#xff1a;本文是【ASP.NET Web API系列教程】的一部分&#xff0c;如果您是第一次看本系列教程&#xff0c;请先看前面的内容。 Batching Handler for ASP.N…

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

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

C++中指针和引用的选择

何时使用引用和指针1. 尽可能使用引用传递参数2. 尽可能的使用const来保护引用和指针3. 在可以使用引用的时候不要使用指针4. 不要试图给引用重新赋值&#xff0c;使之指向另一个变量&#xff0c;这是不可能的&#xff08;因为引用是变量的别名&#xff0c;和变量是统一的&…

linux 7 没有权限访问,[CentOS 7系列]文件或目录的权限与属性

在开始今天的话题之前&#xff0c;我们首先来回顾下ls命令。在ls命令中参数“-l”会显示出来目标的详细信息&#xff0c;如下所示&#xff1a;[rootserver02~]#ls-l/tmp/总用量4-rwx------.1rootroot8365月2706:19ks-script-ogzDFAdrwxr-xr-x.5rootroot755月3005:26testdrwxr-x…

POJ 2386 Lake Counting DFS水水

http://poj.org/problem?id2386 题目大意&#xff1a; 有一个大小为N*M的园子&#xff0c;雨后积起了水。八连通的积水被认为是连接在一起的。请求出院子里共有多少水洼&#xff1f; 思路&#xff1a; 水题~直接DFS&#xff0c;DFS过程把途中表示水洼的W改为‘.&#xff0c;看…

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主要添…

StringTokenizer(字符串分隔解析类型)

java.util.StringTokenizer 功效:将字符串以定界符为界&#xff0c;分析为一个个的token&#xff08;可理解为单词&#xff09;&#xff0c;定界符可以自己指定。 &#xff11;、构造函数。1. StringTokenizer(String str) &#xff1a;构造一个用来解析str的StringTokenizer对…

linux 秒数转时间格式,通过delphi将秒数转换成日期格式

摘要将秒数转换成日期格式&#xff0c;是经常用到的一个算法&#xff0c;下面有几个方法&#xff0c;可以借鉴具体代码1&#xff1a;转换成HH:MM:SS格式的字符串格式&#xff1a;function SecondToTime(a:integer):string;beginresult:timetostr(a/86400);end;或者function Sec…

Watch online

1.youku 在优酷看视视频时可登录m.youku.com/wap,在IE上都不需wap,但在chrome上不加会自动跳转成www.youku.com。那上面的视频是一个整体&#xff0c;可以用迅雷下也可在浏览器上直接看。 随便搜了下&#xff0c;发现可直接利用www.youku.com上的视频ID找到上述可直接播放下载的…

java开机自启动 Linux,java项目jar包开机自启(WINDOWS,Linux)

WINDOWS:1.新建一个text文件&#xff0c;将 java -jar D:\eclipse-workspace\attendance\target\mybatis-generator.jar写入&#xff0c;修改文件为.bat文件。2.编写run.vbs文件&#xff0c;新建一个run.text文件&#xff0c;将下面代码写入,然后将文件后缀改为.vbsSet ws Cre…

PHP中,json汉字编码

当用json与js或者其它客户端交互时&#xff0c;如果有中文&#xff0c;则会变成unicode。虽然能使用&#xff0c;但是影响观看。不好调试呀。从网上找到了几个方法 一&#xff0c;用下面这个函数&#xff0c;需要编码时&#xff0c;直接调用这个函数就成 function jsonEnco…

[收藏] Opera鼠标手势命令

Opera的Presto内核版本已经不复存在了&#xff01;&#xff01;惋惜&#xff01;痛惜&#xff01; 现在我的电脑硬盘里还保存着两个版本&#xff0c;一个是第三方优化版的v11.00 1156&#xff0c;另一个是Presto的最终官方版&#xff1a;v12.16&#xff0c;现在看起来都有一种莫…

收到有关RabbitMQ集群分区的通知

如果您在集群中运行RabbitMQ&#xff0c;则集群不太可能会被分区 &#xff08;集群的一部分失去与其余部分的连接&#xff09;。 上面的链接页面介绍了显示状态和配置行为的基本命令。 当发生分区时&#xff0c;您首先希望得到通知&#xff0c;然后进行解决。 RabbitMQ实际上使…

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

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

九度 1474:矩阵幂(二分法)

题目描述&#xff1a; 给定一个n*n的矩阵&#xff0c;求该矩阵的k次幂&#xff0c;即P^k 思路 1. 和求解整数幂的思路相同, 使用分治策略, 代码的框架是 int pow(a, b) { c pow(a, b/2) c* c; if(b 为奇数) c * a; return c } 2. 这道题求的是矩阵, 上面的框架不太好用, 毕竟返…

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

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

linux安装程序过程,linux 应用程序安装过程

四.GRUB安装方式:(1)tar zxvf grub-0.5.96.1.tar.gz(2)cd grub-0.5.96.1(3)./configure(4)make(5)make check(6)make install(7)cp r /usr/local/share/grub/i386-pc/ /boot/grub/(8)vi /boot/menu.lst (内容参考grub-0.5.96.1/docs/menu.lst)例参考如:## /boot/grub/menu.lst …