Hibernate事实:如何“断言” SQL语句计数

介绍

Hibernate简化了CRUD操作,尤其是在处理实体图时。 但是任何抽象都有其代价,而Hibernate也不例外。 我已经讨论了获取策略和了解Criteria SQL查询的重要性,但是您可以做更多的事情来统治JPA。 这篇文章是关于控制Hibernate代表您调用SQL语句计数的。

在ORM工具如此流行之前,所有数据库交互都是通过显式SQL语句完成的,而优化主要针对慢速查询。

Hibernate可能会给人一种错误的印象,即您不必担心SQL语句。 这是一个错误和危险的假设。 Hibernate应该减轻域模型的持久性,而不是使您摆脱任何SQL交互。

使用Hibernate,您可以管理实体状态转换,然后转换为SQL语句。 生成SQL语句的数量受当前的获取策略,条件查询或集合映射影响,您可能并不总是能获得所需的结果。 忽略SQL语句是有风险的,最终可能会给整个应用程序性能带来沉重的负担。

我是同行评审的坚定倡导者,但这并不是发现不良的Hibernate使用情况的“必要条件”。 细微的更改可能会影响SQL语句的计数,并且在检查过程中不会引起注意。 至少,当“猜测” JPA SQL语句时,我觉得我可以使用任何其他帮助。 我要尽可能地实现自动化,这就是为什么我想出一种用于执行SQL语句计数期望的机制的原因。

首先,我们需要一种方法来拦截所有已执行SQL语句。 我对此主题进行了研究,很幸运能找到这个出色的数据源代理库。

添加自动验证器

此保护措施旨在仅在测试阶段运行,因此我将其专门添加到“集成测试”弹簧上下文中。 我已经讨论过Spring bean别名 ,现在正是使用它的合适时机。

<bean id="testDataSource" class="bitronix.tm.resource.jdbc.PoolingDataSource" init-method="init"destroy-method="close"><property name="className" value="bitronix.tm.resource.jdbc.lrc.LrcXADataSource"/><property name="uniqueName" value="testDataSource"/><property name="minPoolSize" value="0"/><property name="maxPoolSize" value="5"/><property name="allowLocalTransactions" value="false" /><property name="driverProperties"><props><prop key="user">${jdbc.username}</prop><prop key="password">${jdbc.password}</prop><prop key="url">${jdbc.url}</prop><prop key="driverClassName">${jdbc.driverClassName}</prop></props></property>
</bean><bean id="proxyDataSource" class="net.ttddyy.dsproxy.support.ProxyDataSource"><property name="dataSource" ref="testDataSource"/><property name="listener"><bean class="net.ttddyy.dsproxy.listener.ChainListener"><property name="listeners"><list><bean class="net.ttddyy.dsproxy.listener.CommonsQueryLoggingListener"><property name="logLevel" value="INFO"/></bean><bean class="net.ttddyy.dsproxy.listener.DataSourceQueryCountListener"/></list></property></bean></property>
</bean><alias name="proxyDataSource" alias="dataSource"/>

新的代理数据源将装饰现有数据源,从而拦截所有已执行SQL语句。 该库可以记录所有SQL语句以及实际参数值,这与默认的Hibernate记录不同,该记录只显示一个占位符。

验证器的外观如下:

public class SQLStatementCountValidator {private SQLStatementCountValidator() {}/*** Reset the statement recorder*/public static void reset() {QueryCountHolder.clear();}/*** Assert select statement count* @param expectedSelectCount expected select statement count*/public static void assertSelectCount(int expectedSelectCount) {QueryCount queryCount = QueryCountHolder.getGrandTotal();int recordedSelectCount = queryCount.getSelect();if(expectedSelectCount != recordedSelectCount) {throw new SQLSelectCountMismatchException(expectedSelectCount, recordedSelectCount);}}/*** Assert insert statement count* @param expectedInsertCount expected insert statement count*/public static void assertInsertCount(int expectedInsertCount) {QueryCount queryCount = QueryCountHolder.getGrandTotal();int recordedInsertCount = queryCount.getInsert();if(expectedInsertCount != recordedInsertCount) {throw new SQLInsertCountMismatchException(expectedInsertCount, recordedInsertCount);}}/*** Assert update statement count* @param expectedUpdateCount expected update statement count*/public static void assertUpdateCount(int expectedUpdateCount) {QueryCount queryCount = QueryCountHolder.getGrandTotal();int recordedUpdateCount = queryCount.getUpdate();if(expectedUpdateCount != recordedUpdateCount) {throw new SQLUpdateCountMismatchException(expectedUpdateCount, recordedUpdateCount);}}/*** Assert delete statement count* @param expectedDeleteCount expected delete statement count*/public static void assertDeleteCount(int expectedDeleteCount) {QueryCount queryCount = QueryCountHolder.getGrandTotal();int recordedDeleteCount = queryCount.getDelete();if(expectedDeleteCount != recordedDeleteCount) {throw new SQLDeleteCountMismatchException(expectedDeleteCount, recordedDeleteCount);}}
}

