写点什么

MyBatis3 源码解析 (2) 数据库连接

作者:
  • 2022 年 2 月 16 日
  • 本文字数:2724 字

    阅读完需:约 9 分钟

简介

基于上篇的示例感受,下面我们探索下 MyBatis 连接数据库的细节是如果实现的,在日常使用中是如何能和 Druid 数据库连接池等配合起来的

源码解析

基于上篇的示例代码:


public class MybatisTest {
@Test public void test() { try(SqlSession session = buildSqlSessionFactory().openSession()) { PersonMapper personMapper = session.getMapper(PersonMapper.class); personMapper.createTable(); personMapper.save(Person.builder().id(1L).name("1").build()); Person person = personMapper.getPersonById(1); System.out.println(person); } }
public static SqlSessionFactory buildSqlSessionFactory() { String JDBC_DRIVER = "org.h2.Driver"; String DB_URL = "jdbc:h2:mem:test;DB_CLOSE_DELAY=-1"; String USER = "sa"; String PASS = ""; DataSource dataSource = new PooledDataSource(JDBC_DRIVER, DB_URL, USER, PASS); Environment environment = new Environment("Development", new JdbcTransactionFactory(), dataSource); Configuration configuration = new Configuration(environment); configuration.addMapper(PersonMapper.class); SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); return builder.build(configuration); }}
复制代码


当前我们想找的是与数据库建立连接的部分


通过阅读书籍:《MyBatis3 源码深度解析》,我们大概知道执行是在 Executor 中,我们跟踪相关的代码


经过不懈的努力跟踪,得到下面的关键代码:


找到了在执行语句中,在 Executor 中获取连接的关键代码


public class SimpleExecutor extends BaseExecutor {    private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {  // 获取数据库连接        Connection connection = this.getConnection(statementLog);        Statement stmt = handler.prepare(connection, this.transaction.getTimeout());        handler.parameterize(stmt);        return stmt;    }}
复制代码


继续跟踪,来到我们示例中定义的事务管理器:JdbcTransactionFactory


public class JdbcTransaction implements Transaction {    public Connection getConnection() throws SQLException {        if (this.connection == null) {            this.openConnection();        }
return this.connection; }
protected void openConnection() throws SQLException { if (log.isDebugEnabled()) { log.debug("Opening JDBC Connection"); }
// 从DataSource中获取 this.connection = this.dataSource.getConnection(); if (this.level != null) { this.connection.setTransactionIsolation(this.level.getLevel()); }
this.setDesiredAutoCommit(this.autoCommit); }}
复制代码


上面可以看到是从 DataSource 中获取的,来到我们定义的:PooledDataSource


public class PooledDataSource implements DataSource {    public Connection getConnection() throws SQLException {        return this.popConnection(this.dataSource.getUsername(), this.dataSource.getPassword()).getProxyConnection();    }
private PooledConnection popConnection(String username, String password) throws SQLException { while(conn == null) { synchronized(this.state) { PoolState var10000; if (!this.state.idleConnections.isEmpty()) { ...... } else if (this.state.activeConnections.size() < this.poolMaximumActiveConnections) { // 获取数据库连接池连接 conn = new PooledConnection(this.dataSource.getConnection(), this); if (log.isDebugEnabled()) { log.debug("Created connection " + conn.getRealHashCode() + "."); } } else { ...... } if (conn != null) { ...... } } } ...... }}
复制代码


我们继续跟下去:


public class UnpooledDataSource implements DataSource {    public Connection getConnection() throws SQLException {        return this.doGetConnection(this.username, this.password);    }
private Connection doGetConnection(String username, String password) throws SQLException { Properties props = new Properties(); if (this.driverProperties != null) { props.putAll(this.driverProperties); }
if (username != null) { props.setProperty("user", username); }
if (password != null) { props.setProperty("password", password); }
return this.doGetConnection(props); }
private Connection doGetConnection(Properties properties) throws SQLException { this.initializeDriver(); // 看到了熟悉的原生的获取数据库连接的方式 Connection connection = DriverManager.getConnection(this.url, properties); this.configureConnection(connection); return connection; }}
复制代码


到这里我们找到了源码中如何获取数据库连接的关键代码


其实就是对于原生数据库操作的封装

调用栈回顾

我们回过头来看看整个过程中的类调用栈:


  • MybatisTest:我们的测试代码

  • MapperProxy:MyBatis 的 Mapper 的代理类

  • MapperMethod:SQL 执行相关

  • DefaultSqlSession

  • CachingExecutor

  • BaseExecutor

  • SimpleExecutor

  • JdbcTransation

  • PooledDataSource

  • UnpooledDataSource


可以看到数据库连接是从 DataSource 中获取的,而 PooledDataSource 是 MyBatis 自己的一个数据库连接池,其中使用非池化的 UnpooledDataSource


在我们的日常开发中,经常使用 MyBatis+Druid 等数据库连接池一起使用,从这里就可以看到,我们简单替换一下 MyBatis 初始化时候的 DataSource 即可

总结

本篇中,我们跟踪了数据库如何进行连接获取,看到日常开发中 MyBatis+Druid 等数据库连接的配置使用的背后原理

发布于: 刚刚阅读数: 2
用户头像

关注

还未添加个人签名 2018.09.09 加入

代码是门手艺活,也是门艺术活

评论

发布
暂无评论
MyBatis3源码解析(2)数据库连接