最近我们项目中引入了时序数据库TDengine,所以可以访问的数据库需要配置两个,并且在不同的时机访问不同的数据库,在配置多数据源的过程中,我想了很多问题,花费了一部分精力将数据库访问的原理彻彻底底的梳理了一下,在这里我想和大家分享一下。
在计算机程序中,没有什么问题是通过增加一层抽象层解决不了的,如果有,那就再增加一层。
应用访问数据库程序也一样,通过一层一层的抽象,将最初的通过TCP连接传输复杂的协议数据来操作数据,封装成我们现在的简单几个配置就能操作数据库中数据,真是太神奇了,下面,我们就从这一层一层抽象入手,看看每一层抽象都做了什么,为什么要这样做?
下面,我们主要从以下几个方面聊聊:
1.如何访问数据库?
2.为什么要有JDBC规范,JDBC规范定义了什么?
3.DataSource和DriverManager有什么关系,DataSource本质是什么,DataSource连接池怎么实现?
4.spring的JdbcTemplate又干了什么?
5.mybatis的本质和逻辑是什么?
6.mybatis和springboot是怎么结合的?如何配置多数据源?
1.如何访问数据库?
众所周知,两个进程之间如果要通过网络进行连接并且通行,那么最简单也是最通用的就是socket编程,socket客户端服务端和客户端通过tcp连接起来,就可以双向通信了。
所以最初我们应用程序访问数据库的时候,就是建立一个tcp连接,然后应用程序和数据库共同商量一个应用层协议,进行数据库的操作。
这个应用层协议是很复杂的,需要定义很多东西,比如:
应用程序想要和数据库建立连接的时候,发送什么消息来握手?
怎么去做安全认证,授权,数据加密?
要查询数据的时候发送什么?数据库怎么给我返回?
增删改数据的时候发送什么?数据库怎么告知我结果?
还有数据库相关的事务,函数什么的怎么处理?怎么处理分包、粘包问题?
所以说,如果使用这种方式进行编程会很复杂,但是,这种方式确实解决了应用程序访问数据库的问题。原理如下图所示:
2.为什么要有JDBC规范,JDBC规范定义了什么?
后来,越来越多的数据库定义了自己的业务协议,如果要访问这些数据库操作数据的话,就需要按照他们的协议来,这样,如果我们的程序要连接两个数据库,就需要写两套访问数据库的代码,并且如果后面切换数据库的时候,所有和数据库相关的代码都会被推翻重写,这是很不合理的。
后来,java也觉得这样实在不是办法,一定要想办法解决。
首先,对所有数据库的访问在代码中一定要统一起来才能减少我们开发人员的负担,那么怎么解决协议不一致的问题呢?我们程序语言总不能规范人家数据库的通信协议吧,所以我们必须有一个抽象层,将这些繁杂的访问细节屏蔽了,提供给我们开发人员一个更加简洁的接口进行数据库的操作,于是定义了JDBC(java database connection)规范。
JDBC规范主要是将我们应用程序可能用到的数据库操作定义成统一的接口,我们不管使用什么数据库,只需要调用这些统一的接口就可以,比如获取连接、增删改查数据接口等等,至于接口的具体实现,由于每个数据库的交互协议都不相同,所以由数据库厂商来提供实现,我们只需要引入一个驱动包就行。
那么这个JDBC规范中,要包含哪些东西呢?
首先,要访问数据库,那就必须有一个连接,定义一个Connection吧;然后要执行数据库的sql怎么办?总不能用连接执行sql吧,因此需要定义一个对象来执行sql,就定义一个Statement吧,'陈述’一下,访问数据库要干啥;执行了sql怎么代表包装返回结果呢?定义一个结果集ResultSet吧;因此,应用层代码应该这样写:
先获取连接Connection,从连接获取可以执行sql的Statement,然后执行sql,返回结果为ResultSet,从结果集中,我们可以获取返回的一切,一气呵成,完美!
那么还有一个问题,怎么获取数据库的连接呢?为了遵守开闭原则,我们不能直接new数据库的连接实现,我们可以使用工厂模式,用工厂来创建Connection,这样就解耦了连接使用者和连接创建者,如果我们连接实现改变了,我也不用改变连接的使用者。这个工厂