该实用程序与JPA和MongoDB乐观并发控制重试机制一起,是我的db-util项目的一部分。

由于它已经在Maven Central Repository中提供,因此只需将以下依赖项添加到pom.xml中就可以轻松使用它:

<dependency><groupId>com.vladmihalcea</groupId><artifactId>db-util</artifactId><version>0.0.1</version>
</dependency>

让我们写一个测试来检测臭名昭著的N + 1选择查询问题 。

为此,我们将编写两种服务方法,其中一种受到上述问题的影响:

@Override
@Transactional
public List<WarehouseProductInfo> findAllWithNPlusOne() {List<WarehouseProductInfo> warehouseProductInfos = entityManager.createQuery("from WarehouseProductInfo", WarehouseProductInfo.class).getResultList();navigateWarehouseProductInfos(warehouseProductInfos);return warehouseProductInfos;
}@Override
@Transactional
public List<WarehouseProductInfo> findAllWithFetch() {List<WarehouseProductInfo> warehouseProductInfos = entityManager.createQuery("from WarehouseProductInfo wpi " +"join fetch wpi.product p " +"join fetch p.company", WarehouseProductInfo.class).getResultList();navigateWarehouseProductInfos(warehouseProductInfos);return warehouseProductInfos;
}private void navigateWarehouseProductInfos(List<WarehouseProductInfo> warehouseProductInfos) {for(WarehouseProductInfo warehouseProductInfo : warehouseProductInfos) {warehouseProductInfo.getProduct();}
}

单元测试非常简单,因为它遵循与任何其他JUnit断言机制相同的编码风格。

try {SQLStatementCountValidator.reset();warehouseProductInfoService.findAllWithNPlusOne();assertSelectCount(1);
} catch (SQLSelectCountMismatchException e) {assertEquals(3, e.getRecorded());
}SQLStatementCountValidator.reset();
warehouseProductInfoService.findAllWithFetch();
assertSelectCount(1);

我们的验证器适用于所有SQL语句类型,因此让我们检查以下服务方法正在执行多少个SQL INSERT:

@Override
@Transactional
public WarehouseProductInfo newWarehouseProductInfo() {LOGGER.info("newWarehouseProductInfo");Company company = entityManager.createQuery("from Company", Company.class).getResultList().get(0);Product product3 = new Product("phoneCode");product3.setName("Phone");product3.setCompany(company);WarehouseProductInfo warehouseProductInfo3 = new WarehouseProductInfo();warehouseProductInfo3.setQuantity(19);product3.addWarehouse(warehouseProductInfo3);entityManager.persist(product3);return warehouseProductInfo3;
}

验证器看起来像:

SQLStatementCountValidator.reset();
warehouseProductInfoService.newWarehouseProductInfo();
assertSelectCount(1);
assertInsertCount(2);

让我们检查一下测试日志,以使自己确信其有效性:

INFO  [main]: o.v.s.i.WarehouseProductInfoServiceImpl - newWarehouseProductInfo
Hibernate: select company0_.id as id1_6_, company0_.name as name2_6_ from Company company0_
INFO  [main]: n.t.d.l.CommonsQueryLoggingListener - Name:, Time:1, Num:1, Query:{[select company0_.id as id1_6_, company0_.name as name2_6_ from Company company0_][]}
Hibernate: insert into WarehouseProductInfo (id, quantity) values (default, ?)
INFO  [main]: n.t.d.l.CommonsQueryLoggingListener - Name:, Time:0, Num:1, Query:{[insert into WarehouseProductInfo (id, quantity) values (default, ?)][19]}
Hibernate: insert into Product (id, code, company_id, importer_id, name, version) values (default, ?, ?, ?, ?, ?)
INFO  [main]: n.t.d.l.CommonsQueryLoggingListener - Name:, Time:0, Num:1, Query:{[insert into Product (id, code, company_id, importer_id, name, version) values (default, ?, ?, ?, ?, ?)][phoneCode,1,-5,Phone,0]}

结论

