浅析Mybatis和连接池组件的关系

如果你觉得内容对你有帮助的话,不如给个赞,鼓励一下更新。

本文持续更新,最新版本请移步:浅析Mybatis和连接池组件的关系

什么是连接池

对于一个简单的数据库应用,由于对于数据库的访问不是很频繁。这时可以简单地在需要访问数据库时,就新创建一个连接,用完后就关闭它,这样做也不会带来什么明显的性能上的开销。但是对于一个复杂的数据库应用,情况就完全不同了。频繁的建立、关闭连接,会极大的减低系统的性能,因为对于连接的使用成了系统性能的瓶颈。
连接复用: 通过建立一个数据库连接池以及一套连接使用管理策略,使得一个数据库连接可以得到高效、安全的复用,避免了数据库连接频繁建立、关闭的开销。
对于共享资源,有一个很著名的设计模式:资源池。该模式正是为了解决资源频繁分配、释放所造成的问题的。把该模式应用到数据库连接管理领域,就是建立一个数据库连接池,提供一套高效的连接分配、使用策略,最终目标是实现连接的高效、安全的复用。
数据库连接池的基本原理是在内部对象池中维护一定数量的数据库连接,并对外暴露数据库连接获取和返回方法。

如:外部使用者可通过getConnection 方法获取连接,使用完毕后再通过releaseConnection方法将连接返回,注意此时连接并没有关闭,而是由连接池管理器回收,并为下一次使用做好准备。

但是我们要明白一点:真正解决我们连接复用的问题的,是像 Druid、hikari 这样的连接池组件,而不是Mybatis、JPA这种持久层框架。

从查询语句看关系

Mybatis只有在真正执行sql操作的时候才会去获取数据库连接, 我们从一段代码开始分析。

sqlSession.selectOne("xxx");

经过一系列调用到SimpleExecutor#doQuery方法:

  @Override
  public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
    Statement stmt = null;
    try {
      Configuration configuration = ms.getConfiguration();
      StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
      stmt = prepareStatement(handler, ms.getStatementLog());
      return handler.query(stmt, resultHandler);
    } finally {
      closeStatement(stmt);
    }
  }

关键代码stmt = prepareStatement(handler,ms.getStatementLog());这一句根据方法名就能猜测、是根据Connection来获取执行Sql的PrepareStatement

  private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
    Statement stmt;
    // 获取数据库连接
    Connection connection = getConnection(statementLog);
    stmt = handler.prepare(connection, transaction.getTimeout());
    handler.parameterize(stmt);
    return stmt;
  }

getConnection() 会走到 BaseExecutor#getConnection
Mybatis中关于事务配置项的值是”JDBC”,所以这里的transaction其实是:**JdbcTransaction。**最终到JdbcTransaction获取连接的方法中

  protected Connection getConnection(Log statementLog) throws SQLException {
    Connection connection = transaction.getConnection();
    if (statementLog.isDebugEnabled()) {
      return ConnectionLogger.newInstance(connection, statementLog, queryStack);
    } else {
      return connection;
    }
  }

 // JdbcTransaction会一直走到DataSource中去取数据库连接
  protected void openConnection() throws SQLException {
    if (log.isDebugEnabled()) {
      log.debug("Opening JDBC Connection");
    }
    connection = dataSource.getConnection();
    if (level != null) {
      connection.setTransactionIsolation(level.getLevel());
    }
    setDesiredAutoCommit(autoCommit);
  }

JDBC

JDBC(Java DataBase Connectivity)是 Java 程序与关系型数据库交互的统一API。 实际上,JDBC 由两部分 API 构成:第一部分是面向 Java 开发者的 Java API,它是一个统一的、标准的 Java API,独立于各个数据库产品的接口规范;第二部分是面向数据库驱动程序开发者的 API,它是由各个数据库厂家提供的数据库驱动,是第一部分接口规范的底层实现,用于连接具体的数据库产品。
我相信我们学习JDBC的时候都用过这样一段代码。

// 加载驱动,jdbc2后可以省略
Class.forName(driver);
// 获取db连接
Connection connection = DriverManager.getConnection(url, user, password);
// 创建Statement
Statement statement = connection.createStatement();
// 执行语句
statement.execute(sql1);

现在有了许多持久化框架,我们基本上不会再直接使用jdbc操作db了,但各个框架也是对jdbc的封装,要执行一个sql上面的步骤还是必不可少的,或许框架做了一下操作让我们不用感知到这些的过程
JDBC 操作的核心步骤,具体如下:

  1. 注册数据库驱动类,指定数据库地址,其中包括 DB 的用户名、密码及其他连接信息;
  2. 调用 DriverManager.getConnection() 方法创建 Connection 连接到数据库;
  3. 调用 Connection 的 createStatement() 或 prepareStatement() 方法,创建 Statement 对象,此时会指定 SQL(或是 SQL 语句模板 + SQL 参数);
  4. 通过 Statement 对象执行 SQL 语句,得到 ResultSet 对象,也就是查询结果集;
  5. 遍历 ResultSet,从结果集中读取数据,并将每一行数据库记录转换成一个 JavaBean 对象;
  6. 关闭 ResultSet 结果集、Statement 对象及数据库 Connection,从而释放这些对象占用的底层资源。

DataSource

从 JDBC 2.0后java推荐使用DataSource来代表一个db数据源并从中获取与db的连接,DataSource是一个简单的接口只包含了两个文明获取连接的接口定义:

public interface DataSource  extends CommonDataSource, Wrapper {
    // 获取一个与db的连接
    Connection getConnection() throws SQLException;

    // 获取一个与db的连接,可以指定获取连接时的用户和密码
    Connection getConnection(String username, String password) throws SQLException;
}

DataSource接口由驱动程序供应商实现,我们常见的数据源组件都实现了 Javax.sql.DataSource 接口。例如:Hikari、Druid等

这篇文章到这就结束啦,喜欢的话就给个赞 + 收藏 + 关注吧!
有什么想看的欢迎留言!!!

你可能感兴趣的:(Java学习指南,java,mybatis,jdbc,sql,spring)