/*
   * Method to check to see if a connection is still usable
   *
   * @param conn - the connection to check
   * @return True if the connection is still usable
   */
  protected boolean pingConnection(PooledConnection conn) { // 用连接做个查询,测试一个
    boolean result = true;

    try {
      result = !conn.getRealConnection().isClosed();
    } catch (SQLException e) {
      if (log.isDebugEnabled()) {
        log.debug("Connection " + conn.getRealHashCode() + " is BAD: " + e.getMessage());
      }
      result = false;
    }

    if (result) {
      if (poolPingEnabled) {
        if (poolPingConnectionsNotUsedFor >= 0
            && conn.getTimeElapsedSinceLastUse() > poolPingConnectionsNotUsedFor) {
          try {
            if (log.isDebugEnabled()) {
              log.debug("Testing connection " + conn.getRealHashCode() + " ...");
            }
            Connection realConn = conn.getRealConnection(); // 取出真连接
            Statement statement = realConn.createStatement();
            ResultSet rs = statement.executeQuery(poolPingQuery); // 测试一个
            rs.close();
            statement.close();
            if (!realConn.getAutoCommit()) {
              realConn.rollback();
            }
            result = true;
            if (log.isDebugEnabled()) {
              log.debug("Connection " + conn.getRealHashCode() + " is GOOD!");
            }
          } catch (Exception e) {
            log.warn("Execution of ping query '" + poolPingQuery + "' failed: " + e.getMessage());
            try {
              conn.getRealConnection().close();
            } catch (Exception e2) {
              // ignore
            }
            result = false;
            if (log.isDebugEnabled()) {
              log.debug("Connection " + conn.getRealHashCode() + " is BAD: " + e.getMessage());
            }
          }
        }
      }
    }
    return result;
  }
 private static Object crateProxy(
     Class<?> type,
     Callback callback,
     List<Class<?>> constructorArgTypes,
     List<Object> constructorArgs) {
   Enhancer enhancer = new Enhancer();
   enhancer.setCallback(callback);
   enhancer.setSuperclass(type);
   try {
     type.getDeclaredMethod(WRITE_REPLACE_METHOD);
     // ObjectOutputStream will call writeReplace of objects returned by writeReplace
     log.debug(
         WRITE_REPLACE_METHOD
             + " method was found on bean "
             + type
             + ", make sure it returns this");
   } catch (NoSuchMethodException e) {
     enhancer.setInterfaces(new Class[] {WriteReplaceInterface.class});
   } catch (SecurityException e) {
     // nothing to do here
   }
   Object enhanced = null;
   if (constructorArgTypes.isEmpty()) {
     enhanced = enhancer.create();
   } else {
     Class<?>[] typesArray = constructorArgTypes.toArray(new Class[constructorArgTypes.size()]);
     Object[] valuesArray = constructorArgs.toArray(new Object[constructorArgs.size()]);
     enhanced = enhancer.create(typesArray, valuesArray);
   }
   return enhanced;
 }
  protected void pushConnection(PooledConnection conn) throws SQLException { // 关闭一个连接,其实是放回pool

    synchronized (state) { // 加锁
      state.activeConnections.remove(conn); // 从活动list移出
      if (conn.isValid()) { // conn是有效的
        if (state.idleConnections.size() < poolMaximumIdleConnections
            && conn.getConnectionTypeCode() == expectedConnectionTypeCode) {
          state.accumulatedCheckoutTime += conn.getCheckoutTime();
          if (!conn.getRealConnection().getAutoCommit()) { // 不是自动提交的话
            conn.getRealConnection().rollback(); // 回滚
          }
          PooledConnection newConn =
              new PooledConnection(conn.getRealConnection(), this); // 新建一个连接,用原来的真连接
          state.idleConnections.add(newConn); // 加入空闲list
          newConn.setCreatedTimestamp(conn.getCreatedTimestamp());
          newConn.setLastUsedTimestamp(conn.getLastUsedTimestamp());
          conn.invalidate(); // 老连接标记为无效
          if (log.isDebugEnabled()) {
            log.debug("Returned connection " + newConn.getRealHashCode() + " to pool.");
          }
          state.notifyAll(); // 唤醒popConnection中等待连接的线程可以来抢state的锁
        } else {
          state.accumulatedCheckoutTime += conn.getCheckoutTime();
          if (!conn.getRealConnection().getAutoCommit()) {
            conn.getRealConnection().rollback(); // 回滚
          }
          conn.getRealConnection().close(); // 关闭
          if (log.isDebugEnabled()) {
            log.debug("Closed connection " + conn.getRealHashCode() + ".");
          }
          conn.invalidate();
        }
      } else {
        if (log.isDebugEnabled()) {
          log.debug(
              "A bad connection ("
                  + conn.getRealHashCode()
                  + ") attempted to return to the pool, discarding connection.");
        }
        state.badConnectionCount++;
      }
    }
  }
  protected void pushConnection(PooledConnection conn) throws SQLException {

    synchronized (state) {
      state.activeConnections.remove(conn);
      if (conn.isValid()) {
        if (state.idleConnections.size() < poolMaximumIdleConnections
            && conn.getConnectionTypeCode() == expectedConnectionTypeCode) {
          state.accumulatedCheckoutTime += conn.getCheckoutTime();
          if (!conn.getRealConnection().getAutoCommit()) {
            conn.getRealConnection().rollback();
          }
          PooledConnection newConn = new PooledConnection(conn.getRealConnection(), this);
          state.idleConnections.add(newConn);
          newConn.setCreatedTimestamp(conn.getCreatedTimestamp());
          newConn.setLastUsedTimestamp(conn.getLastUsedTimestamp());
          conn.invalidate();
          if (log.isDebugEnabled()) {
            log.debug("Returned connection " + newConn.getRealHashCode() + " to pool.");
          }
          state.notifyAll();
        } else {
          state.accumulatedCheckoutTime += conn.getCheckoutTime();
          if (!conn.getRealConnection().getAutoCommit()) {
            conn.getRealConnection().rollback();
          }
          conn.getRealConnection().close();
          if (log.isDebugEnabled()) {
            log.debug("Closed connection " + conn.getRealHashCode() + ".");
          }
          conn.invalidate();
        }
      } else {
        if (log.isDebugEnabled()) {
          log.debug(
              "A bad connection ("
                  + conn.getRealHashCode()
                  + ") attempted to return to the pool, discarding connection.");
        }
        state.badConnectionCount++;
      }
    }
  }
