Mybatis学习(二)--- 数据源DataSource

    Mybatis提供了两个数据源的实现:PooledDataSource和UnPolledDataSource,然后通过不同的工厂方法创建不同的DataSource.

DataSourceFactory工厂

    DataSourceFactory是工厂类接口的,UnpooledDataSourceFactory和PooledDataSourceFactory扮演着具体的工厂类的。该接口主要提供了两个方法。

//设置DataSource的属性
void setProperties(Properties props);
//获取DataSource
DataSource getDataSource();

UnpooledDataSourceFactory工厂

    在UnpooledDataSourceFactory工厂中,直接构造UnpooledDataSource对象,setProperties方法会完成UnpooledDataSource的属性设置。

protected DataSource dataSource;

//直接构建UnpooledDataSource对象
public UnpooledDataSourceFactory() {
  this.dataSource = new UnpooledDataSource();
}

@Override
public void setProperties(Properties properties) {
  Properties driverProperties = new Properties();
  MetaObject metaDataSource = SystemMetaObject.forObject(dataSource);
  //遍历property集合
  for (Object key : properties.keySet()) {
    String propertyName = (String) key;
    //属性是以“driver.”开头表示是对DataSource的配置,记录在driverProperties中
    if (propertyName.startsWith(DRIVER_PROPERTY_PREFIX)) {
      String value = properties.getProperty(propertyName);
      driverProperties.setProperty(propertyName.substring(DRIVER_PROPERTY_PREFIX_LENGTH), value);
    } else if (metaDataSource.hasSetter(propertyName)) {
      String value = (String) properties.get(propertyName);
      //根据属性类型进行类型转换, 主要是Integer 、Long 、Boolean 三种类型的转换
      Object convertedValue = convertValue(metaDataSource, propertyName, value);
      //属性设置
      metaDataSource.setValue(propertyName, convertedValue);
    } else {
      throw new DataSourceException("Unknown DataSource property: " + propertyName);
    }
  }
  if (driverProperties.size() > 0) {
    metaDataSource.setValue("driverProperties", driverProperties);
  }
}

@Override
public DataSource getDataSource() {
  return dataSource;
}

PooledDataSourceFactory工厂

    继承了UnpooledDataSourceFactory,没有重写方法,只是在初始化的时候会将DataSource初始化为PooledDataSource。

public PooledDataSourceFactory() {
  this.dataSource = new PooledDataSource();
}

UnpooledDataSource

    实现DataSource接口,用于获取数据库的连接,每次通过UnpooledDataSource.getConnection方法获取数据库连接时都会创建一个新的连接。通过属性registeredDrivers记录注册的JDBC驱动。

private static Map<String, Driver> registeredDrivers = new ConcurrentHashMap<String, Driver>();

   包含一个静态代码块,负责将已在DriverManager注册的JDBC Driver复制一份到registeredDrivers中。

static {
  Enumeration<Driver> drivers = DriverManager.getDrivers();
  while (drivers.hasMoreElements()) {
    Driver driver = drivers.nextElement();
    registeredDrivers.put(driver.getClass().getName(), driver);
  }
}

    获取数据库连接是最终通过doGetCOnnection获取

private Connection doGetConnection(Properties properties) throws SQLException {
  initializeDriver(); //初始化驱动
  //获取连接
  Connection connection = DriverManager.getConnection(url, properties);
  //配置数据库的autocommit以及事务的级别
  configureConnection(connection);
  return connection;
}

PooledDataSource

    数据库连接耗时长,因此一般是通过数据库连接池实现数据库连接的管理,在初始化的时候,一般会在连接池中添加一定的连接备用,当需要使用数据库连接的时候,从池中获取连接,不再使用的时候,将连接放回连接池中,而不是直接关闭。PooledDataSource实现了简单的连接池功能,通过其封装的UnpooledDataSource创建新的连接。而且不会直接管理Connection,是通过管理PooledConnection来管理连接的。然后通过PooledState管理PooledConnection对象的连接状态。通过PopConnection方法获取连接,逻辑如下图:

