为啥快
- 只干必要的事情
- 消除线程竞争
- 减少调用消耗
- 业务层面
只干必要的事情
只实现了数据源的基本功能,没有什么花哨的功能。
- 代理了
Connection
Statement
CallableStatement
PreparedStatement
ResultSet
实例,没有提供什么拦截器之类的额外功能。 - 指标监控比较简单,包括
totalConnections
idleConnections
activeConnections
pendingThreads
消除线程竞争
参见ConcurrentBag
的实现。
使用ThreadLocal将连接与线程绑定,消除了大部分线程竞争的情况。
减少调用消耗
使用静态方法代替实例方法减少调用消耗。这部分消耗主要是invokestatic
和invokevirtual
字节码使用上有差别造成的。
不过这里不明白为什么要动态生成字节码而不是直接编码。
业务考虑
在关闭Statement
时,需要在Connection
中取消与该Statement
的关联。那么如何快速找到Connection
中的Statement
呢?
使用Map
是一个方法,不过空间上略有浪费。另一个方法是使用List
,但需要遍历,不过对于一般业务来说,数量不太多,遍历倒也还好。不过使用JDK自带的List
实现来说,在数据源使用这个业务场景下,remove
方法的性能不太好,因为remove
方法是从前向后遍历的,而实际的业务场景中,大部分情况是先关闭最后一个即可,即FILO模式。虽然可以使用LinkedList
来规避问题,但LinkedList
的空间局部性不好。Hikari的解决方案是自己实现了List
,即FastList
,对于remove
方法的实现就是从后向前遍历,力求尽快退出循环,同时使用 相同代替 相等作为判断条件,提高效率。
与Tomcat-JDBC对比
- tomcat-jdbc使用了
buzy
和idle
两个列表来保存连接,并发场景下加锁/解锁操作较多 - tomcat-jdbc支持
interceptor
机制,功能上更强,当然耗时也会更多