Beispiel #5
0
 public void close(boolean forceRollback) {
   try {
     try {
       rollback(forceRollback);
     } finally {
       if (transaction != null) transaction.close();
     }
   } catch (SQLException e) {
     // Ignore.  There's nothing that can be done at this point.
     log.debug("Unexpected exception on closing transaction.  Cause: " + e);
   } finally {
     transaction = null;
     deferredLoads = null;
     localCache = null;
     localOutputParameterCache = null;
     batchResults = null;
     closed = true;
   }
 }
  /*
   * Closes all active and idle connections in the pool
   */
  public void forceCloseAll() { // 关闭pool里的所有连接,两个list中的连接都移除且关闭
    synchronized (state) {
      expectedConnectionTypeCode =
          assembleConnectionTypeCode(
              dataSource.getUrl(), dataSource.getUsername(), dataSource.getPassword());
      for (int i = state.activeConnections.size(); i > 0; i--) { // 遍历活动连接list
        try {
          PooledConnection conn = state.activeConnections.remove(i - 1); // 从活动连接list移出
          conn.invalidate(); // PooledConnection的valid设为false

          Connection realConn = conn.getRealConnection(); // 获取真conn (java.sql.Connection)
          if (!realConn.getAutoCommit()) { // 不是自动提交的话
            realConn.rollback(); // 回滚
          }
          realConn.close();
        } catch (Exception e) {
          // ignore
        }
      }
      for (int i = state.idleConnections.size(); i > 0; i--) { // 简历空闲连接list
        try {
          PooledConnection conn = state.idleConnections.remove(i - 1);
          conn.invalidate();

          Connection realConn = conn.getRealConnection();
          if (!realConn.getAutoCommit()) {
            realConn.rollback();
          }
          realConn.close();
        } catch (Exception e) {
          // ignore
        }
      }
    }
    if (log.isDebugEnabled()) {
      log.debug("PooledDataSource forcefully closed/removed all connections.");
    }
  }
  /*
   * Closes all active and idle connections in the pool
   */
  public void forceCloseAll() {
    synchronized (state) {
      expectedConnectionTypeCode =
          assembleConnectionTypeCode(
              dataSource.getUrl(), dataSource.getUsername(), dataSource.getPassword());
      for (int i = state.activeConnections.size(); i > 0; i--) {
        try {
          PooledConnection conn = (PooledConnection) state.activeConnections.remove(i - 1);
          conn.invalidate();

          Connection realConn = conn.getRealConnection();
          if (!realConn.getAutoCommit()) {
            realConn.rollback();
          }
          realConn.close();
        } catch (Exception e) {
          // ignore
        }
      }
      for (int i = state.idleConnections.size(); i > 0; i--) {
        try {
          PooledConnection conn = (PooledConnection) state.idleConnections.remove(i - 1);
          conn.invalidate();

          Connection realConn = conn.getRealConnection();
          if (!realConn.getAutoCommit()) {
            realConn.rollback();
          }
          realConn.close();
        } catch (Exception e) {
          // ignore
        }
      }
    }
    if (log.isDebugEnabled()) {
      log.debug("PooledDataSource forcefully closed/removed all connections.");
    }
  }
 protected void printQueryId(String queryId) {
   if (log.isDebugEnabled()) {
     log.debug("\t QueryId	\t :	" + queryId);
   }
 }
  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里还有空闲连接
          // Pool has available connection
          conn = state.idleConnections.remove(0); // 从空闲list移出一个conn,用做新连接
          if (log.isDebugEnabled()) {
            log.debug("Checked out connection " + conn.getRealHashCode() + " from pool.");
          }
        } else { // pool里没有空闲连接了
          // Pool does not have available connection
          if (state.activeConnections.size() < poolMaximumActiveConnections) { // 活动list没有满
            // Can create new connection
            conn = new PooledConnection(dataSource.getConnection(), this); // 新建一个PooledConnection
            if (log.isDebugEnabled()) {
              log.debug("Created connection " + conn.getRealHashCode() + ".");
            }
          } else { // 活动list已经满了,无法创建新连接
            // Cannot create new connection
            PooledConnection oldestActiveConnection = state.activeConnections.get(0); // 获取最早开始活动的连接
            long longestCheckoutTime =
                oldestActiveConnection.getCheckoutTime(); // 获得最老的活动连接的checkout时间
            if (longestCheckoutTime > poolMaximumCheckoutTime) { // 如果checkout时间大于最大值
              // Can claim overdue connection
              state.claimedOverdueConnectionCount++; // 过期连接计数++
              state.accumulatedCheckoutTimeOfOverdueConnections +=
                  longestCheckoutTime; // 累加过期连接的checkout时间
              state.accumulatedCheckoutTime += longestCheckoutTime; // 累加checkout时间
              state.activeConnections.remove(oldestActiveConnection); // 从活动list移出最老的活动连接,留出空位来啦
              if (!oldestActiveConnection.getRealConnection().getAutoCommit()) {
                oldestActiveConnection.getRealConnection().rollback(); // 回滚
              }
              conn =
                  new PooledConnection(
                      oldestActiveConnection.getRealConnection(), this); // 新建连接,用最老连接的真连接
              oldestActiveConnection.invalidate(); // 最老连接标记无效
              if (log.isDebugEnabled()) {
                log.debug("Claimed overdue connection " + conn.getRealHashCode() + ".");
              }
            } else { // 如果checkout时间并没有超过最大值,必须等待
              // Must wait
              try {
                if (!countedWait) { // countedWait原来是false
                  state.hadToWaitCount++; // 必须等待的计数++
                  countedWait = true; // countedWait变为true
                }
                if (log.isDebugEnabled()) {
                  log.debug(
                      "Waiting as long as " + poolTimeToWait + " milliseconds for connection.");
                }
                long wt = System.currentTimeMillis();
                state.wait(
                    poolTimeToWait); // 等poolTimeToWait微秒,pushConnection移出一个连接时会notifyAll来唤醒wait的线程
                state.accumulatedWaitTime += System.currentTimeMillis() - wt;
              } catch (InterruptedException e) {
                break;
              }
            }
          }
        }
        if (conn != null) { // conn非空,确实建出来了
          if (conn.isValid()) { // conn有效
            if (!conn.getRealConnection().getAutoCommit()) {
              conn.getRealConnection().rollback(); // 这里回滚是干啥? hama
            }
            conn.setConnectionTypeCode(
                assembleConnectionTypeCode(dataSource.getUrl(), username, password));
            conn.setCheckoutTimestamp(System.currentTimeMillis());
            conn.setLastUsedTimestamp(System.currentTimeMillis());
            state.activeConnections.add(conn); // 加入活动list
            state.requestCount++;
            state.accumulatedRequestTime += System.currentTimeMillis() - t;
          } else { // conn无效
            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.");
            }
          }
        }
      }
    } // 到这里while结束

    if (conn == null) { // 出现了奇葩的Unknown错吧
      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;
  }
  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.size() > 0) {
          // Pool has available connection
          conn = (PooledConnection) state.idleConnections.remove(0);
          if (log.isDebugEnabled()) {
            log.debug("Checked out connection " + conn.getRealHashCode() + " from pool.");
          }
        } else {
          // Pool does not have available connection
          if (state.activeConnections.size() < poolMaximumActiveConnections) {
            // Can create new connection
            conn = new PooledConnection(dataSource.getConnection(), this);
            @SuppressWarnings("unused")
            // used in logging, if enabled
            Connection realConn = conn.getRealConnection();
            if (log.isDebugEnabled()) {
              log.debug("Created connection " + conn.getRealHashCode() + ".");
            }
          } else {
            // Cannot create new connection
            PooledConnection oldestActiveConnection =
                (PooledConnection) state.activeConnections.get(0);
            long longestCheckoutTime = oldestActiveConnection.getCheckoutTime();
            if (longestCheckoutTime > poolMaximumCheckoutTime) {
              // Can claim overdue connection
              state.claimedOverdueConnectionCount++;
              state.accumulatedCheckoutTimeOfOverdueConnections += longestCheckoutTime;
              state.accumulatedCheckoutTime += longestCheckoutTime;
              state.activeConnections.remove(oldestActiveConnection);
              if (!oldestActiveConnection.getRealConnection().getAutoCommit()) {
                oldestActiveConnection.getRealConnection().rollback();
              }
              conn = new PooledConnection(oldestActiveConnection.getRealConnection(), this);
              oldestActiveConnection.invalidate();
              if (log.isDebugEnabled()) {
                log.debug("Claimed overdue connection " + conn.getRealHashCode() + ".");
              }
            } else {
              // Must wait
              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;
  }
  /**
   * Build a {@code SqlSessionFactory} instance.
   *
   * <p>The default implementation uses the standard MyBatis {@code XMLConfigBuilder} API to build a
   * {@code SqlSessionFactory} instance based on an Reader.
   *
   * @return SqlSessionFactory
   * @throws IOException if loading the config file failed
   */
  protected SqlSessionFactory buildSqlSessionFactory() throws IOException {

    Configuration configuration;

    XMLConfigBuilder xmlConfigBuilder = null;
    if (this.configLocation != null) {
      xmlConfigBuilder =
          new XMLConfigBuilder(
              this.configLocation.getInputStream(), null, this.configurationProperties);
      configuration = xmlConfigBuilder.getConfiguration();
    } else {
      if (logger.isDebugEnabled()) {
        logger.debug(
            "Property 'configLocation' not specified, using default MyBatis Configuration");
      }
      configuration = new Configuration();
      configuration.setVariables(this.configurationProperties);
    }

    if (this.objectFactory != null) {
      configuration.setObjectFactory(this.objectFactory);
    }

    if (this.objectWrapperFactory != null) {
      configuration.setObjectWrapperFactory(this.objectWrapperFactory);
    }

    if (hasLength(this.typeAliasesPackage)) {
      String[] typeAliasPackageArray =
          tokenizeToStringArray(
              this.typeAliasesPackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
      for (String packageToScan : typeAliasPackageArray) {
        configuration
            .getTypeAliasRegistry()
            .registerAliases(
                packageToScan, typeAliasesSuperType == null ? Object.class : typeAliasesSuperType);
        if (logger.isDebugEnabled()) {
          logger.debug("Scanned package: '" + packageToScan + "' for aliases");
        }
      }
    }

    if (!isEmpty(this.typeAliases)) {
      for (Class<?> typeAlias : this.typeAliases) {
        configuration.getTypeAliasRegistry().registerAlias(typeAlias);
        if (logger.isDebugEnabled()) {
          logger.debug("Registered type alias: '" + typeAlias + "'");
        }
      }
    }

    if (!isEmpty(this.plugins)) {
      for (Interceptor plugin : this.plugins) {
        configuration.addInterceptor(plugin);
        if (logger.isDebugEnabled()) {
          logger.debug("Registered plugin: '" + plugin + "'");
        }
      }
    }

    if (hasLength(this.typeHandlersPackage)) {
      String[] typeHandlersPackageArray =
          tokenizeToStringArray(
              this.typeHandlersPackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
      for (String packageToScan : typeHandlersPackageArray) {
        configuration.getTypeHandlerRegistry().register(packageToScan);
        if (logger.isDebugEnabled()) {
          logger.debug("Scanned package: '" + packageToScan + "' for type handlers");
        }
      }
    }

    if (!isEmpty(this.typeHandlers)) {
      for (TypeHandler<?> typeHandler : this.typeHandlers) {
        configuration.getTypeHandlerRegistry().register(typeHandler);
        if (logger.isDebugEnabled()) {
          logger.debug("Registered type handler: '" + typeHandler + "'");
        }
      }
    }

    if (xmlConfigBuilder != null) {
      try {
        xmlConfigBuilder.parse();

        if (logger.isDebugEnabled()) {
          logger.debug("Parsed configuration file: '" + this.configLocation + "'");
        }
      } catch (Exception ex) {
        throw new NestedIOException("Failed to parse config resource: " + this.configLocation, ex);
      } finally {
        ErrorContext.instance().reset();
      }
    }

    if (this.transactionFactory == null) {
      this.transactionFactory = new SpringManagedTransactionFactory();
    }

    Environment environment =
        new Environment(this.environment, this.transactionFactory, this.dataSource);
    configuration.setEnvironment(environment);

    if (this.databaseIdProvider != null) {
      try {
        configuration.setDatabaseId(this.databaseIdProvider.getDatabaseId(this.dataSource));
      } catch (SQLException e) {
        throw new NestedIOException("Failed getting a databaseId", e);
      }
    }
    // TODO 增加location 获取加载xml的路径,也可配置
    String location = null;
    if (!isEmpty(this.mapperLocations)) {
      for (Resource mapperLocation : this.mapperLocations) {
        if (location == null) {
          location = mapperLocation.toString();
        }
        if (mapperLocation == null) {
          continue;
        }

        try {
          XMLMapperBuilder xmlMapperBuilder =
              new XMLMapperBuilder(
                  mapperLocation.getInputStream(),
                  configuration,
                  mapperLocation.toString(),
                  configuration.getSqlFragments());
          xmlMapperBuilder.parse();
        } catch (Exception e) {
          e.printStackTrace(); // 出现错误抛出异常
          throw new NestedIOException(
              "Failed to parse mapping resource: '" + mapperLocation + "'", e);
        } finally {
          ErrorContext.instance().reset();
        }

        if (logger.isDebugEnabled()) {
          logger.debug("Parsed mapper file: '" + mapperLocation + "'");
        }
      }
    } else {
      if (logger.isDebugEnabled()) {
        logger.debug("Property 'mapperLocations' was not specified or no matching resources found");
      }
    }

    // TODO 编译sqlsession时,启动定时器
    new org.apache.ibatis.thread.Runnable(location, configuration).run();

    return this.sqlSessionFactoryBuilder.build(configuration);
  }