资讯专栏INFORMATION COLUMN

构建高性能Java持久层的14个建议

shenhualong / 1397人阅读

摘要:系列文章地址原文地址一个高性能的数据访问层需要很多关于数据库的内部结构以及很多优化商业应用的技术建议。在语句中的表现最好,不过不能使用约束,数据完整性的控制较差。应用层的缓存则利用高速副本的方式来保证低响应时间。

Github系列文章地址

原文地址

Introduction

一个高性能的数据访问层需要很多关于数据库的内部结构、JDBC、JPA、Hibernate以及很多优化商业应用的技术建议。

SQL Statement Logging:SQL语句日志

如果你正在使用譬如Hibernate或者MyBatis这样的ORM框架,那么可以参考验证执行语句的效率。另外推荐一个 测试中断言机制 可以帮你在提交代码之前就发现很多的查询问题。

Connection management:连接管理

数据库连接一直是数据库中比较耗时的操作,因此建议是务必使用数据库连接池 机制。另外,数据库连接还受到数据库底层的限制,因此也需要合理有效地释放无用的数据库连接。在性能调优中,我们经常需要测试并且设置合理的连接池大小。这里推荐一个FlexyPool工具可以帮助你选择生产环境下合适的连接池大小。

JDBC Batching:批量JDBC操作

JDBC Batching允许在单次数据库连接中发送多个SQL语句。这篇博客里进行了对比可以看出Batch操作的性能提升非常巨大 ,无论是在客户端还是数据库端。 PreparedStatements 是不错的用于Batching操作的选择,像Oracle也仅支持基于PreparedStatements的Batching操作。

JDBC中已经基于PreparedStataement.addBatchPreparedStataement.executeBatch)提供了Batching操作的辅助,不过如果打算手动的构造Batching操作,那么在设计阶段就要考虑到是否需要引入Batching。如果你用的是Hibernate,那么可以用简单的配置就开启Batching,Hibernate 5.2 提供了 Session级别的Batching, 也是非常方便的。

Statement Caching:语句缓存

Statement Caching算是最不常用的几种优化手段之一了,你可以利用PreparedStatements同时在客户端(Driver)或者数据库端同时缓存语句。

Hibernate Identifiers

如果你是使用Hibernate作为ORM工具,那么IDENTITY生成器可能会影响到你的性能,因为它会禁止掉JDBC Batching。Table生成器也不是啥好选择,它会使用独立的事务上下文进行捕获操作,而导致底层的事务日志承受额外的压力,并且导致了每次连接池中的新的请求都需要一个新的Identifier。因此笔者还是推荐SEQUENCE生成器,SQL Server在2012版本之后也开始支持了该生成器。

选择合适的列类型

在数据库设计的时候,我们应该尽可能地选用合适的列类型,这样可以让你的数据库以最合适的方式去索引存储你的数据。譬如在PostgreSQL中你应该使用inet来存放IPv4的地址,特别是Hibernate还允许你自定义数据类型,这样方面和数据库中的列类型一一对应。

Relationships:映射关联

Hibernate提供了很多的关系映射,不过并不是所有的映射都是性能优化的。

我们在开发的过程中需要注意避免单向的关系映射,以及@ManyToMany这种映射。对于集合查询而言,双向的@OneToMany关系才是值得推荐的。

Inheritance:继承

继承是面向对象的语言中的不可或缺的一部分,但这也是关系型数据库与面向对象的语言之间的不协调最甚的地方。JPA提供了譬如SINGLE_TABLEJOIN以及TABLE_PER_CLASS来处理继承映射的问题,而这几个办法都是各有千秋。

SINGLE_TABLE在SQL语句中的表现最好,不过不能使用NOT NULL约束,数据完整性的控制较差。

JOIN 通过更复杂的语句控制来保证了数据的完整性,只要你不使用多态查询或者@OneToMany关系注解,那一切还好。

应该避免使用TABLE_PER_CLASS,它基本上无法生成高效的SQL语句。

