Hibernate隐藏的宝石:pooled-lo优化器

介绍

在这篇文章中,我们将揭示一个序列标识符生成器,​​它结合了标识符分配效率和与其他外部系统的互操作性(同时访问底层数据库系统)。

传统上,有两种序列标识符策略可供选择。

  • 序列标识符,对于每个新值分配总是命中数据库。 即使使用数据库序列预分配,我们也要花费大量的数据库往返费用。
  • seqhilo标识符,使用hi / lo算法。 该生成器在内存中计算一些标识符值,因此减少了数据库往返调用。 这种优化技术的问题在于当前的数据库序列值不再反映当前的最高内存生成值。 数据库序列用作存储区编号,这使得其他系统很难与所讨论的数据库表进行互操作。 其他应用程序必须了解高/低标识符策略的内部工作方式,才能正确生成非冲突标识符。

增强的标识符

Hibernate提供了一类新的标识符生成器 ,解决了原始标识符生成器的许多缺点。 增强的标识符生成器没有固定的标识符分配策略。 优化策略是可配置的,我们甚至可以提供自己的优化实现。 默认情况下,Hibernate带有以下内置优化器 :

  • none :每个标识符都是从数据库中获取的,因此等效于原始序列生成器。
  • hi / lo :它使用hi / lo算法,与原始seqhilo生成器等效。
  • 合并的 :此优化器使用高/低优化策略,但是当前内存中标识符的最高边界是从实际数据库序列值中提取的。
  • pooled-lo :它类似于优化器,但是数据库序列值用作当前的内存最低边界

在正式发布公告中 , 公告了合并的优化器可与其他外部系统进行互操作:

即使其他应用程序也在插入值,我们也将是绝对安全的,因为SEQUENCE本身将处理应用此增量大小。

这实际上是我们正在寻找的东西; 当其他外部系统在同一数据库表中同时插入行时,标识符生成器既高效又不会冲突。

测试时间

以下测试将检查新的优化器如何与其他外部数据库表插入配合使用。 在我们的情况下,外部系统将是同一数据库表/序列上的一些本机JDBC插入语句。

doInTransaction(new TransactionCallable<Void>() {@Overridepublic Void execute(Session session) {for (int i = 0; i < 8; i++) {session.persist(newEntityInstance());}session.flush();assertEquals(8, ((Number) session.createSQLQuery("SELECT COUNT(*) FROM sequenceIdentifier").uniqueResult()).intValue());insertNewRow(session);insertNewRow(session);insertNewRow(session);assertEquals(11, ((Number) session.createSQLQuery("SELECT COUNT(*) FROM sequenceIdentifier").uniqueResult()).intValue());List<Number> ids = session.createSQLQuery("SELECT id FROM sequenceIdentifier").list();for (Number id : ids) {LOGGER.debug("Found id: {}", id);}for (int i = 0; i < 3; i++) {session.persist(newEntityInstance());}session.flush();return null;}
});

池优化器

我们将首先使用优化器策略:

@Entity(name = "sequenceIdentifier")
public static class PooledSequenceIdentifier {@Id@GenericGenerator(name = "sequenceGenerator", strategy = "enhanced-sequence",parameters = {@org.hibernate.annotations.Parameter(name = "optimizer", value = "pooled"),@org.hibernate.annotations.Parameter(name = "initial_value", value = "1"),@org.hibernate.annotations.Parameter(name = "increment_size", value = "5")})@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")private Long id;
}

运行测试最终会引发以下异常:

DEBUG [main]: n.t.d.l.SLF4JQueryLoggingListener - Name: Time:0 Num:1 Query:{[insert into sequenceIdentifier (id) values (?)][9]} 
DEBUG [main]: n.t.d.l.SLF4JQueryLoggingListener - Name: Time:0 Num:1 Query:{[insert into sequenceIdentifier (id) values (?)][10]} 
DEBUG [main]: n.t.d.l.SLF4JQueryLoggingListener - Name: Time:0 Num:1 Query:{[insert into sequenceIdentifier (id) values (?)][26]} 
WARN  [main]: o.h.e.j.s.SqlExceptionHelper - SQL Error: -104, SQLState: 23505
ERROR [main]: o.h.e.j.s.SqlExceptionHelper - integrity constraint violation: unique constraint or index violation; SYS_PK_10104 table: SEQUENCEIDENTIFIER
ERROR [main]: c.v.h.m.l.i.PooledSequenceIdentifierTest - Pooled optimizer threw
org.hibernate.exception.ConstraintViolationException: could not execute statementat org.hibernate.exception.internal.SQLExceptionTypeDelegate.convert(SQLExceptionTypeDelegate.java:72) ~[hibernate-core-4.3.5.Final.jar:4.3.5.Final]	
Caused by: java.sql.SQLIntegrityConstraintViolationException: integrity constraint violation: unique constraint or index violation; SYS_PK_10104 table: SEQUENCEIDENTIFIERat org.hsqldb.jdbc.JDBCUtil.sqlException(Unknown Source) ~[hsqldb-2.3.2.jar:2.3.2]