代码审查是一种很好的技术,但是在大规模开发项目中还远远不够。 这就是为什么自动检查至关重要。 一旦编写了测试,您可以放心,将来的任何更改都不会破坏您的假设。

  • 代码可在GitHub上获得 。

参考: Hibernate Fact:如何通过Vlad Mihalcea的Blog博客从我们的JCG合作伙伴 Vlad Mihalcea “断言” SQL语句计数 。

翻译自: https://www.javacodegeeks.com/2014/02/hibernate-facts-how-to-assert-the-sql-statement-count.html

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

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

相关文章

交换机工作原理介绍

交换机是一种用于电&#xff08;光&#xff09;信号转发的网络设备。它可以为接入交换机的任意两个网络节点提供独享的电信号通路。最常见的交换机是以太网交换机。交换机工作于OSI参考模型的第二层&#xff0c;即数据链路层。交换机拥有一条高带宽的背部总线和内部交换矩阵&am…

【渝粤教育】电大中专金融与税收作业 题库

1.根据马克思的货币需要量公式&#xff0c;在货币流通速度不变的条件下&#xff0c;执行流通手段的货币量取决于&#xff08;&#xff09;。 A.商品质量 B.商品生产技术条件 C.待销售商品价格总额 D.投机性货币需求 错误 正确答案&#xff1a;左边查询 学生答案&#xff1a;A 2…

下载不了java应用程序_Java 7u45 - java webstart不会下载我的jar并执行应用程序,除非我显示java控制台...

首先&#xff0c;对不起我的英语&#xff0c;这不是我的母语。我的环境有&#xff1a;- jre 1.5.0_12(二进制)- jre 1.6.0_17(默认jre)- jre 1.7.0_45(二进制)我有两种方法可以通过Java Webstart启动应用程序&#xff1a;1)\\\javaws-1.5.0_12.exe \\\urClient-DAP2.jnlp2)&quo…

【渝粤题库】陕西师范大学500011 物理学史 作业(专升本)

《物理学史》作业 一、名词解释 1、伽利略“等末速度假设” 2、卡诺理想热机 3、光量子假设 4、阿拉果圆盘实验 5、活力守恒定律 6、牛顿主张的光的微粒说 7、卡诺提出的理想循环过程 8、法拉第圆盘实验 9、卡文迪许测量G的实验 10、卡诺定理 11、惠更斯原理 12、热质说 13、无…

将应用程序集成为Heroku附加组件

Heroku是受欢迎的平台即服务提供商&#xff0c;它为供应商提供了作为附件提供的选项。 Heroku客户可以以不同的方式使用加载项&#xff0c;但是典型的情况是“启动数据库”&#xff0c;“启动MQ”或“启动日志记录解决方案”。 将附加组件添加到您的帐户后&#xff0c;您可以连…

bitmap的java原理_布隆算法的原理及JAVA实现

Bloom Filter是由Bloom在1970年提出的一种多哈希函数映射的快速查找算法。通常应用在一些需要快速判断某个元素是否属于集合&#xff0c;但是并不严格要求100%正确的场合。Bloom Filter是一种空间效率很高的随机数据结构&#xff0c;它利用位数组很简洁地表示一个集合&#xff…

[渝粤教育] 中国地质大学 自动控制原理 复习题

《自动控制原理》模拟题 一.单选题 1.当输入为单位斜坡且系统为单位反馈时对于II型系统其稳态误差为() A.0 B.0.1/k C.1/k D.无穷大 2.I型系统开环对数幅频特性的低频段斜率为() A.-40(dB/dec) B.-20(dB/dec) C.0(dB/dec) D.20(dB/dec) 3.当输入为单位斜坡且系统为单位反馈时…

什么是语音复用设备?

语音复用设备是一种小容量、多业务的复用及传输设备&#xff0c;它能为用户提供综合的通信功能&#xff0c;满足用户对电话、数据以及计算机网络连接的实际需要。它的多种传输方式使其能灵活的应用在各种通信网络中&#xff1a;可以作为光电一体化综合通信业务接入设备&#xf…

[渝粤教育] 中国地质大学 金融保险业会计 复习题 (2)

《金融保险会计》模拟题 单选题 1.下列不符合外汇分账制基本要求的有(). A.对各种外币的收付凡有人民币牌价的平时都按原币填制凭证登记账簿编制报表 B.对各种外币的收付凡有人民币牌价的平时都按人民币填制凭证登记账簿编制报表 C.设置”外汇买卖”科目 D.各种外币分别设置一…

截断整型提升算数转换