Persistence Context Size:持久化上下文的大小

在使用JPA或者Hibernate时候,应该随时注意持久化上下文的大小,避免同时管理过多的实体类。通过限制受管实体类的数量,我们可以更好地进行内存管理,而默认的脏检测机制也会有更好的效果。

只获取必要的数据

获取过多的冗余数据可能是导致数据访问层性能下降的原因之一,即使是包含了投影等操作,对于实体的查询应该也是排外的,即不会引入冗余数据的。我们应该只获取那些业务逻辑需要到的数据,这里推荐使用DTO Projections。过早的数据获取以及Open Session In View这种反模式都是要被避免的。

Caching:缓存

关系型数据库使用了很多的内存缓冲结构体来避免大量的磁盘访问,但是我们往往忽略了数据库缓存。我们可以通过调整数据库查询引擎,将更多的内容留于内存中以避免磁盘查询最终明显的减少响应耗时。应用层的缓存则利用高速副本的方式来保证低响应时间。而Second-Level缓存能够有效减少读写事务的响应时间,特别是在主从复制架构中。根据不同的应用取钱,Hibernate提供了 READ_ONLY, NONSTRICT_READ_WRITE, READ_WRITE, 以及 TRANSACTIONAL这几种方式。

Concurrency Control:并发控制

在考虑性能和数据完整性的时候,事务隔离层 就变得至关重要。对于并发较高的应用,需要避免更新失败, 可以使用 乐观锁或者扩展的持久化上下文.

而为了避免 乐观锁中的 false positives, 可以使用 无版本的乐观控制或者基于写属性集的实体划分.

提高数据库查询能力

虽然你是用了JPA或者Hibernate,但是你可以用一些原生查询,建议是好好利用Window Functions, CTE (Common Table Expressions), CONNECT BY, PIVOT等等。这些工具能够避免你一次性传输过多的数据进入应用层,如果你可以把这个操作托付给数据库层进行,那么可以仅关心最终的结果,从而节约了磁盘IO与网络带宽。

集群扩展

关系型数据库能够方便地进行扩展,像Facebook、Twitter、Pinterest这些大公司都扩展了数据库系统:

数据副本与分片是两种常用的增加吞吐量的扩展方式,你应该合理的组合应用这些方式从而提高你的商业应用的能力。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/64865.html

相关文章

  • 技术选型之Docker容器引擎

    摘要:是系统提供的容器化技术,简称,它结合和技术为用户提供了更易用的接口来实现容器化。公司结合和以下列出的技术实现了容器引擎,相比于,具备更加全面的资源控制能力,是一种应用级别的容器引擎。 showImg(https://segmentfault.com/img/bVbtPbG?w=749&h=192); 题外话   最近对Docker和Kubernetes进行了一番学习,前两天做了一次技术...

    monw3c 评论0 收藏0
  • 牛人给Java初学者的建议(必看篇)

    摘要:从不知为何物到现在一个小小的项目经理虽说不上此道高手,大概也算有点斤两了吧每次上网,泡逛论坛,没少去相关的版面总体感觉初学者多,高手少,精通的更少由于我国高等教育制度教材陈旧,加上自身发展不过十年左右的时间还有一个很重要的原因就是这门语言更 从不知java为何物到现在一个小小的j2ee项目经理虽说不上此道高手,大概也算有点斤两了吧每次上网,泡bbs逛论坛,没少去java相关的版 面总体...

    JayChen 评论0 收藏0
  • 微服务框架lagom

    摘要:在这种情况下,每一个微服务定义一个限界上下文,类似于领域驱动的限界上下文。设计你的微服务系统的响应式微服务架构这本书对于微服务系统架构很有帮助。 1.Lagom概念介绍 lagom框架包含一系列的可以支持我们从开发到部署的库以及开发环境: >在开发阶段,可以通过一个简单的命令构建我们的项目,启动所有你的服务,并且可以支持所有的lagom基础设置层。当你修改了代码,logom是有热加载的...

    Michael_Lin 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<