我不确定这是错误还是仅是设计限制,但是合并的优化器不满足互操作性要求。

为了可视化发生的情况,我在下图中总结了序列调用:

池优化器

优化器检索当前序列值时,它将使用它来计算最低的内存边界。 最小值是实际的先前序列值,并且该值可能已被其他一些外部INSERT语句使用。

Pool-lo优化器

幸运的是,还有另外一个要测试的优化器(参考文档中未提及)。 pool-lo优化器使用当前数据库序列值作为最低的内存边界,因此其他系统可以自由使用下一个序列值而不会冒标识符冲突的风险:

@Entity(name = "sequenceIdentifier")
public static class PooledLoSequenceIdentifier {@Id@GenericGenerator(name = "sequenceGenerator", strategy = "enhanced-sequence",parameters = {@org.hibernate.annotations.Parameter(name = "optimizer",value = "pooled-lo"),@org.hibernate.annotations.Parameter(name = "initial_value", value = "1"),@org.hibernate.annotations.Parameter(name = "increment_size", value = "5")})@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")private Long id;
}

为了更好地了解此优化器的内部工作原理,下图总结了标识符分配过程:

合并循环优化器

结论

一颗隐藏的宝石是大多数人甚至都不知道其存在的巨大特征之一。 pool-lo优化器非常有用,但是大多数人甚至都不知道它的存在。

  • 代码可在GitHub上获得 。

翻译自: https://www.javacodegeeks.com/2014/07/hibernate-hidden-gem-the-pooled-lo-optimizer.html

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

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

相关文章

vue inheritAttrs、$attrs和$listeners使用

inheritAttrs、$attrs和$listeners使用场景&#xff1a; 组件传值&#xff0c;尤其是祖孙组件有跨度的传值。 &#xff08;1&#xff09;inheritAttrs 属性说明&#xff1a;https://cn.vuejs.org/v2/api/#inheritAttrs 说明比较晦涩。 组件传值一般是通过props传值的。inhe…

鼠标滚轮事件及解决滚轮事件多次触发问题

转载&#xff1a;https://www.cnblogs.com/jjxhp/p/11736066.html#_label0 一、滚轮事件的 js 写法 二、jQuery写法 三、参考 四、滚轮事件滚动过快&#xff0c;事件触发两次 一、js //判断鼠标滚轮滚动方向 if (window.addEventListener){ //FF,火狐浏览器会识别该方法wind…

Leetcode 2976. Minimum Cost to Convert String I

Leetcode 2976. Minimum Cost to Convert String I 1. 解题思路2. 代码实现 题目链接&#xff1a;2976. Minimum Cost to Convert String I 1. 解题思路 这道题思路上其实是非常直接的&#xff0c;本质上就是给出有向图之后&#xff0c;求出有向图上任意两点之间的最短距离&…

仍不切换到Java 8的6个理由

Java 8很棒。 期。 但是……在我们有机会玩耍并玩弄它之后&#xff0c;就该退出了&#xff0c;避免吃盐。 所有的好东西都是有代价的&#xff0c;在这篇文章中&#xff0c;我将分享Java 8的主要痛点。请确保在升级和放弃7之前您已经意识到了这些痛点。 1.并行流实际上会使您减…

硬币回收价格

1957年 1分 1元1960年 1分 80元 1962年 1分 30元1965年 1分 350元1966年 1分 180元1967年 1分 350元1968年 1分 88元1969年 1分 150元1977年 1分 320元1981年 1分 5元1988年 1分 300元1989年 1分 150元1990年 1分 180元1995年 1分 0.5元1955年 2分 15元1957年 2分 2元1958年 …

13 字符串相关函数

# ### 字符串相关函数 # *capitalize 字符串首字母大写 strvar "this is a dog" res strvar.capitalize() print(res)# *title 每个单词的首字母大写 (非字母隔开的单词) strvar "this is123a dog" res strvar.title() print(res)# *upper 将所有字母变…

Vue 生命周期LIFECYCLE是8个吗?

vue生命周期钩子个数是&#xff1a;11个。 export const LIFECYCLE_HOOKS [beforeCreate,created,beforeMount,mounted,beforeUpdate,updated,beforeDestroy,destroyed,activated,deactivated,errorCaptured] github地址&#xff1a; https://github.com/vuejs/vue/blob/dev/…

鼠标滚轮切屏效果

