本篇来介绍一下 mybatis 的数据源连接池相干内容,咱们平时在我的项目中应用的数据源连接池有 Hikaricp、Druid、c3p0 等等,大多数状况下咱们应用 mybatis 的时候都是集成内部数据源连接池来应用,其实 mybatis 本身也实现了简略的数据源连接池。
知识点
- 什么是连接池
- 如何应用 mybatis 连接池
- mybatis 连接池的实现原理
什么是连接池
对于连接池的概念,我置信大家都比较清楚,对于很新很新的新人,这里还是简略的介绍一下。简略的说就是一个容器里放了很多个连贯,咱们须要连贯就去容器里拿,用完了就还回去,容器负责对所有连贯的治理。画了个图,能够感受一下:
如果还不能了解,就把连接池设想成一个外包公司,外面有很多员工,里面有我的项目须要就派人进来,我的项目完结了人就回来,公司就是一个池子,员工就是每个连贯。
如何应用 mybatis 连接池
mybatis 原生形式
对于 mybatis 连接池的应用,官网文档有介绍
在 dataSource 中指定 type 即可,目前反对三种内置的实现,别离为 UNPOOLED、POOLED、JNDI,这三种都是 mybatis 的内置定义的假名,会去找到理论的类型,当然咱们也能够自定义数据源工厂类来指定其余的数据源,具体实现能够参考官网。
集成 spring 形式
通常咱们都是集成 srping 来应用 mybatis 的,集成了 spring 之后,以上形式就不起作用了,起因是 spring 框架中会去替换配置里的环境信息(也就是 environment 节点),此时咱们就得通过 spring 的配置形式来指定数据源,大抵须要以下两步:
1、配置数据源必填属性
<bean id="dataSource" class="org.apache.ibatis.datasource.pooled.PooledDataSource">
<property name="driver" value="${driver}" />
<property name="url" value="${url}" />
<property name="username" value="${username}" />
<property name="password" value="${password}" />
</bean>
2、指定 spring 数据源
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
</bean>
应用 springboot 形式
随着 springboot 应用地越来越多,mybatis 对应的 srpingboot 集成包也面世了,我的项目中引入以下包即可应用
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
当然 mybatis 的 springboot 形式在配置方面还有很多局限性,也包含咱们这次要说的应用 mybatis 自带的连接池。如果要应用 mybatis 自带的连接池,肯定要自定义一个连接池类来进行包装,也是两步:
1、自定义一个连接池包装类
package com.example.mybatisanalyze.datasource;
import org.apache.ibatis.datasource.pooled.PooledDataSource;
import javax.sql.DataSource;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.logging.Logger;
/**
* @author Don
* @date 2022/2/7.
*/
public class MyDataSource implements DataSource {private final PooledDataSource dataSource = new PooledDataSource();
public void setDriverClassName(String driver) {dataSource.setDriver(driver);
}
public void setUrl(String url) {dataSource.setUrl(url);
}
public void setUsername(String username) {dataSource.setUsername(username);
}
public void setPassword(String password) {dataSource.setPassword(password);
}
@Override
public Connection getConnection() throws SQLException {return dataSource.getConnection();
}
@Override
public Connection getConnection(String username, String password) throws SQLException {return dataSource.getConnection();
}
@Override
public <T> T unwrap(Class<T> iface) throws SQLException {return dataSource.unwrap(iface);
}
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {return dataSource.isWrapperFor(iface);
}
@Override
public PrintWriter getLogWriter() throws SQLException {return dataSource.getLogWriter();
}
@Override
public void setLogWriter(PrintWriter out) throws SQLException {dataSource.setLogWriter(out);
}
@Override
public void setLoginTimeout(int seconds) throws SQLException {dataSource.setLoginTimeout(seconds);
}
@Override
public int getLoginTimeout() throws SQLException {return dataSource.getLoginTimeout();
}
@Override
public Logger getParentLogger() throws SQLFeatureNotSupportedException {return dataSource.getParentLogger();
}
}
2、配置文件中指定数据源
spring.datasource.type=com.example.mybatisanalyze.datasource.MyDataSource
spring.datasource.username=${username}
spring.datasource.password=${password}
spring.datasource.url=${url}
spring.datasource.driver-class-name=${driverclass}
为什么不能间接指定数据源类型为 org.apache.ibatis.datasource.pooled.PooledDataSource
呢,认真看代码的敌人预计曾经发现了,封装的办法有一处和理论类型的接口名称是不统一的
因为 springboot 是基于 driverClassName 来进行注入的,然而 mybatis 的连接池只提供了 driver 的接口注入。
mybatis 连接池的实现原理
概念和应用方面都介绍完了,最初来看一下 mybatis 的连接池是如何实现的,先看代码
mybatis 连接池相干的代码都在这个包上面。从这里就能够看出有三种实现:jndi、pooled、unpooled,和官网介绍的配置相符。同时也能看出它应用的是工厂模式来创立数据源。jndi 就不做具体介绍了,大略就是通过配置文件的形式进行配置,而后在代码中能够依据名称获得具体的数据源对象进行应用,tomcat 就是这么做的,参考 JNDI 介绍。次要来看下 pooled 形式,顺带也会理解 unpooled 形式。
在介绍原生形式应用的时候说过,通过配置 type 成 POOLED,咱们就能够应用池化的数据源,首先是因为 mybatis 内置了对应的假名和具体实现类的映射
这样就找到具体实现类PooledDataSourceFactory
,看下具体代码
能够看到继承了UnpooledDataSourceFactory
,次要是为了对配置的属性进行赋值
另外就是生成了一个PooledDataSource
。这是池化的数据源对象,我这里把正文加了一下,不便了解
能够看到其中有一个 UnpooledDataSource
类型的变量,它就是负责新连贯创立的。
所有的用户名明码等属性都是在这里,包含数据库驱动包也是在这里加载,说白了这个类就是配置数据库信息以及获取新连贯用的。再回过头来看下PooledDataSource
,咱们去获取连贯的时候,它会进行一次 pop 操作
这个 pop 操作是线程平安的,因为用了一个锁,这个锁对象就是 PoolState
,PoolState
是整个池子下惟一的,它用于对连接池信息进行治理,治理哪些信息呢,我这里也在代码中做了正文
这样就很清晰了,有了 PoolState
,咱们就可能更好的理解连接池的应用状况。再次回过头看PooledDataSource
的 popConnection 办法
这里合成进去就是以下逻辑:
1、闲暇连贯存在,则间接检出;
2、闲暇连贯不存在,则先判断沉闷连贯是否达到最大沉闷数
1)否,则新建连贯
2)是,则取出最早检出的沉闷连贯,判断检出工夫是否大于最大逾期工夫
- 是,则声明该连贯生效,并新建连贯
- 否,则期待配置的等待时间(2s)
3、取到连贯则进行一次统计并返回,取不到则再次循环获取
再来看一下 pushConnection 办法
顾名思义,pop 是取出连贯,push 就是把连贯放回去,和 pop 用的一把锁,同样是线程平安的。什么时候触发连贯放回操作呢?看下这个类PooledConnection
我在这里同样加了正文,这个类的作用大略就是对实在连贯的代理,而整个代理操作就是对于 close 操作放回连贯到连接池
在每次 pop 和 push 连贯的时候会检测一下连贯的有效性,这时候就用到了 pingConnection 办法
这个办法也比较简单,就是周期到了会去检测一次连贯有效性。
总结
连接池这一块实现还是比较简单的,咱们本人在开发设计的时候也能够参考它是怎么实现的,有哪些益处,对于其余连接池也是殊途同归。
参考资料
这篇写得不错:https://blog.csdn.net/xb_work…