前言
HikariCP数据源简介;数据层HikariCP与MyBatis整合;MyBatis逆向生成工具;SpringBoot整合mybatis-pagehelper。
一、HikariCP数据源
1.1 简述
HikariCP:光中它更快。嗨·卡·里 [嗨·卡··lē](产地:日语):光;射线。
SpingBoot由1.X升级为2.X,默认的数据源发生更改,选用HikariCP作为默认数据源。
快速、简单、可靠。HikariCP 是一个“零开销”生产就绪的 JDBC 连接池。大约130Kb,库非常轻。在这里https://github.com/brettwooldridge/HikariCP了解下如何做到这一点。
与其他 JDBC 操作相比,操作数很少。大量的性能提升来自于包装 、等的“委托”的优化。getConnection()ConnectionStatement
1.2 微优化
HikariCP包含许多微观优化,这些优化本身几乎无法测量,但共同提高整体性能。其中一些优化是在数百万次调用中摊销的几分之一毫秒来衡量的。
- ArrayList
一个不平凡的(性能方面)优化是:不再使用ArrayList在ConnectionProxy用于跟踪开放实例Statement的实例。当关闭Statement时,必须将其从此Connection中删除,关闭时,必须迭代集合并关闭所有打开的Statement实例,最后必须清除该集合。ArrayList用于通用用途,在每次调用get(int index)时执行范围检查。但是,由于可以提供有关范围的保证,因此此检查只是开销。
此外,该remove(Object)实现从头到尾执行扫描,但是JDBC编程中的常见模式是在使用后立即关闭语句,或者以相反的打开顺序关闭语句。对于这些情况,从尾部开始的扫描将表现得更好。因此,ArrayList被替换为自定义类FastList,该类消除了范围检查并执行从尾到头的删除扫描。
- ConcurrentBag
HikariCP包含一个名为ProcurrentBag的自定义无锁集合。这个想法是从C# .NET ConcurrentBag类中借用的,但内部实现完全不同。ConcurrentBag 提供:
- 无锁设计
- 线程本地缓存
- 队列窃取
- 直接交接优化
…从而实现高度并发、极低的延迟,并最大限度地减少错误共享的发生。
- 调用:vsinvokevirtual vs invokestatic
为了生成连接、语句和 ResultSet 实例的代理,HikariCP 最初使用单例工厂,在 静态字段 (PROXY_FACTORY) 的情况下保存ConnectionProxy。
有十几种类似于以下内容的方法:
public final PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException
{
return PROXY_FACTORY.getProxyPreparedStatement(this, delegate.prepareStatement(sql, columnNames));
}
使用原始的单例工厂,生成的字节码如下所示:
public final java.sql.PreparedStatement prepareStatement(java.lang.String, java.lang.String[]) throws java.sql.SQLException;
flags: ACC_PRIVATE, ACC_FINAL
Code:
stack=5, locals=3, args_size=3
0: getstatic #59 // Field PROXY_FACTORY:Lcom/zaxxer/hikari/proxy/ProxyFactory;
3: aload_0
4: aload_0
5: getfield #3 // Field delegate:Ljava/sql/Connection;
8: aload_1
9: aload_2
10: invokeinterface #74, 3 // InterfaceMethod java/sql/Connection.prepareStatement:(Ljava/lang/String;[Ljava/lang/String;)Ljava/sql/PreparedStatement;
15: invokevirtual #69 // Method com/zaxxer/hikari/proxy/ProxyFactory.getProxyPreparedStatement:(Lcom/zaxxer/hikari/proxy/ConnectionProxy;Ljava/sql/PreparedStatement;)Ljava/sql/PreparedStatement;
18: return
可以看到,首先有一个getstatic调用来获取静态字段PROXY_FACTORY的值,以及(最后)invokevirtual通过getProxyPreparedStatement()对实例的ProxyFactory调用。
删除了单例工厂(由Javassist生成),并将其替换为具有static方法的最终类(其主体由Javassist生成)。Java 代码变为:
public final PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException
{