protected Connection getConnection(Log statementLog) throws SQLException { Connection connection = transaction.getConnection(); if (statementLog.isDebugEnabled() || connectionLog.isDebugEnabled()) { return ConnectionLogger.newInstance(connection, statementLog); } else { return connection; } }
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; }
/* * 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; }
/* * 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."); } }
/** * 从数据库里查询总的记录数并计算总页数,回写进分页参数<code>PageParameter</code>,这样调用 者就可用通过 分页参数 <code>PageParameter * </code>获得相关信息。 * * @param sql * @param connection * @param mappedStatement * @param boundSql * @param page */ private void setPageParameter( String sql, Connection connection, MappedStatement mappedStatement, BoundSql boundSql, PageParameter page) { // 记录总记录数 String countSql = "select count(0) as total from (" + sql + ") tt"; PreparedStatement countStmt = null; ResultSet rs = null; try { countStmt = connection.prepareStatement(countSql); setParameters(countStmt, mappedStatement, boundSql); rs = countStmt.executeQuery(); int totalCount = 0; if (rs.next()) { totalCount = rs.getInt(1); } page.setTotalElements(totalCount); // int totalPage = totalCount / page.getPageSize() + ((totalCount % page.getPageSize() == 0) // ? 0 : 1); // page.setTotalPage(totalPage); } catch (SQLException e) { logger.error("Ignore this exception", e); } finally { try { rs.close(); } catch (SQLException e) { logger.error("Ignore this exception", e); } try { countStmt.close(); } catch (SQLException e) { logger.error("Ignore this exception", e); } } }
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; } }
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++; } } }
@Override public Object intercept(Invocation invocation) throws Throwable { StatementHandler statementHandler = (StatementHandler) invocation.getTarget(); MetaObject metaStatementHandler = MetaObject.forObject( statementHandler, DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY, DEFAULT_REFLECTOR_FACTORY); // 分离代理对象链(由于目标类可能被多个拦截器拦截,从而形成多次代理,通过下面的两次循环 // 可以分离出最原始的的目标类) while (metaStatementHandler.hasGetter("h")) { Object object = metaStatementHandler.getValue("h"); metaStatementHandler = MetaObject.forObject( object, DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY, DEFAULT_REFLECTOR_FACTORY); } // 分离最后一个代理对象的目标类 while (metaStatementHandler.hasGetter("target")) { Object object = metaStatementHandler.getValue("target"); metaStatementHandler = MetaObject.forObject( object, DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY, DEFAULT_REFLECTOR_FACTORY); } if (null == dialect || "".equals(dialect)) { logger.warn("Property dialect is not setted,use default 'mysql' "); dialect = defaultDialect; } if (null == pageSqlId || "".equals(pageSqlId)) { logger.warn("Property pageSqlId is not setted,use default '.*Page$' "); pageSqlId = defaultPageSqlId; } MappedStatement mappedStatement = (MappedStatement) metaStatementHandler.getValue("delegate.mappedStatement"); PageParameter page = null; Object type = metaStatementHandler.getValue("delegate.boundSql.parameterObject"); if (PageParameter.class.isInstance(type)) { page = (PageParameter) type; } // 只重写需要分页的sql语句。通过MappedStatement的ID匹配,默认重写以Page结尾的 // MappedStatement的sql if (mappedStatement.getId().matches(pageSqlId) && page != null && page.getLimit() > 0) { BoundSql boundSql = (BoundSql) metaStatementHandler.getValue("delegate.boundSql"); Object parameterObject = boundSql.getParameterObject(); if (parameterObject == null) { throw new NullPointerException("parameterObject is null!"); } else { // 分页参数作为参数对象parameterObject的一个属性 String sql = boundSql.getSql(); // 重写sql String pageSql = buildPageSql(sql, page, dialect); metaStatementHandler.setValue("delegate.boundSql.sql", pageSql); // 采用物理分页后,就不需要mybatis的内存分页了,所以重置下面的两个参数 metaStatementHandler.setValue("delegate.rowBounds.offset", RowBounds.NO_ROW_OFFSET); metaStatementHandler.setValue("delegate.rowBounds.limit", RowBounds.NO_ROW_LIMIT); Connection connection = (Connection) invocation.getArgs()[0]; // 重设分页参数里的总页数等 setPageParameter(sql, connection, mappedStatement, boundSql, page); } } // 将执行权交给下一个拦截器 return invocation.proceed(); }
protected void printQueryId(String queryId) { if (log.isDebugEnabled()) { log.debug("\t QueryId \t : " + queryId); } }
@Before public void setUp() throws SQLException { when(log.isDebugEnabled()).thenReturn(true); when(statement.execute(anyString())).thenReturn(true); st = StatementLogger.newInstance(statement, log, 1); }
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); }