Druid源码阅读系列(六)

今天周一,一周的愉快生活就开始了,我们继续来看下Druid的源码。前面我们说到了DruidDataSource的初始化,以及连接的创建线程和摧毁线程逻辑。我们今天来看下pool包下和查询相关的几个类的逻辑。

第一天,我们来看点比较简单的东西,就是Druid整个sql执行流程是什么样的。

SQL执行流程
  1. 注册驱动
  2. 初始化数据源
  3. 从数据源获取连接
  4. 用连接创建Statment
  5. 在Statment上创建sql
  6. 执行sql
  7. 拿到返回的ResultSet

我们前面主要是对前三点进行了梳理,再来看下后面的几点。

java.sql包知识点复习

看之前先复习一个JDKjava.sql包的一些知识,看下包里的几个关键接口/类。

Statement:英文是陈述,我觉得语句更形象,是所有sql语句的一个抽象,当建立连接后,如果你想要操作数据库,需要执行sql,就是将Statement对象将你的sql和数据库传输,并得到执行结果。

Statement会有以下两种子类接口,分别对应两种数据库执行方式:

  • PreparedStatement:进行预编译的Statement,如果一个语句会执行多次推荐使用这种方式。
  • CallableStatement:执行存储过程的对象。

ResultSet会拿到返回结果,但是只是一个汇总的信息,实际的信息并没有,需要用rs.next()拿到。但是只能每行每行的拿值。

DruidPooledStatement

然后我们类比着来看看pool包下面的类

在这里插入图片描述

我框柱的部分,看着是不是很眼熟,对的,就是和java.sql里面那些是一样的,只是进行了一些封装而已,加入了“池化”支持。

我们先看下DruidPooledStatement这个类,不出所料,它实现了Statement这个接口,所以常规sql操作它都会有,大概说下,前面的DruidDataSource那个类的init()方法写的很详细,因为很重要,后面这些不太重要的就不会过得那么细了,只过一下核心部分。这里主要看下它的execute方法:

@Override
public final boolean execute(String sql) throws SQLException {
    checkOpen();

    incrementExecuteCount();
    transactionRecord(sql);

    try {
        return stmt.execute(sql);
    } catch (Throwable t) {
        errorCheck(t);

        throw checkException(t, sql);
    }
}

首先校验连接是否已经被关闭了,在对执行语句计数加一,然后记录执行的sql。最后执行整个sql,这里的stmt是一个接口Statement,具体实现是在StatementProxyImpl里的execute方法。方法如下:

@Override
public boolean execute(String sql) throws SQLException {
    updateCount = null;
    lastExecuteSql = sql;
    lastExecuteType = StatementExecuteType.Execute;
    lastExecuteStartNano = -1L;
    lastExecuteTimeNano = -1L;

    FilterChainImpl chain = createChain();
    firstResultSet = chain.statement_execute(this, sql);
    recycleFilterChain(chain);
    return firstResultSet;
}

最终实现是在filterChain里的statement_execute里,这个是先执行filter的逻辑,然后交给具体数据库的jdbc去实现的。

DruidPooledPreparedStatement

核心代码如下

@Override
public ResultSet executeQuery() throws SQLException {
    checkOpen();

    incrementExecuteQueryCount();
    transactionRecord(sql);

    oracleSetRowPrefetch();

    conn.beforeExecute();
    try {
        ResultSet rs = stmt.executeQuery();

        if (rs == null) {
            return null;
        }

        DruidPooledResultSet poolableResultSet = new DruidPooledResultSet(this, rs);
        addResultSetTrace(poolableResultSet);

        return poolableResultSet;
    } catch (Throwable t) {
        errorCheck(t);

        throw checkException(t);
    } finally {
        conn.afterExecute();
    }
}

其实和上面代码类似,底层是利用ResultSet rs = stmt.executeQuery()执行语句和执行结果的。

DruidPooledResultSet

这个类的实现基本就是对ResultSet的一些封装而已,可以直接像ResultSet一样使用。用每列的名字去拿到每行的值。

想法

通过Druid源码可以看出我们可以通过封装一些底层逻辑,在它之上做很多加工,这也是自己定义一个所谓的DruidPooledPreparedStatement这个类的原因,因为我们可以在封装的类里面做所有想做的逻辑,只要在对应的方法里面在调用以前的实现即可。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值