【Mybatis】【数据源】【三】Mybatis源码解析-UnpooledDataSource

1  前言

上节我们看过了连接池的管理,那么我们这节再看下非池连接的数据源的源码,这部分内容比较少,应该会很轻松,我们来看下吧。

2  源码分析

我们先来看下 UnpooledDataSource 类的基础信息:

2.1  基础信息

public class UnpooledDataSource implements DataSource {
  private ClassLoader driverClassLoader;
  private Properties driverProperties;
  private static Map<String, Driver> registeredDrivers = new ConcurrentHashMap<>();
  // 驱动
  private String driver;
  // 连接 url
  private String url;
  // 用户名
  private String username;
  // 密码
  private String password;
  // 是否开启自动提交
  private Boolean autoCommit;
  // 默认的事务隔离级别
  private Integer defaultTransactionIsolationLevel;
  // 默认超时时间
  private Integer defaultNetworkTimeout;
  static {
    // 获取所有的驱动
    Enumeration<Driver> drivers = DriverManager.getDrivers();
    while (drivers.hasMoreElements()) {
      Driver driver = drivers.nextElement();
      registeredDrivers.put(driver.getClass().getName(), driver);
    }
  }
  private static class DriverProxy implements Driver {
  private Driver driver;
  DriverProxy(Driver d) {
  this.driver = d;
  }
}

可以看到配置的 4+3个属性,并且该类有个静态代码块,会去加载所有的数据库驱动进来,通过 DriverManager 类加载的,我们简单看下:

public class DriverManager {
    static {
        loadInitialDrivers();
        println("JDBC DriverManager initialized");
    }
    private static void loadInitialDrivers() {
        ...

        ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);
        Iterator<Driver> driversIterator = loadedDrivers.iterator();
    }
}

也是通过静态代码块进行类加载的,好啦那我们回来看 UnpooledDataSource ,了解了基础信息我们看看是如何获取连接的。

2.2  获取连接

// 获取连接
public Connection getConnection() throws SQLException {
  return doGetConnection(username, password);
}
@Override
public Connection getConnection(String username, String password) throws SQLException {
  return doGetConnection(username, password);
}
private Connection doGetConnection(String username, String password) throws SQLException {
  Properties props = new Properties();
  // 设置属性
  if (driverProperties != null) {
    props.putAll(driverProperties);
  }
  if (username != null) {
    props.setProperty("user", username);
  }
  if (password != null) {
    props.setProperty("password", password);
  }
  return doGetConnection(props);
}
private Connection doGetConnection(Properties properties) throws SQLException {
  // 初始化驱动类
  initializeDriver();
  // 跟我们以前自己手写 jdbc 差不多,从驱动上获取连接
  Connection connection = DriverManager.getConnection(url, properties);
  // 配置连接
  configureConnection(connection);
  return connection;
}

可以看到经过几个重载方法,最后走到 doGetConnection 首先是判断驱动有没有加载,没有加载的话先进行驱动的加载,当然不是每次获取连接都加载,加载有两个时机,一个是我们上边看到类初始化的时候静态代码块去初始化加载驱动,一个就是这里的判断加载,有了驱动后来进行获取连接,跟我以前在学校刚开始那会儿 Servlet 那个时代,自己通过 JDBC 获取连接一样的。

那我们简单看下初始化驱动和配置初始化的内容:

// 初始化驱动
private synchronized void initializeDriver() throws SQLException {
  // 没初始化的话
  if (!registeredDrivers.containsKey(driver)) {
    Class<?> driverType;
    try {
      // 加载驱动类型
      if (driverClassLoader != null) {
        // 使用 driverClassLoader 加载驱动
        driverType = Class.forName(driver, true, driverClassLoader);
      } else {
        // 通过其他 ClassLoader 加载驱动 说实话咱也不是很懂这个加载
        driverType = Resources.classForName(driver);
      }
      // 通过反射创建驱动实例
      // DriverManager requires the driver to be loaded via the system ClassLoader.
      // http://www.kfu.com/~nsayer/Java/dyn-jdbc.html
      Driver driverInstance = (Driver) driverType.getDeclaredConstructor().newInstance();
      /*
       * 注册驱动,将 Driver 代理类 DriverProxy 对象注册到 DriverManager 中
       * 代理类 DriverProxy 就在下边是一层壳子
       */
      DriverManager.registerDriver(new DriverProxy(driverInstance));
      registeredDrivers.put(driver, driverInstance);
    } catch (Exception e) {
      throw new SQLException("Error setting driver on UnpooledDataSource. Cause: " + e);
    }
  }
}
private void configureConnection(Connection conn) throws SQLException {
  // 关于超时的
  if (defaultNetworkTimeout != null) {
    conn.setNetworkTimeout(Executors.newSingleThreadExecutor(), defaultNetworkTimeout);
  }
  // 关于自动提交的
  if (autoCommit != null && autoCommit != conn.getAutoCommit()) {
    conn.setAutoCommit(autoCommit);
  }
  // 事务隔离级别的
  if (defaultTransactionIsolationLevel != null) {
    conn.setTransactionIsolation(defaultTransactionIsolationLevel);
  }
}

这就是我们的 UnpooledDataSource 的内容了。

3  小结

本节我们主要看了下非池数据源的内容,有理解不对的地方欢迎指正哈。

posted @ 2023-03-02 07:12  酷酷-  阅读(40)  评论(0编辑  收藏  举报