先来看看java纯jdbc查询数据的示例:
try {//加载对应的驱动类Class.forName("com.mysql.cj.jdbc.Driver");//创建连接Connection connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test?serverTimezone=UTC", "root", "root123");String sql = "select * from t_user";//创建statementStatement createStatement = connection.createStatement();//利用statement执行SQL语句返回结果集ResultSet rs = createStatement.executeQuery(sql);//遍历结果集while(rs.next()) {System.out.print(rs.getString(1) + " > ");System.out.print(rs.getString(2) + " > ");System.out.print(rs.getString(3) + " > ");System.out.println(rs.getString(4));}//关闭rs.close();createStatement.close();connection.close();
} catch (ClassNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();
} catch (SQLException e) {// TODO Auto-generated catch blocke.printStackTrace();
}
这是一个最基础的查询数据的示例,也是所有的使用Java ORM框架与数据库交互的底层,只不过是封装一下罢了,但是像这种使用DriverManager创建连接的方式,已经基本淘汰了,在应用中是比较浪费资源的,所以JDK就提供一种数据库连接池接口,供第三方组件实现,java.sql.DataSource,这个仅仅是个接口,具体的连接池的实现需第三方进行实现。
我们就直接先看一下Mybatis中的数据源连接池是怎么实现的。
设计模式
我们现需要了解一下数据源模块中的设计模式
工厂模式(Factory Pattern)
是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。
UML:
但是这种工厂模式存在一定的弊端,比如在新增一个新业务模块的时候,是必须修改创建工厂的代码,违反了开闭原则。
所以就有一种新泽设计模式,
抽象工厂模式(Abstract Factory Pattern)
是围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
在抽象工厂模式中,接口是负责创建一个相关对象的工厂,不需要显式指定它们的类。每个生成的工厂都能按照工厂模式提供对象。
当业务扩展的时候新增扩展的工厂,无需修改工厂代码,Mybatis的数据源模块就是使用的抽象工厂设计模式。
源码分析
在源码中超级工厂如下:
package org.apache.ibatis.datasource;import java.util.Properties;import javax.sql.DataSource;/*** @author Clinton Begin*/
public interface DataSourceFactory {void setProperties(Properties props);DataSource getDataSource();}
设计的UML如下(一个工厂类对应只生产一种数据源):
JndiDataSourceFactory:是一个引用,可以直接获取应用级容器中的上下文数据源。
UnpooledDataSourceFactory:生产UnpooledDataSource的数据源工厂,单一连接,非使用了数据源连接池。
PooledDataSourceFactory:生产PooledDataSource数据源工厂,提供了一个线程安全的数据源连接池。
UnpooledDataSource
虽说是继承了DataSource但是并没有具体的实现了连接池的特性,可以看一下这个是怎么产出Connection
跟开始那个JDBC连接数据库的示例是一致的用法。
PooledDataSource
这个就是真正的数据源连接池的实现
连接池需要比较多的参数设置,比如超时,检测连接是否有效,活动的连接,空闲连接等等。
所以今天就讲讲比较核心的一些东西:
里面创建连接是通过创建UnpooledDataSource对象来产出连接的,连接主要是存于List当中,然后配合一系列的操作就变成了线程安全的连接池了,
但是Mybatis的连接池的连接并非直接的使用的Connection而是使用的PooledConnection,进去发现这个是个连接代理,给真正的连接进行了代理增强
连接池释放连接的过程
连接池获取连接的过程(这个就比较长了)
这里用到了并发编程的知识,大家可以看看我之前发布的博文,有讲解这一块的东西
进行校验后会将当前的线程添加到活动连接集合当中,
在获取PooledConnection对象后,获取的连接是代理的连接
解析基本结束了。
最后要提一下为什么在JDBC中使用连接只要用DriverManager.getConnection就能获取连接了,
因为在Class.forName("")加载的时候会去加载驱动类的静态代码块,将其驱动放到registeredDrivers集合中,这个是个CopyOnWriteArrayList读写分离集合
然后在DriverManager获取连接