private PooledConnection popConnection(String username, String password) throws SQLException {
  boolean countedWait = false;
  PooledConnection conn = null;
  long t = System.currentTimeMillis();
  int localBadConnectionCount = 0;

  while (conn == null) {
    synchronized (state) {
      if (!state.idleConnections.isEmpty()) { //检测空闲连接
        // Pool has available connection
        conn = state.idleConnections.remove(0); //获取连接
        if (log.isDebugEnabled()) {
          log.debug("Checked out connection " + conn.getRealHashCode() + " from pool.");
        }
      } else {
        // 没有空闲的连接,
        if (state.activeConnections.size() < poolMaximumActiveConnections) {
          // 活跃连接数没有达到最大值,可以创建新的连接
          conn = new PooledConnection(dataSource.getConnection(), this);
          if (log.isDebugEnabled()) {
            log.debug("Created connection " + conn.getRealHashCode() + ".");
          }
        } else {
          // 活跃连接数达到最大值,获取最先创建的连接
          PooledConnection oldestActiveConnection = state.activeConnections.get(0);
          long longestCheckoutTime = oldestActiveConnection.getCheckoutTime();
          //连接是否超时
          if (longestCheckoutTime > poolMaximumCheckoutTime) {
            // 对超时连接进行统计
            state.claimedOverdueConnectionCount++;
            state.accumulatedCheckoutTimeOfOverdueConnections += longestCheckoutTime;
            state.accumulatedCheckoutTime += longestCheckoutTime;
            //将起时连接移出活跃连接集合
            state.activeConnections.remove(oldestActiveConnection);
            if (!oldestActiveConnection.getRealConnection().getAutoCommit()) {
              oldestActiveConnection.getRealConnection().rollback();
            }
            //创建新的PooledConnection,没有创建数据库连接
            conn = new PooledConnection(oldestActiveConnection.getRealConnection(), this);
            oldestActiveConnection.invalidate();
            if (log.isDebugEnabled()) {
              log.debug("Claimed overdue connection " + conn.getRealHashCode() + ".");
            }
          } else {
            // 没有空闲连接,无法创建新的连接而且无超时连接,阻塞等待
            try {
              if (!countedWait) {
                state.hadToWaitCount++;
                countedWait = true;
              }
              if (log.isDebugEnabled()) {
                log.debug("Waiting as long as " + poolTimeToWait + " milliseconds for connection.");
              }
              long wt = System.currentTimeMillis();
              state.wait(poolTimeToWait);
              state.accumulatedWaitTime += System.currentTimeMillis() - wt;
            } catch (InterruptedException e) {
              break;
            }
          }
        }
      }
      if (conn != null) {
        if (conn.isValid()) {
          if (!conn.getRealConnection().getAutoCommit()) {
            conn.getRealConnection().rollback();
          }
          conn.setConnectionTypeCode(assembleConnectionTypeCode(dataSource.getUrl(), username, password));
          conn.setCheckoutTimestamp(System.currentTimeMillis());
          conn.setLastUsedTimestamp(System.currentTimeMillis());
          state.activeConnections.add(conn);
          state.requestCount++;
          state.accumulatedRequestTime += System.currentTimeMillis() - t;
        } else {
          if (log.isDebugEnabled()) {
            log.debug("A bad connection (" + conn.getRealHashCode() + ") was returned from the pool, getting another connection.");
          }
          state.badConnectionCount++;
          localBadConnectionCount++;
          conn = null;
          if (localBadConnectionCount > (poolMaximumIdleConnections + 3)) {
            if (log.isDebugEnabled()) {
              log.debug("PooledDataSource: Could not get a good connection to the database.");
            }
            throw new SQLException("PooledDataSource: Could not get a good connection to the database.");
          }
        }
      }
    }

  }

  if (conn == null) {
    if (log.isDebugEnabled()) {
      log.debug("PooledDataSource: Unknown severe error condition.  The connection pool returned a null connection.");
    }
    throw new SQLException("PooledDataSource: Unknown severe error condition.  The connection pool returned a null connection.");
  }

  return conn;
}

   使用完连接之后,通过pushConnection进行处理

PooledConnection

    继承了Invocationhandler接口,通过动态代理的方式对close进行代理,并且调用真正的数据库连接的方法前进行检查

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  String methodName = method.getName();
  //如果调用的方法是close,将其放回连接池,不是关闭
  if (CLOSE.hashCode() == methodName.hashCode() && CLOSE.equals(methodName)) {
    dataSource.pushConnection(this);
    return null;
  } else {
    try {
      if (!Object.class.equals(method.getDeclaringClass())) {
        // issue #579 toString() should never fail
        // throw an SQLException instead of a Runtime
        checkConnection();
      }
      //调用方法
      return method.invoke(realConnection, args);
    } catch (Throwable t) {
      throw ExceptionUtil.unwrapThrowable(t);
    }
  }
}

PooledState

    通过集合分别管理空闲状态的连接和活跃状态的连接

//空闲的PooledConnection集合
protected final List<PooledConnection> idleConnections = new ArrayList<PooledConnection>();
//活跃的PooledConnection集合
protected final List<PooledConnection> activeConnections = new ArrayList<PooledConnection>();
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值