详解Mybatis中的PooledDataSource

目录
  • 前言
  • PooledConnection
  • PooledDataSource的pushConnection()方法
  • 总结

前言

上篇Java Mybatis数据源之工厂模式文章中我们介绍了Mybatis的数据源模块的DataSource接口和它对应的实现类UnpooledDataSource、PooledDataSource,这篇文章详细介绍一下PooledDataSource
PooledDataSource使用了数据库连接池可以实现数据库连接池的重复利用,还能控制连接数据库的连接上限,实现数据库连接的统一管理,缓存数据连接信息还能防止流量突发连接数据库不及时

PooledDataSource有个PoolState状态,PoolState里保存着数据库连接信息PooledConnection,PooledConnection实现InvocationHandler接口,重写invoke方法,显然这是一个代理类,使用了JDK的动态代理

PooledConnection

   class PooledConnection implements InvocationHandler {
    private static final Class<?>[] IFACES = new Class<?>[] { Connection.class };
    public PooledConnection(Connection connection, PooledDataSource dataSource) {
        this.hashCode = connection.hashCode();
        this.realConnection = connection;
        this.dataSource = dataSource;
        this.createdTimestamp = System.currentTimeMillis();
        this.lastUsedTimestamp = System.currentTimeMillis();
        this.valid = true;
        this.proxyConnection = (Connection) Proxy.newProxyInstance(Connection.class.getClassLoader(), IFACES, this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        String methodName = method.getName();
        if (CLOSE.equals(methodName)) {
            dataSource.pushConnection(this);
            return null;
        }
        try {
            if (!Object.class.equals(method.getDeclaringClass())) {
                checkConnection();
            }
            return method.invoke(realConnection, args);
        } catch (Throwable t) {
            throw ExceptionUtil.unwrapThrowable(t);
        }
    }
}

我们看一看到构造方法中调用了Proxy.newProxyInstance()方法来生成代理类,而重写invoke方法中如果是close()就调用pushConnection()方法直接把它放入连接池而不是关闭连接,其他情况调用checkConnection()检查连接信息,代理类调用realConnection()方法,下面就看一下pushConnection()方法

PooledDataSource的pushConnection()方法

方法的功能就是把数据库连接放入连接池中:

protected void pushConnection(PooledConnection conn) throws SQLException {
        synchronized (state) {
            state.activeConnections.remove(conn);
            if (conn.isValid()) {
                if (state.idleConnections.size() < poolMaximumIdleConnections && conn.getConnectionTypeCode() == expectedConnectionTypeCode) {
                    state.accumulatedCheckoutTime += conn.getCheckoutTime();
                    if (!conn.getRealConnection().getAutoCommit()) {
                        conn.getRealConnection().rollback();
                    }
                    PooledConnection newConn = new PooledConnection(conn.getRealConnection(), this);
                    state.idleConnections.add(newConn);
                    newConn.setCreatedTimestamp(conn.getCreatedTimestamp());
                    newConn.setLastUsedTimestamp(conn.getLastUsedTimestamp());
                    conn.invalidate();
                    if (log.isDebugEnabled()) {
                        log.debug("Returned connection " + newConn.getRealHashCode() + " to pool.");
                    }
                    state.notifyAll();
                } else {

                    state.accumulatedCheckoutTime += conn.getCheckoutTime();
                    if (!conn.getRealConnection().getAutoCommit()) {
                        conn.getRealConnection().rollback();
                    }
                    conn.getRealConnection().close();
                    if (log.isDebugEnabled()) {
                        log.debug("Closed connection " + conn.getRealHashCode() + ".");
                    }
                    conn.invalidate();
                }
            } else {
                if (log.isDebugEnabled()) {
                    log.debug("A bad connection (" + conn.getRealHashCode() + ") attempted to return to the pool, discarding connection.");
                }
                state.badConnectionCount++;
            }
        }
    }
  • 从活跃连接集合中删除该连接
  • 如果PooledConnection有效,并且空闲连接数小于最大空闲连接数,就利用当前PooledConnection创建PooledConnection,放入空闲连接数集合中,方便下次使用,关闭当前PooledConnection对象的数据库连接,并对当前PooledConnection对象设置无效,最后唤醒其他等待的线程。如果空闲连接数大于最大空闲连接数了就关闭连接,设置当前连接无效
  • 如果PooledConnection无效,badConnectionCount加一,这个badConnectionCount是记录无效的数据库连接信息的

总结

本篇文章主要介绍了PooledConnection和PooledDataSource的pushConnection()方法,PooledConnection用到了jdk的动态代理,生成Connection的实现类的代理类,拦截的逻辑中对于close()方法没有真正关闭,而是把数据库连接信息放入连接池中供下次再使用,数据库连接信息放入连接池的过程是通过调用PooledDataSource的pushConnection()来完成的,具体就是从活跃连接集合中删除这个连接,然后放入空闲连接数集合中并把当前连接设置为无效。

到此这篇关于详解Mybatis中的PooledDataSource的文章就介绍到这了,更多相关Mybatis PooledDataSource内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • mybatis配置mapper-locations的坑及解决

    目录 mybatis配置mapper-locations的坑 mapperLocations配置失效 问题根源 解决 mybatis配置mapper-locations的坑 很多时候想把xml文件与mapper类放在一起. mapper-locations: com.demo.dao.*.xml 这么配置之后 发现报错找不到xml中id pom.xml配置这句话就可以了!! <build>     <resources>         <resource>      

  • Mybatis条件if test如何使用枚举值

    目录 Mybatis条件if test使用枚举值 1.正确 2.错误 Mybatis里使用枚举Enum判断 TestTypeEnum定义如下 Mybatis条件if test使用枚举值 1.正确 package com.weather.weatherexpert.common.utils; /** * <p>Title: </p> * <p>Description: </p> * * @Author * @CreateTime */ public enum

  • Mybatis返回Map数据方式示例

    目录 一. 方式1 接口 调用 二. 方式2 接口 调用 三. 方式3 接口 调用 一. 方式1 接口 public interface UserMapper { List<Map<String, String>> selectTestData1(); } <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//

  • Mybatis的mapper.xml中if标签test判断的用法说明

    目录 mapper.xml中if标签test判断的用法 1. 字符串等于条件的两种写法 2. 非空条件的判断 3. 判断数组是否包含某个元素 mapper.xml <if test>书写时候的一些坑 1. 分页 2. 字符串形式的数据比较 mapper.xml中if标签test判断的用法 1. 字符串等于条件的两种写法 ① 将双引号和单引号的位置互换 <if test=' testString != null and testString == "A" '>  

  • springboot实现指定mybatis中mapper文件扫描路径

    目录 指定mybatis中mapper文件扫描路径 mybatis配置多个扫描路径写法 指定mybatis中mapper文件扫描路径 所有的mapper映射文件 mybatis.mapper-locations=classpath*:com/springboot/mapper/*.xml 或者resource下的mapper映射文件 mybatis.mapper-locations=classpath*:mapper/**/*.xml mybatis配置多个扫描路径写法 百度得到,但是很乱,稍微

  • mybatis中mapper-locations的作用

    目录 mapper-locations的作用说明 1.mapper-locations 2.使用场景 3.补充 mybatis.mapper-locations作用和Invalid bound statement (not found)错误 对应错误:mapper.xml没被加载到 mybatis.mapper-locations mapper-locations的作用说明 1.mapper-locations mapper-locations是一个定义mapper接口位置的属性,在xxx.ym

  • Java Mybatis数据源之工厂模式

    目录 工厂模式的工厂 工厂模式的产品 总结 工厂模式的工厂 DataSourceFactory是工厂角色的接口层 public interface DataSourceFactory { void setProperties(Properties props); DataSource getDataSource(); } 这个两个方法一个是设置DataSource的相关属性,一个是获取当前的dataSource UnpooledDataSourceFactory实现了这个接口,它的构造方法中指定

  • 详解Mybatis中的PooledDataSource

    目录 前言 PooledConnection PooledDataSource的pushConnection()方法 总结 前言 上篇Java Mybatis数据源之工厂模式文章中我们介绍了Mybatis的数据源模块的DataSource接口和它对应的实现类UnpooledDataSource.PooledDataSource,这篇文章详细介绍一下PooledDataSourcePooledDataSource使用了数据库连接池可以实现数据库连接池的重复利用,还能控制连接数据库的连接上限,实现数

  • 详解Mybatis中的 ${} 和 #{}区别与用法

    Mybatis 的Mapper.xml语句中parameterType向SQL语句传参有两种方式:#{}和${} 我们经常使用的是#{},一般解说是因为这种方式可以防止SQL注入,简单的说#{}这种方式SQL语句是经过预编译的,它是把#{}中间的参数转义成字符串,举个例子: select * from student where student_name = #{name} 预编译后,会动态解析成一个参数标记符?: select * from student where student_name

  • 详解Mybatis中的CRUD

    1.namespace namespace中的包名要和Dao/mapper接口的包名一致! 2. select 选择,查询语句: id:就是对应的namespace中的方法名: resultType: Sql语句执行的返回类型! parameterType:参数类型! 1.编写接口 //根据id查询用户 User getUserById(int id); ​ 2.编写对应的mapper.xml中的sql语句 <select id="getUserById" parameterTy

  • 详解Mybatis中万能的Map和模糊查询写法

    1.万能的Map 假设,我们的实体类,或者数据库中的表,字段或参数过多,我们接口参数以前用的是实体类,现在考虑使用下Map! 接口: //万能的Map int addUser2(Map<String,Object> map); mapper.xml: <!--Map中的key--> <insert id="addUser2" parameterType="map"> insert into mybatis.user (id,nam

  • 详解mybatis中的if-else的嵌套使用

    目录 案例一:if-else 案例二:if嵌套 MyBatis中if和choose的嵌套 案例一:if-else 在mybatis的使用过程中,难免会存在使用if-else的逻辑,但是实际是没有这种语法的,提供了choose标签来替代这种语法 <select id="selectUserByState" resultType="com.bz.model.entity.User"> SELECT * FROM user WHERE 1=1 <choo

  • 详解MyBatis中主键回填的两种实现方式

    主键回填其实是一个非常常见的需求,特别是在数据添加的过程中,我们经常需要添加完数据之后,需要获取刚刚添加的数据 id,无论是 Jdbc 还是各种各样的数据库框架都对此提供了相关的支持,本文我就来和和大家分享下数据库主键回填在 MyBatis 中的两种实现思路. 原生写法 框架来源于我们学过的基础知识,主键回填实际上是一个在 JDBC 中就被支持的写法,有的小伙伴可能不知道这一点,因此这里我先来说说在 JDBC 中如何实现主键回填. JDBC 中实现主键回填其实非常容易,主要是在构造 Prepar

  • 详解Mybatis中的select方法

    selectById方法 根据id,查询记录 public void updateRecycleAssayBusinessItemCharge(String Id) { AssayBusinessItemCharge assayBusinessItemCharge = assayBusinessItemChargeService.selectById(Id); assayBusinessItemCharge.setRecordStatus(RecordStatusEnum.VALID.getVa

  • 详解Mybatis中常用的约束文件

    SqlMapConfig.xml的约束,也就是Mybatis主配置文件的约束 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> 持久层接口映射文件的

  • 详解mybatis中association和collection的column传入多个参数问题

    项目中在使用association和collection实现一对一和一对多关系时需要对关系中结果集进行筛选,如果使用懒加载模式,即联合使用select标签时,主sql和关系映射里的sql是分开的,查询参数传递成为问题. mybatis文档: property description column 数据库的列名或者列标签别名.与传递给resultSet.getString(columnName)的参数名称相同.注意: 在处理组合键时,您可以使用column="{prop1=col1,prop2=c

  • 详解Mybatis是如何把数据库数据封装到对象中的

    一.前言 接到一个问题,数据库为Null的数据,传递到前端显示为0.之前有了解过,持久层框架(mybatis)在把数据库数据封装到对象中,是利用对象的Setter方法,这个大家也都知道,因此我就在Setter方法尝试,结果并不完全是这样.下面我用例子演示. 二.准备阶段 1.数据表 2.表对应的实体类 @Data @ApiModel("用户账号") public class User { @ApiModelProperty(value = "用户id") Integ

随机推荐