MyBatis-如何创建DataSource&获取Connection

4,719 阅读2分钟

1 解析配置

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">
<configuration>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="UNPOOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
    </environments>
</configuration>

environment节点,会在XMLConfigBuilder中的parseConfiguration方法中执行:

environmentsElement(root.evalNode("environments"));

////
private void environmentsElement(XNode context) throws Exception {
    if (context != null) {
      if (environment == null) {
        environment = context.getStringAttribute("default");
      }
      for (XNode child : context.getChildren()) {
        String id = child.getStringAttribute("id");
        if (isSpecifiedEnvironment(id)) {
          TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager"));
          
          // 解析datasource节点,创建DataSourceFactory对象。
          DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource"));
          
          //从DataSourceFactory中获取DataSource
          DataSource dataSource = dsFactory.getDataSource();
          
          // DataSource放入 Configuration.environment.dataSource
          Environment.Builder environmentBuilder = new Environment.Builder(id)
              .transactionFactory(txFactory)
              .dataSource(dataSource);
          configuration.setEnvironment(environmentBuilder.build());
        }
      }
    }
  }

2 创建DataSource

创建DataSourceFactory,在XMLConfigBuilder.dataSourceElement中:

  private DataSourceFactory dataSourceElement(XNode context) throws Exception {
    if (context != null) {
     
      // 根据上面的xml配置文件, type = "UNPOOLED"
      String type = context.getStringAttribute("type");
      Properties props = context.getChildrenAsProperties();
      
      // resolveClass方法,在TypeAliasRegistry中寻找别名对应的类。
      DataSourceFactory factory = (DataSourceFactory) resolveClass(type).newInstance();
      
      // 用dataSource标签下的一系列property,设置DataSourceFactory的属性
      factory.setProperties(props);
      return factory;
    }
    throw new BuilderException("Environment declaration requires a DataSourceFactory.");
  }

根据org.apache.ibatis.session.Configuration类构造函数中的:

 typeAliasRegistry.registerAlias("UNPOOLED", UnpooledDataSourceFactory.class);

可知: 配置文件中为'UNPOOLED'时,dataSourceElement返回的是UnpooledDataSourceFactory这个类的对象。

TypeAliasRegitry默认值详情可查看MyBatis-初始化过程

UnpooledDataSourceFactory创建的时候,直接创建了DataSource对象:

  protected DataSource dataSource;

  public UnpooledDataSourceFactory() {
    this.dataSource = new UnpooledDataSource();
  }

这里的UnpooledDataSource就是javax.sql.DataSource的实现类。

前面dataSourceElement方法中调用了setProperties,设置DataSource的属性,如driver/url/username/password等。

注:这里只是创建了DataSource对象,设置了属性,并没有做驱动注册等操作。

3 获取Connection

一般通过DataSource.getConnection获取Connection;

UnpooledDataSource中,getConnection最终调用doGetConnection获取Connection,并在这个过程中注册驱动:

private Connection doGetConnection(Properties properties) throws SQLException {

    // 初始化驱动
    initializeDriver();
    // 获取Connection
    Connection connection = DriverManager.getConnection(url, properties);
    // 配置Connection:是否自动提交,事务隔离等级。
    configureConnection(connection);
    return connection;
  }

  private synchronized void initializeDriver() throws SQLException {
    if (!registeredDrivers.containsKey(driver)) {
      Class<?> driverType;
      try {
      
        // forName 加载类文件
        if (driverClassLoader != null) {
          driverType = Class.forName(driver, true, driverClassLoader);
        } else {
          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.newInstance();
        
        // 使用代理的方式,注册驱动。
        DriverManager.registerDriver(new DriverProxy(driverInstance));
        registeredDrivers.put(driver, driverInstance);
      } catch (Exception e) {
        throw new SQLException("Error setting driver on UnpooledDataSource. Cause: " + e);
      }
    }
  }

4 总结

通过上面的分析,总结可知:

1)创建DataSource可以使用两种方式:

  • 1 XML配置创建:type='UNPOOLED|POOLED',分别对应工UnpooledDataSourcePooledDataSource;
  • 2 调用Configuration.setEnvironment

2)代码中获取DataSource:Configuration.getEnvironment().getDataSource()