乐趣区

关于mybatis:mybatis之数据源连接池

本篇来介绍一下 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 操作是线程平安的,因为用了一个锁,这个锁对象就是 PoolStatePoolState 是整个池子下惟一的,它用于对连接池信息进行治理,治理哪些信息呢,我这里也在代码中做了正文

这样就很清晰了,有了 PoolState,咱们就可能更好的理解连接池的应用状况。再次回过头看PooledDataSource 的 popConnection 办法

这里合成进去就是以下逻辑:

1、闲暇连贯存在,则间接检出;

2、闲暇连贯不存在,则先判断沉闷连贯是否达到最大沉闷数

1)否,则新建连贯

2)是,则取出最早检出的沉闷连贯,判断检出工夫是否大于最大逾期工夫

  • 是,则声明该连贯生效,并新建连贯
  • 否,则期待配置的等待时间(2s)

3、取到连贯则进行一次统计并返回,取不到则再次循环获取

再来看一下 pushConnection 办法

顾名思义,pop 是取出连贯,push 就是把连贯放回去,和 pop 用的一把锁,同样是线程平安的。什么时候触发连贯放回操作呢?看下这个类PooledConnection

我在这里同样加了正文,这个类的作用大略就是对实在连贯的代理,而整个代理操作就是对于 close 操作放回连贯到连接池

在每次 pop 和 push 连贯的时候会检测一下连贯的有效性,这时候就用到了 pingConnection 办法

这个办法也比较简单,就是周期到了会去检测一次连贯有效性。

总结

连接池这一块实现还是比较简单的,咱们本人在开发设计的时候也能够参考它是怎么实现的,有哪些益处,对于其余连接池也是殊途同归。

参考资料

这篇写得不错:https://blog.csdn.net/xb_work…

退出移动版