某天发现一个网站《北京新鸿儒世纪网络技术有限公司》&#xff0c;一开始打开&#xff0c;哇&#xff0c;好简单啊&#xff0c;特别是首页&#xff0c;就一张图&#xff0c;后来发现里面有挺多小细节的&#xff0c;比如&#xff1a;做了媒体响应式、滚轮切屏&#xff08;第一次…

JavaFX技巧11:更新只读属性

自定义控件通常具有“只读”属性。 这意味着不能从控件外部进行设置&#xff0c;甚至不能从自己的皮肤类别进行设置。 通常&#xff0c;控件的行为会导致更改只读属性。 在JavaFX中&#xff0c;可以在控件本身和皮肤中实现此行为。 因此&#xff0c;有时我们最终希望通过皮肤来…

DVT和ADVT - 为数不多的DICOM测试工具说明AND下载

1、 前言做DICOM研究、开发和应用的人&#xff0c;最头疼的就是没有充分的工具和手段来进行测试&#xff0c;所以无法知道自己的程序、软件是否正确&#xff0c;能否正确地与其他设备进行DICOM连接&#xff1f;连接出错的原因在哪里&#xff1f;改正的话该从哪里下手&#xff1…

高阶函数 实现sum(2)(3) 柯里化

<!DOCTYPE html><html><head><meta charset"utf-8" /><title>高阶函数 实现sum(2)(3)</title></head><body><script type"text/javascript">function add() {var args [].slice.call(arguments);v…

设置和重置ssh key

查看本地是否有已经生成好的ssh key $ cat ~/.ssh/id_rsa.pub 若有,先删除: $ cd ~ $ rm -rf .ssh 重新生成ssh key ssh-keygen -t rsa -C "youemailexample.com" 提示输入密码或确认密码 直接全部回车即可 查看新生成的ssh key $ cat ~/.ssh/id_rsa.pub 然后获取到密…

小程序 自定义组件报错[“usingComponents“][“my-list“] 未找到

根据官网案例写了一个自定义组件&#xff0c;引入时总是报这个错误。 后面在社区里面找到了解决办法&#xff0c;把上面配置中改成&#xff1a;"my-list": "/components/my-list/my-list" 就可以了。 具体原因&#xff1a;官方文档上的自定义组件是 4 个文…

编写干净的测试–验证或不验证

在编写使用模拟对象的单元测试时&#xff0c;请遵循以下步骤&#xff1a; 配置我们的模拟对象的行为。 调用测试的方法。 验证是否已调用模拟对象的正确方法。 第三步的描述实际上有点误导&#xff0c;因为通常我们最终会验证是否调用了正确的方法以及未调用模拟对象的其他…

http 请求报文和响应报文

1、请求报文 示例&#xff1a; 2、响应报文 示例&#xff1a; 更多专业前端知识&#xff0c;请上 【猿2048】www.mk2048.com

小程序 封装table组件

实在是懒得自己封装了&#xff0c;就在网上找了一下别人封装好的&#xff0c;这里主要参考的是 灰信网上的一篇文章&#xff0c;我在他的基础上改了一下样式&#xff0c;动态生成列表每一列列宽。 表格可左右横向滑动 一、子页面 table.wxml <scroll-view class"ta…

服务器--停止启动服务,查看日志文件

停止启动服务 ./shutdown.sh 停止掉当前服务 ./startup.sh 启动当前服务 例如&#xff1a; Tomcat服务器&#xff1a;在apache-tomcat-7.0.82/bin 目录下&#xff0c;sh shutdown.sh 停止掉当前服务&#xff0c;sh startup.sh 启动当前服务 查看日志文件&#xff1a; Tomcat查看…

linq 解决winForm中控件CheckedListBox操作的问题。(转载)

1.获取CheckedListBox选中项的文本的字符串&#xff0c;并用分隔符连接。系统没有提供相应的属性&#xff0c;方法。 这里我们利用3.0的特性给其来个扩展方法,如下&#xff1a; public static stringGetCheckedItemsText(thisCheckedListBox box) { stringre…

一个在自己的线程中运行测试的JUnit规则

有时&#xff0c;能够在单独的线程中运行JUnit测试会很有帮助。 特别是在编写与封装的ThreadLocal或类似对象交互的集成测试时&#xff0c;这可能会派上用场。 单独的线程将隐式确保每次测试运行都未初始化threadlocal的与线程相关的引用。 这篇文章介绍了提供此类功能的JUnit …

linux LVS管理之keepalive

Keepalive01: ! Configuration File for keepalivedglobal_defs {notification_email { ##接收邮件的地址&#xff1b;就是说通知邮件应该发送给谁&#xff0c;通常写自己的地址rootlocalhost ##收件人&#xff0c;表示发送给本机的root用户}notification_email_from k…