生产背景最近忙于集团内部安全等安全加密相关事宜。最初决定使用shardingsphere是因为项目比较多,兼容性的需求也随之而来。加密数据源和动态数据源的兼容性,还有分库分表和加密数据源的兼容性等等,反正不一致,兼容是毋庸置疑的。以上或多或少都与数据源有关,所以在处理不同的Compatibility等问题时也让我对DataSource再次产生了兴趣。这个曾经被很多人遗忘的重要概念是很久以前的事了。从这样的操作可以明显看出,获取数据库连接的代码还是需要用到DriverManager。大家都知道DriverManager#getConnection是通过数据库驱动直接与数据库建立连接的。建立数据库连接和关闭连接都是耗时的。如果业务层的每条SQL查询都使用这种方式,会产生很大的系统开销。一般系统的性能要求,单次请求需要稳定在200ms。经过本地环境测试,以DriverManager的形式创建数据库连接大概需要300~500ms,练习五分钟,拍照两小时?随着系统的发展和迭代,由于系统的复杂性和性能要求,这种获取连接的方式是不可接受的连接池的出现。相信有的读者能想象到,创建数据库连接消耗资源的场景好像在哪里听过。是的,和创建线程的情况基本类似。既然线程可以关联线程池,那么数据库连接是否可以放在一个池中呢?是的,确实有一种存储数据库连接的池化技术,叫做连接池。应用程序从连接池中获取数据库连接,使用后放入池中。感觉不错吗?完美解决了重复创建和消耗资源的情况。看似完美的背后,其实有一个致命的问题,那就是我第一次去连接池获取连接的时候,连接池中并没有连接,需要走创建过程。连接池是如何解决这个问题的呢?通过在创建连接池的时候初始化连接,一般的连接池都有这样一个参数initialSize代表池中初始化的连接数。下图展示了Druid执行init方法时数据库连接初始化的过程。当初始化连接小于池中连接时,会循环创建,直到池中连接满足初始化数连接池,线程池。。。这些池化技术的核心思想是交换空间换时间。因为在绝大多数情况下,空间并不是那么稀缺,我们更关心系统数据源的性能。虽然连接池是🐂🍺,它本身是无法支撑的。连接池不具备生成连接的能力,需要配合类似DriverManager组件和数据库驱动来创建连接。如果像这样放到业务代码里,不就得封装了吗?这时候我就想到了一个公司,sun公司是做什么的?制定规范是对的,他们在jdbc2.0版本推出了一个DataSource的东西,规范约束访问数据库的过程相当于结合了DriverManager和连接池的概念。如果要获取数据库连接,可以通过我的DataSource获取。你不需要关心连接池和数据库连接是如何创建的。就用它吧。当它结束时,使用后无需关闭连接。实际上,DataSource获取的连接来自于连接池,而连接池的连接实际上是由DriverManager或者类似的组件创建的。DriverManager只是jdbcversion1.0用来调用数据库驱动的一个工具包。jdbc2.0版本引入DataSource后,一个典型的LikeDruidDataSource,不依赖DriverManager,而是在自己的实现类中调用数据库驱动。这只是为了强调数据库连接不一定是使用DriverManager创建的。综上所述,数据源(DataSource)是Sun规定的获取数据库连接的标准接口。应用程序处于数据库连接抽象的中间层。它存在于javax.sql包中,用于替代DriverManager获取数据库连接。使用DataSource而不是DriverManager有什么好处?在应用程序中创建/关闭连接时,DriverManager会影响应用程序性能。不支持连接池,重复创建/关闭连接会浪费系统性能。DataSource由于在应用程序中不创建/关闭连接,因此可以很好地提高应用程序的性能。提供连接池的功能是为了避免重复创建。这里画一张图来描述下使用DataSource和DriverManager为应用程序获取连接的区别。DataSource之后,将数据库连接、用户名、密码作为DataSource属性的一部分统一管理,填写数据库驱动名称,底层自动加载DataSource技术解析。我们先看看DataSource接口的说明和对应的方法。首先理解DataSource中只有两个接口,是一个重载关系,用于建立DataSource所代表的数据源的数据库连接。这里需要注意的是,CommonDataSource接口用于定义以下三个数据源接口。javax.sql.DataSource的public方法:定义获取数据库连接的基本接口javax.sql.ConnectionPoolDataSource:定义从数据库连接池获取连接的接口javax.sql.XADataSource:定义获取分布式事务连接的接口。一般很少直接使用XA分布式事务。具体原因参考第一种和第二种分布式2PC和3PC事务模型。它更容易理解。Sun公司在定义规范时,希望大家平时使用DataSource来获取数据库连接。如果底层数据源是连接池的话,使用ConnectionPoolDataSource之后的开发逐渐偏离了原来的轨道预期。比如DruidDataSource同时实现了这两者。类图如下。其实这不是问题。一类DruidDataSource包装了两个DataSource接口实现。读者是无法察觉的。总结文章以循序渐进的方式帮助大家梳理DataSource的输出背景。描述了DriverManager在jdbc1.0版本中获取数据库连接的方式,以及发展到2.0的DataSource,以及其中引入的数据库连接池技术。读者看完后应该对DataSource有更深的理解。有兴趣的读者可以研究一下Hikari和Druid实现的数据源。通过阅读源码,可以更好的理解DataSource的设计思路