文章目录 &#x1f680;前言&#x1f680;截断&#x1f680;整型提升✈️整型提升是怎样的 &#x1f680;算术转换 &#x1f680;前言 大家好啊&#xff01;这里阿辉补一下前面操作符遗漏的地方——截断、整型提升和算数转换 看这一篇要先会前面阿辉讲的数据的存储否则可能看不…

java如何通过grpc连接etcd_grpc通过 etcd 实现服务发现与注册-源码分析

介绍下面介绍 jupiter-0.2.7 版本中 grpc 通过 etcd 实现服务发现与注册。服务发现与注册的实现解析服务注册服务注册的流程图&#xff1a;etcd的服务注册代码模块在 jupiter/pkg/registry/etcdv3 中。下面让我们来看看实际的代码// Registry register/unregister service// re…

视频光端机各种视频接口的传输距离是多少?

视频光端机将1到多路的模拟视频信号通过各种编码转换成光信号通过光纤介质进行远距离传输。那么&#xff0c;对于视频光端机的各种视频接口以及传输距离你是否详细了解过呢&#xff1f;接下来我们就跟随飞畅科技的小编一起来看看吧&#xff01; 一、视频信号接口  1.监控视频…

[渝粤教育] 中国地质大学 面向对象程序设计 复习题

《面向对象程序设计》模拟题 一.单选题 1.如果一个类中包含纯虚函数则该类称为(). A.抽象类 B.虚基类 C.派生类 D.子类 2.在类中将show声明为不带返回值的纯虚函数则正确的写法是(). A.virtual void show()0; B.virtual show()0; C.virtual void show(); D.void show()0 virtu…

spring jms 事务_Spring JMS:处理事务中的消息

spring jms 事务1.引言 这篇文章将向您展示使用JMS异步接收消息期间使用者执行过程中的错误如何导致消息丢失。 然后&#xff0c;我将解释如何使用本地事务解决此问题。 您还将看到这种解决方案在某些情况下可能导致消息重复&#xff08;例如&#xff0c;当它将消息保存到数据…

[渝粤教育] 西南科技大学 智能交通系统 在线考试复习资料

智能交通系统——在线考试复习资料 一、单选题 1.运用多种方式将路线优化结果告知用户的过程称为( )。 A.数据挖掘 B.路线诱导 C.模式识别 D.预测分析 2.( )是根据国家现行财税制度和借个体系,分析、计算投资者或项目直接发生的财务效益和费用,编制财务报表,计算评价指标,考察…

php 脏数据,使用 PHP Masked Package 屏蔽敏感数据

Fuko \ Masked 是 Kaloyan Tsvetkov 的一个小型 PHP 库&#xff0c;用于通过用编辑后的元素替换列入黑名单的元素来屏蔽敏感数据。以下是 软件包 readme 的基本用法示例&#xff1a;use Fuko\Masked\Protect;//隐藏$secret_key var中的值Protect::hideValue($secret_key);//隐藏…

视频数据复用光端机故障排除方法

数字光端机是一种通过数字电路控制光信号&#xff0c;使用类似于0、1代码来实现光通信的机器&#xff0c;广泛应用于光纤通信等领域。那么&#xff0c;我们在使用数据光端机的时候&#xff0c;如果遇到故障该如何来解决呢&#xff1f;接下来我们就跟随飞畅科技的小编一起来详细…

[渝粤教育] 西南科技大学 电子商务原理及应用 在线考试复习资料(1)

电子商务原理及应用——在线考试复习资料 一、单选题 1.( )接受商家的送货要求,将商品送到消费者手中。 A.邮局 B.快递公司 C.送货公司 D.物流中心 2.卓越属于( )类型的B2C电子商务企业: A.经营着离线商店的零售商 B.没有离线商店的虚拟零售企业 C.商品制造商 D.网络交易服务公…

使用AWS Lambda,S3和AWS CloudFront进行动态内容缓存

快速提供内容对于任何网站或应用程序具有更好的客户体验至关重要。 如果您将网站或应用程序托管在AWS Cloud中&#xff0c;那么无论从何处访问应用程序&#xff0c;都可以以较低的延迟快速提供内容。 AWS提供了CloudFront服务&#xff0c;用于将内容缓存在每个用户地理位置本地…

[渝粤教育] 西南科技大学 组织行为学 在线考试复习资料

组织行为学——在线考试复习资料 一、单选题 1.( )是指一个团队的综合情绪控制调节能力。 A.团队学习 B.团队情商 C.团队成员角色 D.团队创建 2.在沟通过程中,由信息发送者选择来向接收者传送信息的媒介物,叫( )。 A.编码 B.解码 C.反馈 D.通道 3.组织风俗属于组织文化的( )。…