文档章节

高性能 Java 持久化的 14 个技巧

编辑部的故事
 编辑部的故事
发布于 2017/11/13 18:11
字数 2135
阅读 3892
收藏 146

一个高性能的数据访问层需要大量关于数据库内部、JDBC、JPA、Hibernate的知识,本文总结了一些可用来优化企业应用程序的重要的技术。

1. SQL语句日志

如果您用了生成符合自己使用习惯的语句的框架,则应始终验证每个语句的有效性和效率。测试时使用断言机制验证更好,因为即使在提交代码之前,也可以捕获N + 1个查询问题。

2.连接管理

数据库的连接开销非常大,因此您应该始终使用连接池机制。

由于连接数由底层数据库集群的功能给出,所以您需要尽可能快地释放连接。

在性能调优中,你总是要测量、设置出正确的连接池,池的大小又是差不多的。 但像FlexyPool这样工具可以帮助您找到合适的大小,即使您已经将应用程序部署到生产环境中。

3.JDBC批处理

JDBC批处理允许我们在单个数据库往返中发送多个SQL语句。性能增益在驱动程序和数据库端都很重要。PreparedStatements 非常适合批处理,而某些数据库系统(例如 Oracle)仅支持用于预处理语句的批处理。

由于JDBC为批处理定义了独特的API(例如PreparedStatement.addBatch和PreparedStatement.executeBatch),如果您手动生成语句,那么您应该从一开始就知道是否应该使用批处理。 使用Hibernate,您可以切换到使用单个配置的批处理。

Hibernate 5.2 提供了会话级别的批处理,所以在这方面更加灵活。

4.语句缓存

语句缓存是您可以轻松利用的最鲜为人知的性能优化之一。 根据基础的JDBC驱动程序,可以在客户端(驱动程序)或数据库端(语法树甚至执行计划)上缓存PreparedStatements。

5.Hibernate 标识符

当使用Hibernate时,IDENTITY生成器不是一个好的选择,因为它禁用了JDBC批处理。

TABLE生成器更糟糕,因为它使用一个单独的事务来获取新的标识符,这会对底层事务日志以及连接池造成压力,因为每次我们需要一个新的标识符时都需要单独的连接。

SEQUENCE是正确的选择,甚至从2012版本就开始支持SQL Server。对于SEQUENCE标识符,Hibernate一直提供优化器,如 pooled 或 pooled-lo,这可以减少获取新的实体标识符值所需的数据库往返次数。

6.选择正确的列类型

您应该始终在数据库端使用正确的列类型。 列类型越紧凑,数据库工作集中可容纳的条目越多,索引将更好地适应于内存。 为此,您应该利用特定于数据库的类型(例如PostgreSQL中的IPv4地址的inet),尤其是在实现新自定义类型时,Hibernate非常灵活。

7 .关系

Hibernate 带有许多关系映射类型,但并不是所有的关系映射类型在效率上都是相等的。

应该避免单向集合和 @ManyToMany 列表。如果您确实需要使用实体集合,则首选双向 @OneToMany关联。对于 @ManyToMany 关系,使用 Set(s),因为在这种情况下它们更高效,或者简单地映射链接的多对多表,并将 @ManyToMany 关系转换为两个双向的 @OneToMany 关联。

然而,与查询不同,集合不够灵活,因为它们不易分页,这意味着当子关联的数量相当高时,我们不能使用它们。出于这个原因,你应该考虑一个集合是否真的有必要。 在许多情况下,实体查询可能是更好的选择。

8.继承

就继承而言,面向对象语言和关系数据库之间的不匹配变得更加明显。 JPA提供了SINGLE_TABLE,JOINED和TABLE_PER_CLASS来处理继承映射,每个策略都有其优缺点。

SINGLE_TABLE在SQL语句方面表现最好,但由于我们不能使用NOT NULL约束,所以我们在数据完整性方面失败了。

当同时提供更复杂的语句时,JOINED采用数据完整性限制。 只要你不使用基本类型的多态查询或@OneToMany关联,这个策略就没有问题。 它的真正的作用在于对数据访问层上由策略模式支持的多态@ManyToOne关联。

应该避免使用TABLE_PER_CLASS,因为它不会生成有效的SQL语句。

9.持久性上下文的大小

在使用 JPA 和 Hibernate 时,应该始终关注持久性上下文的大小。 出于这个原因,您不应该过多地使用托管实体。 通过限制托管实体的数量,我们可以获得更好的内存管理,并且默认的检查机制也将更加高效。

10.只抓取必要的东西

获取太多的数据可能是导致数据访问层性能出问题的首要原因。 一个问题是,即使是只读的 Projections,实体查询也是专用的。

DTO projections更适合于获取自定义视图,而实体只能在业务流需要修改时才能获取。

EAGER抓取是最糟糕的,您应该避免反模式(Anti-Pattern),例如 Open-Session in View

11.高速缓存

关系数据库系统使用许多内存缓冲区结构来避免磁盘访问。 数据库缓存经常被忽视。 我们可以通过适当调整数据库引擎来显着降低响应时间,以便工作集驻留在内存中,而不是一直从磁盘中获取。

应用程序级缓存对于许多企业应用程序来说是不可选的。 应用程序级缓存可以减少响应时间,同时为数据库关闭以进行维护或由于某些严重系统故障提供只读辅助存储库。

二级缓存对于减少读写事务响应时间非常有用,特别是在主从复制体系结构中。 根据应用程序的要求,Hibernate允许你在READ_ONLYNONSTRICT_READ_WRITEREAD_WRITETRANSACTIONAL之间进行选择。

