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

Introduction

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

SQL Statement Logging:SQL语句日志

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

Connection management:链接管理

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

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, 也是很是方便的。json

Statement Caching:语句缓存

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

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这些大公司都扩展了数据库系统:

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

相关文章
相关标签/搜索