12.并发控制

在性能和数据完整性方面,事务隔离级别的选择是非常重要的。 对于多请求Web流程,为避免丢失更新,您应该对分离的实体或 EXTENDED 持久性上下文使用 optimistic 锁定。

为避免optimistic locking误报,您可以使用无版本 optimistic 并发控制或基于读写的属性集来拆分实体。

13.释放数据库查询功能

仅仅因为您使用JPA或Hibernate,并不意味着您不应该使用原生查询。 您应该利用窗口函数,CTE(公用表表达式),CONNECT BY,PIVOT 查询。

这些构造允许您避免获取太多的数据,以便稍后在应用程序层进行转换。 如果可以让数据库进行处理,那么只能获取最终结果,因此可以节省大量的磁盘I / O和网络开销。 为避免主节点重载,可以使用数据库复制和拥有多个从属节点,这样数据密集型的任务就会在从属节点而不是主节点上执行。

14.横向扩展和纵向扩展

关系数据库的伸缩性非常好。如果Facebook、Twitter、Pinterest或StackOverflow可以扩展他们的数据库系统,那么很有可能您可以将企业应用程序扩展到其特定的业务需求。

数据库复制和分片是提高吞吐量的很好的方法,您应该完全可以利用这些经过测试的架构模式来扩展您的企业应用程序。

结论

高性能数据访问层必须与底层数据库系统互相响应。 了解关系数据库和正在使用的数据访问框架的内部工作原理可以使企业高性能应用程序和几乎没有crawls的应用程序之间产生差异。

原文:https://vladmihalcea.com/2016/06/28/14-high-performance-java-persistence-tips/

© 著作权归作者所有

共有 人打赏支持
编辑部的故事

编辑部的故事

粉丝 1142
博文 248
码字总数 430631
作品 0
深圳
运营/编辑
加载中

评论(4)

MGL_ONE
MGL_ONE
good
AkataMoKa
AkataMoKa
9.持久性上下文的大小
里面提到的“托管实体”,是什么东西?
g
gm100861
hibernate软文
神之音
神之音
涉及hibernate的偏多~
Hibernate.Everything data

Hibernate.Everything data Hibernate ORM:关系数据库域模型持久化 Hibernate Search:全文检索域模型 Hibernate Validator:基于域模型注解约束 Hibernate OGM:Nosql数据库域模型持久化 Hibe...

Rksi5
2014/10/09
0
0
编写高性能 Java 代码的最佳实践

摘要:本文首先介绍了负载测试、基于APM工具的应用程序和服务器监控,随后介绍了编写高性能Java代码的一些最佳实践。最后研究了JVM特定的调优技巧、数据库端的优化和架构方面的调整。以下是译...

这篇文章
06/20
0
0
程序运行时,对象是怎么进行放置的呢?特别是内存是怎么分配的呢?对这些方面的了解会对你有很大的帮...

1)寄存器. 这是很宽的存储区,因为它位于不同于其他存储区的地方----处理器内部.但是寄存器的数量汲取有限,所以寄存器根据需求进行分配.你不能直接控制,也不能在程序中感觉到寄存器的存在的任...

深山
2012/11/23
0
0
怎样写出高性能的 Java 代码?

在这篇文章中,我们将讨论几个有助于提升Java应用程序性能的方法。我们首先将介绍如何定义可度量的性能指标,然后看看有哪些工具可以用来度量和监控应用程序性能,以及确定性能瓶颈。 我们还...

程序员之家_
08/24
0
0
提示你Hibernate4开发能力的17个技巧

设计细颗粒度的持久类并且使用<component>来实现映射。 例如使用一个Address持久类来封装 street, suburb, state, postcode. 这将有利于代码重用和简化代码重构(refactoring)的工作。 对持久...

chromeplugin
2012/08/14
0
0

没有更多内容

加载失败,请刷新页面

加载更多

《Netkiller Java 手札》· 二进制文件操作大全

本文节选自《Netkiller Java 手札》 Netkiller Java 手札 Mr. Neo Chan, 陈景峯(BG7NYT) 中国广东省深圳市望海路半岛城邦三期 518067 +86 13113668890 <netkiller@msn.com> $Id: book.xml 6......

netkiller-
13分钟前
0
0
Fiddler Debugger post请求

常用的两种: 第一种默认的 对应URL为www 的要用请求头为:Content-Type: application/x-www-form-urlencoded 请求参数为 :param1=1234¶m2=12345 注:有些接口是指定用这种的第二方式并不...

轻量级赤影
21分钟前
1
0
如何搭建母婴亲子类知识社区

近期社交领域融资动作频繁,海尔高管、海尔医疗有限公司总裁管礼庆创办的母婴知识分享社区平台Alwayslove于上月获得700万天使轮融资。 Alwayslove是一个母婴知识分享社区平台,采用UGC模式,...

ThinkSNS账号
23分钟前
0
0
Android 自定义构建类型 BuildType

最近接触到自定义构建类型 BuildType,发现这一块有些地方稍不注意的话会被绕进去浪费点时间,既然我这边已经花费时间了,如果正好你也需要接触到 BuildType,也许接下来分享的 tips 可能会帮...

猴亮屏
24分钟前
1
0
美团点评基于 Flink 的实时数仓建设实践

引言 近些年,企业对数据服务实时化服务的需求日益增多。本文整理了常见实时数据组件的性能特点和适用场景,介绍了美团如何通过 Flink 引擎构建实时数据仓库,从而提供高效、稳健的实时数据服...

美团技术团队
27分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部