public static boolean registerDriver(Driver driver) { try { DriverManager.registerDriver(driver); try { MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer(); ObjectName objectName = new ObjectName(MBEAN_NAME); if (!mbeanServer.isRegistered(objectName)) { mbeanServer.registerMBean(instance, objectName); } } catch (Throwable ex) { if (LOG == null) { LOG = LogFactory.getLog(DruidDriver.class); } LOG.warn("register druid-driver mbean error", ex); } return true; } catch (Exception e) { if (LOG == null) { LOG = LogFactory.getLog(DruidDriver.class); } LOG.error("registerDriver error", e); } return false; }
public class OracleValidConnectionChecker implements ValidConnectionChecker, Serializable { private static final long serialVersionUID = -2227528634302168877L; private static final Log LOG = LogFactory.getLog(OracleValidConnectionChecker.class); private final Class<?> clazz; private final Method ping; private static final Object[] params = new Object[] {new Integer(5000)}; public OracleValidConnectionChecker() { try { clazz = JdbcUtils.loadDriverClass("oracle.jdbc.driver.OracleConnection"); if (clazz != null) { ping = clazz.getMethod("pingDatabase", new Class[] {Integer.TYPE}); } else { ping = null; } } catch (Exception e) { throw new RuntimeException("Unable to resolve pingDatabase method:", e); } } public boolean isValidConnection( Connection conn, String valiateQuery, int validationQueryTimeout) { try { if (conn.isClosed()) { return false; } } catch (SQLException ex) { // skip return false; } if (valiateQuery == null) { return true; } try { if (conn instanceof DruidPooledConnection) { conn = ((DruidPooledConnection) conn).getConnection(); } if (conn instanceof ConnectionProxy) { conn = ((ConnectionProxy) conn).getRawObject(); } // unwrap if (clazz != null && clazz.isAssignableFrom(conn.getClass())) { Integer status = (Integer) ping.invoke(conn, params); // Error if (status.intValue() < 0) { return false; } return true; } Statement stmt = null; ResultSet rs = null; try { stmt = conn.createStatement(); rs = stmt.executeQuery(valiateQuery); return true; } catch (SQLException e) { return false; } catch (Exception e) { LOG.warn("Unexpected error in ping", e); return false; } finally { JdbcUtils.close(rs); JdbcUtils.close(stmt); } } catch (Exception e) { LOG.warn("Unexpected error in pingDatabase", e); } // OK return true; } }
public class JdbcDataSourceStat implements JdbcDataSourceStatMBean { private static final Log LOG = LogFactory.getLog(JdbcDataSourceStat.class); private final String name; private final String url; private String dbType; private final JdbcConnectionStat connectionStat = new JdbcConnectionStat(); private final JdbcResultSetStat resultSetStat = new JdbcResultSetStat(); private final JdbcStatementStat statementStat = new JdbcStatementStat(); private int maxSize = 1000 * 1; private ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); private final LinkedHashMap<String, JdbcSqlStat> sqlStatMap; private final Histogram connectionHoldHistogram = new Histogram( new long[] { // // 1, 10, 100, 1000, 10 * 1000, // 100 * 1000, 1000 * 1000 // }); private final ConcurrentMap<Long, JdbcConnectionStat.Entry> connections = new ConcurrentHashMap<Long, JdbcConnectionStat.Entry>(); private final AtomicLong clobOpenCount = new AtomicLong(); private final AtomicLong blobOpenCount = new AtomicLong(); public JdbcDataSourceStat(String name, String url) { this(name, url, null); } public JdbcDataSourceStat(String name, String url, String dbType) { this(name, url, dbType, null); } public JdbcDataSourceStat(String name, String url, String dbType, Properties connectProperties) { this.name = name; this.url = url; this.dbType = dbType; if (connectProperties != null) { Object arg = connectProperties.get(Constants.DRUID_STAT_SQL_MAX_SIZE); if (arg == null) { arg = System.getProperty(Constants.DRUID_STAT_SQL_MAX_SIZE); } if (arg != null) { try { maxSize = Integer.parseInt(arg.toString()); } catch (NumberFormatException ex) { LOG.error("maxSize parse error", ex); } } } sqlStatMap = new LRUCache<String, JdbcSqlStat>(maxSize, 16, 0.75f, false); } public void reset() { blobOpenCount.set(0); clobOpenCount.set(0); connectionStat.reset(); statementStat.reset(); resultSetStat.reset(); connectionHoldHistogram.reset(); lock.writeLock().lock(); try { Iterator<Map.Entry<String, JdbcSqlStat>> iter = sqlStatMap.entrySet().iterator(); while (iter.hasNext()) { Map.Entry<String, JdbcSqlStat> entry = iter.next(); JdbcSqlStat stat = entry.getValue(); if (stat.getExecuteCount() == 0 && stat.getRunningCount() == 0) { stat.setRemoved(true); iter.remove(); } else { stat.reset(); } } } finally { lock.writeLock().unlock(); } for (JdbcConnectionStat.Entry connectionStat : connections.values()) { connectionStat.reset(); } } public Histogram getConnectionHoldHistogram() { return connectionHoldHistogram; } public JdbcConnectionStat getConnectionStat() { return connectionStat; } public JdbcResultSetStat getResultSetStat() { return resultSetStat; } public JdbcStatementStat getStatementStat() { return statementStat; } @Override public String getConnectionUrl() { return url; } @Override public TabularData getSqlList() throws JMException { Map<String, JdbcSqlStat> sqlStatMap = this.getSqlStatMap(); CompositeType rowType = JdbcSqlStat.getCompositeType(); String[] indexNames = rowType.keySet().toArray(new String[rowType.keySet().size()]); TabularType tabularType = new TabularType("SqlListStatistic", "SqlListStatistic", rowType, indexNames); TabularData data = new TabularDataSupport(tabularType); for (Map.Entry<String, JdbcSqlStat> entry : sqlStatMap.entrySet()) { data.put(entry.getValue().getCompositeData()); } return data; } public static StatFilter getStatFilter(DataSourceProxy dataSource) { for (Filter filter : dataSource.getProxyFilters()) { if (filter instanceof StatFilter) { return (StatFilter) filter; } } return null; } public JdbcSqlStat getSqlStat(int id) { return getSqlStat((long) id); } public JdbcSqlStat getSqlStat(long id) { lock.readLock().lock(); try { for (Map.Entry<String, JdbcSqlStat> entry : this.sqlStatMap.entrySet()) { if (entry.getValue().getId() == id) { return entry.getValue(); } } return null; } finally { lock.readLock().unlock(); } } public final ConcurrentMap<Long, JdbcConnectionStat.Entry> getConnections() { return connections; } @Override public TabularData getConnectionList() throws JMException { CompositeType rowType = JdbcConnectionStat.Entry.getCompositeType(); String[] indexNames = rowType.keySet().toArray(new String[rowType.keySet().size()]); TabularType tabularType = new TabularType("ConnectionListStatistic", "ConnectionListStatistic", rowType, indexNames); TabularData data = new TabularDataSupport(tabularType); for (Map.Entry<Long, JdbcConnectionStat.Entry> entry : getConnections().entrySet()) { data.put(entry.getValue().getCompositeData()); } return data; } public String getName() { return name; } public String getUrl() { return url; } public Map<String, JdbcSqlStat> getSqlStatMap() { Map<String, JdbcSqlStat> map = new HashMap<String, JdbcSqlStat>(); lock.readLock().lock(); try { map.putAll(sqlStatMap); } finally { lock.readLock().unlock(); } return map; } public JdbcSqlStat getSqlStat(String sql) { lock.readLock().lock(); try { return sqlStatMap.get(sql); } finally { lock.readLock().unlock(); } } public JdbcSqlStat createSqlStat(String sql) { lock.writeLock().lock(); try { JdbcSqlStat sqlStat = sqlStatMap.get(sql); if (sqlStat == null) { sqlStat = new JdbcSqlStat(sql); sqlStat.setDbType(this.dbType); sqlStatMap.put(sql, sqlStat); } return sqlStat; } finally { lock.writeLock().unlock(); } } @Override public long getConnectionActiveCount() { return this.connections.size(); } @Override public long getConnectionConnectAliveMillis() { long nowNano = System.nanoTime(); long aliveNanoSpan = this.getConnectionStat().getAliveTotal(); for (JdbcConnectionStat.Entry connection : connections.values()) { aliveNanoSpan += nowNano - connection.getEstablishNano(); } return aliveNanoSpan / (1000 * 1000); } public long getConnectionConnectAliveMillisMax() { long max = this.getConnectionStat().getAliveNanoMax(); long nowNano = System.nanoTime(); for (JdbcConnectionStat.Entry connection : connections.values()) { long connectionAliveNano = nowNano - connection.getEstablishNano(); if (connectionAliveNano > max) { max = connectionAliveNano; } } return max / (1000 * 1000); } public long getConnectionConnectAliveMillisMin() { long min = this.getConnectionStat().getAliveNanoMin(); long nowNano = System.nanoTime(); for (JdbcConnectionStat.Entry connection : connections.values()) { long connectionAliveNano = nowNano - connection.getEstablishNano(); if (connectionAliveNano < min || min == 0) { min = connectionAliveNano; } } return min / (1000 * 1000); } public long[] getConnectionHistogramRanges() { return connectionStat.getHistogramRanges(); } public long[] getConnectionHistogramValues() { return connectionStat.getHistorgramValues(); } public long getClobOpenCount() { return clobOpenCount.get(); } public void incrementClobOpenCount() { clobOpenCount.incrementAndGet(); } public long getBlobOpenCount() { return blobOpenCount.get(); } public void incrementBlobOpenCount() { blobOpenCount.incrementAndGet(); } }
/** * 注意:避免直接调用Druid相关对象例如DruidDataSource等,相关调用要到DruidStatManagerFacade里用反射实现 * * @author sandzhang[[email protected]] */ public final class DruidStatService implements DruidStatServiceMBean { private static final Log LOG = LogFactory.getLog(DruidStatService.class); public static final String MBEAN_NAME = "com.alibaba.druid:type=DruidStatService"; private static final DruidStatService instance = new DruidStatService(); private static DruidStatManagerFacade statManagerFacade = DruidStatManagerFacade.getInstance(); public static final int RESULT_CODE_SUCCESS = 1; public static final int RESULT_CODE_ERROR = -1; private static final int DEFAULT_PAGE = 1; private static final int DEFAULT_PER_PAGE_COUNT = Integer.MAX_VALUE; private static final String DEFAULT_ORDER_TYPE = "asc"; private static final String DEFAULT_ORDERBY = "SQL"; private DruidStatService() {} public static DruidStatService getInstance() { return instance; } public boolean isResetEnable() { return statManagerFacade.isResetEnable(); } public void setResetEnable(boolean value) { statManagerFacade.setResetEnable(value); } public String service(String url) { Map<String, String> parameters = getParameters(url); if (url.equals("/basic.json")) { return returnJSONResult(RESULT_CODE_SUCCESS, statManagerFacade.returnJSONBasicStat()); } if (url.equals("/reset-all.json")) { statManagerFacade.resetAll(); return returnJSONResult(RESULT_CODE_SUCCESS, null); } if (url.equals("/log-and-reset.json")) { statManagerFacade.logAndResetDataSource(); return returnJSONResult(RESULT_CODE_SUCCESS, null); } if (url.equals("/datasource.json")) { return returnJSONResult(RESULT_CODE_SUCCESS, statManagerFacade.getDataSourceStatDataList()); } if (url.equals("/activeConnectionStackTrace.json")) { return returnJSONResult(RESULT_CODE_SUCCESS, statManagerFacade.getActiveConnStackTraceList()); } if (url.startsWith("/datasource-")) { Integer id = StringUtils.subStringToInteger(url, "datasource-", "."); Object result = statManagerFacade.getDataSourceStatData(id); return returnJSONResult(result == null ? RESULT_CODE_ERROR : RESULT_CODE_SUCCESS, result); } if (url.startsWith("/connectionInfo-") && url.endsWith(".json")) { Integer id = StringUtils.subStringToInteger(url, "connectionInfo-", "."); List<?> connectionInfoList = statManagerFacade.getPoolingConnectionInfoByDataSourceId(id); return returnJSONResult( connectionInfoList == null ? RESULT_CODE_ERROR : RESULT_CODE_SUCCESS, connectionInfoList); } if (url.startsWith("/activeConnectionStackTrace-") && url.endsWith(".json")) { Integer id = StringUtils.subStringToInteger(url, "activeConnectionStackTrace-", "."); return returnJSONActiveConnectionStackTrace(id); } if (url.startsWith("/sql.json")) { return returnJSONResult(RESULT_CODE_SUCCESS, getSqlStatDataList(parameters)); } if (url.startsWith("/wall.json")) { return returnJSONResult(RESULT_CODE_SUCCESS, getWallStatMap(parameters)); } if (url.startsWith("/wall-") && url.indexOf(".json") > 0) { Integer dataSourceId = StringUtils.subStringToInteger(url, "wall-", ".json"); Object result = statManagerFacade.getWallStatMap(dataSourceId); return returnJSONResult(result == null ? RESULT_CODE_ERROR : RESULT_CODE_SUCCESS, result); } if (url.startsWith("/sql-") && url.indexOf(".json") > 0) { Integer id = StringUtils.subStringToInteger(url, "sql-", ".json"); return getSqlStat(id); } if (url.startsWith("/weburi.json")) { return returnJSONResult(RESULT_CODE_SUCCESS, getWebURIStatDataList(parameters)); } if (url.startsWith("/weburi-") && url.indexOf(".json") > 0) { String uri = StringUtils.subString(url, "weburi-", ".json"); return returnJSONResult(RESULT_CODE_SUCCESS, getWebURIStatData(uri)); } if (url.startsWith("/webapp.json")) { return returnJSONResult(RESULT_CODE_SUCCESS, getWebAppStatDataList(parameters)); } if (url.startsWith("/websession.json")) { return returnJSONResult(RESULT_CODE_SUCCESS, getWebSessionStatDataList(parameters)); } if (url.startsWith("/websession-") && url.indexOf(".json") > 0) { String id = StringUtils.subString(url, "websession-", ".json"); return returnJSONResult(RESULT_CODE_SUCCESS, getWebSessionStatData(id)); } if (url.startsWith("/spring.json")) { return returnJSONResult(RESULT_CODE_SUCCESS, getSpringStatDataList(parameters)); } if (url.startsWith("/spring-detail.json")) { String clazz = parameters.get("class"); String method = parameters.get("method"); return returnJSONResult(RESULT_CODE_SUCCESS, getSpringMethodStatData(clazz, method)); } return returnJSONResult( RESULT_CODE_ERROR, "Do not support this request, please contact with administrator."); } private List<Map<String, Object>> getSpringStatDataList(Map<String, String> parameters) { List<Map<String, Object>> array = SpringStatManager.getInstance().getMethodStatData(); return comparatorOrderBy(array, parameters); } private List<Map<String, Object>> getWebURIStatDataList(Map<String, String> parameters) { List<Map<String, Object>> array = WebAppStatManager.getInstance().getURIStatData(); return comparatorOrderBy(array, parameters); } private Map<String, Object> getWebURIStatData(String uri) { return WebAppStatManager.getInstance().getURIStatData(uri); } private Map<String, Object> getWebSessionStatData(String sessionId) { return WebAppStatManager.getInstance().getSessionStat(sessionId); } private Map<String, Object> getSpringMethodStatData(String clazz, String method) { return SpringStatManager.getInstance().getMethodStatData(clazz, method); } private List<Map<String, Object>> getWebSessionStatDataList(Map<String, String> parameters) { List<Map<String, Object>> array = WebAppStatManager.getInstance().getSessionStatData(); return comparatorOrderBy(array, parameters); } private List<Map<String, Object>> getWebAppStatDataList(Map<String, String> parameters) { List<Map<String, Object>> array = WebAppStatManager.getInstance().getWebAppStatData(); return comparatorOrderBy(array, parameters); } private List<Map<String, Object>> comparatorOrderBy( List<Map<String, Object>> array, Map<String, String> parameters) { // when open the stat page before executing some sql if (array == null || array.isEmpty()) { return null; } // when parameters is null String orderBy, orderType = null; Integer page = DEFAULT_PAGE; Integer perPageCount = DEFAULT_PER_PAGE_COUNT; if (parameters == null) { orderBy = DEFAULT_ORDER_TYPE; orderType = DEFAULT_ORDER_TYPE; page = DEFAULT_PAGE; perPageCount = DEFAULT_PER_PAGE_COUNT; } else { orderBy = parameters.get("orderBy"); orderType = parameters.get("orderType"); String pageParam = parameters.get("page"); if (pageParam != null && pageParam.length() != 0) { page = Integer.parseInt(pageParam); } String pageCountParam = parameters.get("perPageCount"); if (pageCountParam != null && pageCountParam.length() > 0) { perPageCount = Integer.parseInt(pageCountParam); } } // others,such as order orderBy = orderBy == null ? DEFAULT_ORDERBY : orderBy; orderType = orderType == null ? DEFAULT_ORDER_TYPE : orderType; if (!"desc".equals(orderType)) { orderType = DEFAULT_ORDER_TYPE; } // orderby the statData array if (orderBy != null && orderBy.trim().length() != 0) { Collections.sort( array, new MapComparator<String, Object>(orderBy, DEFAULT_ORDER_TYPE.equals(orderType))); } // page int fromIndex = (page - 1) * perPageCount; int toIndex = page * perPageCount; if (toIndex > array.size()) { toIndex = array.size(); } return array.subList(fromIndex, toIndex); } private List<Map<String, Object>> getSqlStatDataList(Map<String, String> parameters) { Integer dataSourceId = null; String dataSourceIdParam = parameters.get("dataSourceId"); if (dataSourceIdParam != null && dataSourceIdParam.length() > 0) { dataSourceId = Integer.parseInt(dataSourceIdParam); } List<Map<String, Object>> array = statManagerFacade.getSqlStatDataList(dataSourceId); List<Map<String, Object>> sortedArray = comparatorOrderBy(array, parameters); return sortedArray; } @SuppressWarnings("unchecked") public Map<String, Object> getWallStatMap(Map<String, String> parameters) { Integer dataSourceId = null; String dataSourceIdParam = parameters.get("dataSourceId"); if (dataSourceIdParam != null && dataSourceIdParam.length() > 0) { dataSourceId = Integer.parseInt(dataSourceIdParam); } Map<String, Object> result = statManagerFacade.getWallStatMap(dataSourceId); if (result != null) { List<Map<String, Object>> tables = (List<Map<String, Object>>) result.get("tables"); if (tables != null) { List<Map<String, Object>> sortedArray = comparatorOrderBy(tables, parameters); result.put("tables", sortedArray); } List<Map<String, Object>> functions = (List<Map<String, Object>>) result.get("functions"); if (functions != null) { List<Map<String, Object>> sortedArray = comparatorOrderBy(functions, parameters); result.put("functions", sortedArray); } } else { result = Collections.emptyMap(); } return result; } private String getSqlStat(Integer id) { Map<String, Object> map = statManagerFacade.getSqlStatData(id); if (map == null) { return returnJSONResult(RESULT_CODE_ERROR, null); } String dbType = (String) map.get("DbType"); String sql = (String) map.get("SQL"); map.put("formattedSql", SQLUtils.format(sql, dbType)); List<SQLStatement> statementList = SQLUtils.parseStatements(sql, dbType); if (!statementList.isEmpty()) { SQLStatement sqlStmt = statementList.get(0); SchemaStatVisitor visitor = SQLUtils.createSchemaStatVisitor(dbType); sqlStmt.accept(visitor); map.put("parsedTable", visitor.getTables().toString()); map.put("parsedFields", visitor.getColumns().toString()); map.put("parsedConditions", visitor.getConditions().toString()); map.put("parsedRelationships", visitor.getRelationships().toString()); map.put("parsedOrderbycolumns", visitor.getOrderByColumns().toString()); } DateFormat format = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss:SSS"); Date maxTimespanOccurTime = (Date) map.get("MaxTimespanOccurTime"); if (maxTimespanOccurTime != null) { map.put("MaxTimespanOccurTime", format.format(maxTimespanOccurTime)); } return returnJSONResult(map == null ? RESULT_CODE_ERROR : RESULT_CODE_SUCCESS, map); } private String returnJSONActiveConnectionStackTrace(Integer id) { List<String> result = statManagerFacade.getActiveConnectionStackTraceByDataSourceId(id); if (result == null) { return returnJSONResult(RESULT_CODE_ERROR, "require set removeAbandoned=true"); } return returnJSONResult(RESULT_CODE_SUCCESS, result); } public static String returnJSONResult(int resultCode, Object content) { Map<String, Object> dataMap = new LinkedHashMap<String, Object>(); dataMap.put("ResultCode", resultCode); dataMap.put("Content", content); return JSONUtils.toJSONString(dataMap); } public static void registerMBean() { MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer(); try { ObjectName objectName = new ObjectName(MBEAN_NAME); if (!mbeanServer.isRegistered(objectName)) { mbeanServer.registerMBean(instance, objectName); } } catch (JMException ex) { LOG.error("register mbean error", ex); } } public static void unregisterMBean() { MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer(); try { mbeanServer.unregisterMBean(new ObjectName(MBEAN_NAME)); } catch (JMException ex) { LOG.error("unregister mbean error", ex); } } public static Map<String, String> getParameters(String url) { if (url == null || (url = url.trim()).length() == 0) { return Collections.<String, String>emptyMap(); } String parametersStr = StringUtils.subString(url, "?", null); if (parametersStr == null || parametersStr.length() == 0) { return Collections.<String, String>emptyMap(); } String[] parametersArray = parametersStr.split("&"); Map<String, String> parameters = new LinkedHashMap<String, String>(); for (String parameterStr : parametersArray) { int index = parameterStr.indexOf("="); if (index <= 0) { continue; } String name = parameterStr.substring(0, index); String value = parameterStr.substring(index + 1); parameters.put(name, value); } return parameters; } }
/** @author wenshao<*****@*****.**> */ public class DruidPooledConnection extends PoolableWrapper implements javax.sql.PooledConnection, Connection { private static final Log LOG = LogFactory.getLog(DruidPooledConnection.class); public static final int MAX_RECORD_SQL_COUNT = 10; protected Connection conn; protected volatile DruidConnectionHolder holder; protected TransactionInfo transactionInfo; private final boolean dupCloseLogEnable; private volatile boolean traceEnable = false; private boolean disable = false; private boolean closed = false; private final Thread ownerThread; private long connectedTimeNano; private volatile boolean running = false; private volatile boolean abandoned = false; private StackTraceElement[] connectStackTrace; private Throwable disableError = null; public DruidPooledConnection(DruidConnectionHolder holder) { super(holder.getConnection()); this.conn = holder.getConnection(); this.holder = holder; dupCloseLogEnable = holder.getDataSource().isDupCloseLogEnable(); ownerThread = Thread.currentThread(); } public Thread getOwnerThread() { return ownerThread; } public StackTraceElement[] getConnectStackTrace() { return connectStackTrace; } public void setConnectStackTrace(StackTraceElement[] connectStackTrace) { this.connectStackTrace = connectStackTrace; } public long getConnectedTimeNano() { return connectedTimeNano; } public void setConnectedTimeNano() { if (connectedTimeNano <= 0) { this.setConnectedTimeNano(System.nanoTime()); } } public void setConnectedTimeNano(long connectedTimeNano) { this.connectedTimeNano = connectedTimeNano; } public boolean isTraceEnable() { return traceEnable; } public void setTraceEnable(boolean traceEnable) { this.traceEnable = traceEnable; } public SQLException handleException(Throwable t) throws SQLException { final DruidConnectionHolder holder = this.holder; // if (holder != null) { DruidAbstractDataSource dataSource = holder.getDataSource(); dataSource.handleConnectionException(this, t); } if (t instanceof SQLException) { throw (SQLException) t; } throw new SQLException("Error", t); } public boolean isOracle() { return holder.getDataSource().isOracle(); } public void closePoolableStatement(DruidPooledPreparedStatement stmt) throws SQLException { PreparedStatement rawStatement = stmt.getRawPreparedStatement(); if (holder == null) { return; } if (stmt.isPooled()) { try { rawStatement.clearParameters(); } catch (SQLException ex) { this.handleException(ex); if (rawStatement.getConnection().isClosed()) { return; } LOG.error("clear parameter error", ex); } } stmt.getPreparedStatementHolder().decrementInUseCount(); if (stmt.isPooled() && holder.isPoolPreparedStatements()) { holder.getStatementPool().put(stmt.getPreparedStatementHolder()); stmt.clearResultSet(); holder.removeTrace(stmt); stmt.getPreparedStatementHolder().setFetchRowPeak(stmt.getFetchRowPeak()); stmt.setClosed(true); // soft set close } else { stmt.closeInternal(); holder.getDataSource().incrementClosedPreparedStatementCount(); } } public DruidConnectionHolder getConnectionHolder() { return holder; } @Override public Connection getConnection() { return conn; } public void disable() { disable(null); } public void disable(Throwable error) { if (this.holder != null) { this.holder.clearStatementCache(); } this.traceEnable = false; this.holder = null; this.transactionInfo = null; this.disable = true; this.disableError = error; } public boolean isDisable() { return disable; } @Override public void close() throws SQLException { if (this.disable) { return; } DruidConnectionHolder holder = this.holder; if (holder == null) { if (dupCloseLogEnable) { LOG.error("dup close"); } return; } if (holder.getDataSource().isRemoveAbandoned()) { syncClose(); return; } for (ConnectionEventListener listener : holder.getConnectionEventListeners()) { listener.connectionClosed(new ConnectionEvent(this)); } DruidAbstractDataSource dataSource = holder.getDataSource(); List<Filter> filters = dataSource.getProxyFilters(); if (filters.size() > 0) { FilterChainImpl filterChain = new FilterChainImpl(dataSource); filterChain.dataSource_recycle(this); } else { recycle(); } this.disable = true; } public synchronized void syncClose() throws SQLException { if (this.disable) { return; } DruidConnectionHolder holder = this.holder; if (holder == null) { if (dupCloseLogEnable) { LOG.error("dup close"); } return; } for (ConnectionEventListener listener : holder.getConnectionEventListeners()) { listener.connectionClosed(new ConnectionEvent(this)); } DruidAbstractDataSource dataSource = holder.getDataSource(); List<Filter> filters = dataSource.getProxyFilters(); if (filters.size() > 0) { FilterChainImpl filterChain = new FilterChainImpl(dataSource); filterChain.dataSource_recycle(this); } else { recycle(); } this.disable = true; } public void recycle() throws SQLException { if (this.disable) { return; } DruidConnectionHolder holder = this.holder; if (holder == null) { if (dupCloseLogEnable) { LOG.error("dup close"); } return; } if (!this.abandoned) { DruidAbstractDataSource dataSource = holder.getDataSource(); dataSource.recycle(this); } this.holder = null; conn = null; transactionInfo = null; closed = true; } // //////////////////// @Override public PreparedStatement prepareStatement(String sql) throws SQLException { checkState(); PreparedStatementHolder stmtHolder = null; PreparedStatementKey key = new PreparedStatementKey(sql, getCatalog(), MethodType.M1); boolean poolPreparedStatements = holder.isPoolPreparedStatements(); if (poolPreparedStatements) { stmtHolder = holder.getStatementPool().get(key); } if (stmtHolder == null) { try { stmtHolder = new PreparedStatementHolder(key, conn.prepareStatement(sql)); holder.getDataSource().incrementPreparedStatementCount(); } catch (SQLException ex) { handleException(ex); } } initStatement(stmtHolder); DruidPooledPreparedStatement rtnVal = new DruidPooledPreparedStatement(this, stmtHolder); holder.addTrace(rtnVal); return rtnVal; } private void initStatement(PreparedStatementHolder stmtHolder) throws SQLException { stmtHolder.incrementInUseCount(); holder.getDataSource().initStatement(this, stmtHolder.getStatement()); } @Override public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { checkState(); PreparedStatementHolder stmtHolder = null; PreparedStatementKey key = new PreparedStatementKey( sql, getCatalog(), MethodType.M2, resultSetType, resultSetConcurrency); boolean poolPreparedStatements = holder.isPoolPreparedStatements(); if (poolPreparedStatements) { stmtHolder = holder.getStatementPool().get(key); } if (stmtHolder == null) { try { stmtHolder = new PreparedStatementHolder( key, conn.prepareStatement(sql, resultSetType, resultSetConcurrency)); holder.getDataSource().incrementPreparedStatementCount(); } catch (SQLException ex) { handleException(ex); } } initStatement(stmtHolder); DruidPooledPreparedStatement rtnVal = new DruidPooledPreparedStatement(this, stmtHolder); holder.addTrace(rtnVal); return rtnVal; } @Override public PreparedStatement prepareStatement( String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { checkState(); PreparedStatementHolder stmtHolder = null; PreparedStatementKey key = new PreparedStatementKey( sql, getCatalog(), MethodType.M3, resultSetType, resultSetConcurrency, resultSetHoldability); boolean poolPreparedStatements = holder.isPoolPreparedStatements(); if (poolPreparedStatements) { stmtHolder = holder.getStatementPool().get(key); } if (stmtHolder == null) { try { stmtHolder = new PreparedStatementHolder( key, conn.prepareStatement( sql, resultSetType, resultSetConcurrency, resultSetHoldability)); holder.getDataSource().incrementPreparedStatementCount(); } catch (SQLException ex) { handleException(ex); } } initStatement(stmtHolder); DruidPooledPreparedStatement rtnVal = new DruidPooledPreparedStatement(this, stmtHolder); holder.addTrace(rtnVal); return rtnVal; } @Override public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException { checkState(); PreparedStatementKey key = new PreparedStatementKey(sql, getCatalog(), MethodType.M4, columnIndexes); PreparedStatementHolder stmtHolder = null; boolean poolPreparedStatements = holder.isPoolPreparedStatements(); if (poolPreparedStatements) { stmtHolder = holder.getStatementPool().get(key); } if (stmtHolder == null) { try { stmtHolder = new PreparedStatementHolder(key, conn.prepareStatement(sql, columnIndexes)); holder.getDataSource().incrementPreparedStatementCount(); } catch (SQLException ex) { handleException(ex); } } initStatement(stmtHolder); DruidPooledPreparedStatement rtnVal = new DruidPooledPreparedStatement(this, stmtHolder); holder.addTrace(rtnVal); return rtnVal; } @Override public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException { checkState(); PreparedStatementKey key = new PreparedStatementKey(sql, getCatalog(), MethodType.M5, columnNames); PreparedStatementHolder stmtHolder = null; boolean poolPreparedStatements = holder.isPoolPreparedStatements(); if (poolPreparedStatements) { stmtHolder = holder.getStatementPool().get(key); } if (stmtHolder == null) { try { stmtHolder = new PreparedStatementHolder(key, conn.prepareStatement(sql, columnNames)); holder.getDataSource().incrementPreparedStatementCount(); } catch (SQLException ex) { handleException(ex); } } initStatement(stmtHolder); DruidPooledPreparedStatement rtnVal = new DruidPooledPreparedStatement(this, stmtHolder); holder.addTrace(rtnVal); return rtnVal; } @Override public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { checkState(); PreparedStatementKey key = new PreparedStatementKey(sql, getCatalog(), MethodType.M6, autoGeneratedKeys); PreparedStatementHolder stmtHolder = null; boolean poolPreparedStatements = holder.isPoolPreparedStatements(); if (poolPreparedStatements) { stmtHolder = holder.getStatementPool().get(key); } if (stmtHolder == null) { try { stmtHolder = new PreparedStatementHolder(key, conn.prepareStatement(sql, autoGeneratedKeys)); holder.getDataSource().incrementPreparedStatementCount(); } catch (SQLException ex) { handleException(ex); } } initStatement(stmtHolder); DruidPooledPreparedStatement rtnVal = new DruidPooledPreparedStatement(this, stmtHolder); holder.addTrace(rtnVal); return rtnVal; } // //////////////////// @Override public CallableStatement prepareCall(String sql) throws SQLException { checkState(); PreparedStatementHolder stmtHolder = null; PreparedStatementKey key = new PreparedStatementKey(sql, getCatalog(), MethodType.Precall_1); boolean poolPreparedStatements = holder.isPoolPreparedStatements(); if (poolPreparedStatements) { stmtHolder = holder.getStatementPool().get(key); } if (stmtHolder == null) { try { stmtHolder = new PreparedStatementHolder(key, conn.prepareCall(sql)); holder.getDataSource().incrementPreparedStatementCount(); } catch (SQLException ex) { handleException(ex); } } initStatement(stmtHolder); DruidPooledCallableStatement rtnVal = new DruidPooledCallableStatement(this, stmtHolder); holder.addTrace(rtnVal); return rtnVal; } @Override public CallableStatement prepareCall( String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { checkState(); PreparedStatementHolder stmtHolder = null; PreparedStatementKey key = new PreparedStatementKey( sql, getCatalog(), MethodType.Precall_2, resultSetType, resultSetConcurrency, resultSetHoldability); boolean poolPreparedStatements = holder.isPoolPreparedStatements(); if (poolPreparedStatements) { stmtHolder = holder.getStatementPool().get(key); } if (stmtHolder == null) { try { stmtHolder = new PreparedStatementHolder( key, conn.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability)); holder.getDataSource().incrementPreparedStatementCount(); } catch (SQLException ex) { handleException(ex); } } initStatement(stmtHolder); DruidPooledCallableStatement rtnVal = new DruidPooledCallableStatement(this, stmtHolder); holder.addTrace(rtnVal); return rtnVal; } @Override public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { checkState(); PreparedStatementHolder stmtHolder = null; PreparedStatementKey key = new PreparedStatementKey( sql, getCatalog(), MethodType.Precall_3, resultSetType, resultSetConcurrency); boolean poolPreparedStatements = holder.isPoolPreparedStatements(); if (poolPreparedStatements) { stmtHolder = holder.getStatementPool().get(key); } if (stmtHolder == null) { try { stmtHolder = new PreparedStatementHolder( key, conn.prepareCall(sql, resultSetType, resultSetConcurrency)); holder.getDataSource().incrementPreparedStatementCount(); } catch (SQLException ex) { handleException(ex); } } initStatement(stmtHolder); DruidPooledCallableStatement rtnVal = new DruidPooledCallableStatement(this, stmtHolder); holder.addTrace(rtnVal); return rtnVal; } // //////////////////// @Override public Statement createStatement() throws SQLException { checkState(); Statement stmt = null; try { stmt = conn.createStatement(); } catch (SQLException ex) { handleException(ex); } holder.getDataSource().initStatement(this, stmt); DruidPooledStatement poolableStatement = new DruidPooledStatement(this, stmt); holder.addTrace(poolableStatement); return poolableStatement; } @Override public Statement createStatement( int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { checkState(); Statement stmt = null; try { stmt = conn.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability); } catch (SQLException ex) { handleException(ex); } holder.getDataSource().initStatement(this, stmt); DruidPooledStatement poolableStatement = new DruidPooledStatement(this, stmt); holder.addTrace(poolableStatement); return poolableStatement; } @Override public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { checkState(); Statement stmt = null; try { stmt = conn.createStatement(resultSetType, resultSetConcurrency); } catch (SQLException ex) { handleException(ex); } holder.getDataSource().initStatement(this, stmt); DruidPooledStatement poolableStatement = new DruidPooledStatement(this, stmt); holder.addTrace(poolableStatement); return poolableStatement; } @Override public String nativeSQL(String sql) throws SQLException { checkState(); return conn.nativeSQL(sql); } @Override public void setAutoCommit(boolean autoCommit) throws SQLException { checkState(); boolean useLocalSessionState = holder.getDataSource().isUseLocalSessionState(); if (useLocalSessionState) { if (autoCommit == holder.isUnderlyingAutoCommit()) { return; } } try { conn.setAutoCommit(autoCommit); holder.setUnderlyingAutoCommit(autoCommit); } catch (SQLException ex) { handleException(ex); } } protected void transactionRecord(String sql) throws SQLException { if (transactionInfo == null && (!conn.getAutoCommit())) { DruidAbstractDataSource dataSource = holder.getDataSource(); dataSource.incrementStartTransactionCount(); transactionInfo = new TransactionInfo(dataSource.createTransactionId()); } if (transactionInfo != null) { List<String> sqlList = transactionInfo.getSqlList(); if (sqlList.size() < MAX_RECORD_SQL_COUNT) { sqlList.add(sql); } } } @Override public boolean getAutoCommit() throws SQLException { checkState(); return conn.getAutoCommit(); } @Override public void commit() throws SQLException { checkState(); DruidAbstractDataSource dataSource = holder.getDataSource(); dataSource.incrementCommitCount(); try { conn.commit(); } catch (SQLException ex) { handleException(ex); } finally { handleEndTransaction(dataSource, null); } } public TransactionInfo getTransactionInfo() { return transactionInfo; } @Override public void rollback() throws SQLException { if (transactionInfo == null) { return; } if (holder == null) { return; } DruidAbstractDataSource dataSource = holder.getDataSource(); dataSource.incrementRollbackCount(); try { conn.rollback(); } catch (SQLException ex) { handleException(ex); } finally { handleEndTransaction(dataSource, null); } } @Override public Savepoint setSavepoint(String name) throws SQLException { checkState(); try { return conn.setSavepoint(name); } catch (SQLException ex) { handleException(ex); return null; // never arrive } } @Override public void rollback(Savepoint savepoint) throws SQLException { if (holder == null) { return; } DruidAbstractDataSource dataSource = holder.getDataSource(); dataSource.incrementRollbackCount(); try { conn.rollback(savepoint); } catch (SQLException ex) { handleException(ex); } finally { handleEndTransaction(dataSource, savepoint); } } private void handleEndTransaction(DruidAbstractDataSource dataSource, Savepoint savepoint) { if (transactionInfo != null && savepoint == null) { transactionInfo.setEndTimeMillis(); long transactionMillis = transactionInfo.getEndTimeMillis() - transactionInfo.getStartTimeMillis(); dataSource.getTransactionHistogram().record(transactionMillis); dataSource.logTransaction(transactionInfo); transactionInfo = null; } } @Override public void releaseSavepoint(Savepoint savepoint) throws SQLException { checkState(); try { conn.releaseSavepoint(savepoint); } catch (SQLException ex) { handleException(ex); } } @Override public Clob createClob() throws SQLException { checkState(); try { return conn.createClob(); } catch (SQLException ex) { handleException(ex); return null; // never arrive } } @Override public boolean isClosed() throws SQLException { if (holder == null) { return true; } return conn.isClosed(); } public boolean isAbandonded() { return this.abandoned; } @Override public DatabaseMetaData getMetaData() throws SQLException { checkState(); return conn.getMetaData(); } @Override public void setReadOnly(boolean readOnly) throws SQLException { checkState(); boolean useLocalSessionState = holder.getDataSource().isUseLocalSessionState(); if (useLocalSessionState) { if (readOnly == holder.isUnderlyingReadOnly()) { return; } } try { conn.setReadOnly(readOnly); } catch (SQLException ex) { handleException(ex); } holder.setUnderlyingReadOnly(readOnly); } @Override public boolean isReadOnly() throws SQLException { checkState(); return conn.isReadOnly(); } @Override public void setCatalog(String catalog) throws SQLException { checkState(); try { conn.setCatalog(catalog); } catch (SQLException ex) { handleException(ex); } } @Override public String getCatalog() throws SQLException { checkState(); return conn.getCatalog(); } @Override public void setTransactionIsolation(int level) throws SQLException { checkState(); boolean useLocalSessionState = holder.getDataSource().isUseLocalSessionState(); if (useLocalSessionState) { if (level == holder.getUnderlyingTransactionIsolation()) { return; } } try { conn.setTransactionIsolation(level); } catch (SQLException ex) { handleException(ex); } holder.setUnderlyingTransactionIsolation(level); } @Override public int getTransactionIsolation() throws SQLException { checkState(); return holder.getUnderlyingTransactionIsolation(); } @Override public SQLWarning getWarnings() throws SQLException { checkState(); return conn.getWarnings(); } @Override public void clearWarnings() throws SQLException { checkState(); try { conn.clearWarnings(); } catch (SQLException ex) { handleException(ex); } } @Override public Map<String, Class<?>> getTypeMap() throws SQLException { checkState(); return conn.getTypeMap(); } @Override public void setTypeMap(Map<String, Class<?>> map) throws SQLException { checkState(); conn.setTypeMap(map); } @Override public void setHoldability(int holdability) throws SQLException { checkState(); boolean useLocalSessionState = holder.getDataSource().isUseLocalSessionState(); if (useLocalSessionState) { if (holdability == holder.getUnderlyingHoldability()) { return; } } conn.setHoldability(holdability); holder.setUnderlyingHoldability(holdability); } @Override public int getHoldability() throws SQLException { checkState(); return conn.getHoldability(); } @Override public Savepoint setSavepoint() throws SQLException { checkState(); try { return conn.setSavepoint(); } catch (SQLException ex) { handleException(ex); return null; } } @Override public Blob createBlob() throws SQLException { checkState(); return conn.createBlob(); } @Override public NClob createNClob() throws SQLException { checkState(); return conn.createNClob(); } @Override public SQLXML createSQLXML() throws SQLException { checkState(); return conn.createSQLXML(); } @Override public boolean isValid(int timeout) throws SQLException { checkState(); return conn.isValid(timeout); } @Override public void setClientInfo(String name, String value) throws SQLClientInfoException { if (holder == null) { throw new SQLClientInfoException(); } conn.setClientInfo(name, value); } @Override public void setClientInfo(Properties properties) throws SQLClientInfoException { if (holder == null) { throw new SQLClientInfoException(); } conn.setClientInfo(properties); } @Override public String getClientInfo(String name) throws SQLException { checkState(); return conn.getClientInfo(name); } @Override public Properties getClientInfo() throws SQLException { checkState(); return conn.getClientInfo(); } @Override public Array createArrayOf(String typeName, Object[] elements) throws SQLException { checkState(); return conn.createArrayOf(typeName, elements); } @Override public Struct createStruct(String typeName, Object[] attributes) throws SQLException { checkState(); return conn.createStruct(typeName, attributes); } @Override public void addConnectionEventListener(ConnectionEventListener listener) { if (holder == null) { throw new IllegalStateException(); } holder.getConnectionEventListeners().add(listener); } @Override public void removeConnectionEventListener(ConnectionEventListener listener) { if (holder == null) { throw new IllegalStateException(); } holder.getConnectionEventListeners().remove(listener); } @Override public void addStatementEventListener(StatementEventListener listener) { if (holder == null) { throw new IllegalStateException(); } holder.getStatementEventListeners().add(listener); } @Override public void removeStatementEventListener(StatementEventListener listener) { if (holder == null) { throw new IllegalStateException(); } holder.getStatementEventListeners().remove(listener); } public Throwable getDisableError() { return disableError; } public void checkState() throws SQLException { if (holder == null) { if (disableError != null) { throw new SQLException("connection holder is null", disableError); } else { throw new SQLException("connection holder is null"); } } if (closed) { if (disableError != null) { throw new SQLException("connection closed", disableError); } else { throw new SQLException("connection closed"); } } if (disable) { if (disableError != null) { throw new SQLException("connection disabled", disableError); } else { throw new SQLException("connection disabled"); } } } public String toString() { if (conn != null) { return conn.toString(); } else { return "closed-conn-" + System.identityHashCode(this); } } public void setSchema(String schema) throws SQLException { throw new SQLFeatureNotSupportedException(); } public String getSchema() throws SQLException { throw new SQLFeatureNotSupportedException(); } public void abort(Executor executor) throws SQLException { throw new SQLFeatureNotSupportedException(); } public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException { throw new SQLFeatureNotSupportedException(); } public int getNetworkTimeout() throws SQLException { throw new SQLFeatureNotSupportedException(); } final void beforeExecute() { final DruidConnectionHolder holder = this.holder; if (holder != null && holder.getDataSource().isRemoveAbandoned()) { running = true; } } final void afterExecute() { final DruidConnectionHolder holder = this.holder; if (holder != null && holder.getDataSource().isRemoveAbandoned()) { running = false; holder.setLastActiveTimeMillis(System.currentTimeMillis()); } } boolean isRunning() { return running; } public void abandond() { this.abandoned = true; } }
public class MySqlValidConnectionChecker extends ValidConnectionCheckerAdapter implements ValidConnectionChecker, Serializable { public static final int DEFAULT_VALIDATION_QUERY_TIMEOUT = 1000; private static final long serialVersionUID = 1L; private static final Log LOG = LogFactory.getLog(MySqlValidConnectionChecker.class); private Class<?> clazz; private Method ping; private boolean usePingMethod = false; public MySqlValidConnectionChecker() { try { clazz = Utils.loadClass("com.mysql.jdbc.MySQLConnection"); ping = clazz.getMethod("pingInternal", boolean.class, int.class); if (ping != null) { usePingMethod = true; } } catch (Exception e) { LOG.warn( "Cannot resolve com.mysq.jdbc.Connection.ping method. Will use 'SELECT 1' instead.", e); } configFromProperties(System.getProperties()); } @Override public void configFromProperties(Properties properties) { String property = properties.getProperty("druid.mysql.usePingMethod"); if ("true".equals(property)) { setUsePingMethod(true); } else if ("false".equals(property)) { setUsePingMethod(false); } } public boolean isUsePingMethod() { return usePingMethod; } public void setUsePingMethod(boolean usePingMethod) { this.usePingMethod = usePingMethod; } public boolean isValidConnection( Connection conn, String validateQuery, int validationQueryTimeout) { try { if (conn.isClosed()) { return false; } } catch (SQLException ex) { // skip return false; } if (usePingMethod) { if (conn instanceof DruidPooledConnection) { conn = ((DruidPooledConnection) conn).getConnection(); } if (conn instanceof ConnectionProxy) { conn = ((ConnectionProxy) conn).getRawObject(); } if (clazz.isAssignableFrom(conn.getClass())) { if (validationQueryTimeout < 0) { validationQueryTimeout = DEFAULT_VALIDATION_QUERY_TIMEOUT; } try { ping.invoke(conn, true, validationQueryTimeout); return true; } catch (InvocationTargetException e) { Throwable cause = e.getCause(); if (cause instanceof SQLException) { return false; } LOG.warn("Unexpected error in ping", e); return false; } catch (Exception e) { LOG.warn("Unexpected error in ping", e); return false; } } } Statement stmt = null; ResultSet rs = null; try { stmt = conn.createStatement(); if (validationQueryTimeout > 0) { stmt.setQueryTimeout(validationQueryTimeout); } rs = stmt.executeQuery(validateQuery); return true; } catch (SQLException e) { return false; } catch (Exception e) { LOG.warn("Unexpected error in ping", e); return false; } finally { JdbcUtils.close(rs); JdbcUtils.close(stmt); } } }
/** @author wenshao [[email protected]] */ public final class JdbcUtils implements JdbcConstants { private static final Log LOG = LogFactory.getLog(JdbcUtils.class); private static final Properties DRIVER_URL_MAPPING = new Properties(); private static Boolean mysql_driver_version_6 = null; static { try { ClassLoader ctxClassLoader = Thread.currentThread().getContextClassLoader(); if (ctxClassLoader != null) { for (Enumeration<URL> e = ctxClassLoader.getResources("META-INF/druid-driver.properties"); e.hasMoreElements(); ) { URL url = e.nextElement(); Properties property = new Properties(); InputStream is = null; try { is = url.openStream(); property.load(is); } finally { JdbcUtils.close(is); } DRIVER_URL_MAPPING.putAll(property); } } } catch (Exception e) { LOG.error("load druid-driver.properties error", e); } } public static void close(Connection x) { if (x == null) { return; } try { x.close(); } catch (Exception e) { LOG.debug("close connection error", e); } } public static void close(Statement x) { if (x == null) { return; } try { x.close(); } catch (Exception e) { LOG.debug("close statement error", e); } } public static void close(ResultSet x) { if (x == null) { return; } try { x.close(); } catch (Exception e) { LOG.debug("close result set error", e); } } public static void close(Closeable x) { if (x == null) { return; } try { x.close(); } catch (Exception e) { LOG.debug("close error", e); } } public static void printResultSet(ResultSet rs) throws SQLException { printResultSet(rs, System.out); } public static void printResultSet(ResultSet rs, PrintStream out) throws SQLException { printResultSet(rs, out, true, "\t"); } public static void printResultSet( ResultSet rs, PrintStream out, boolean printHeader, String seperator) throws SQLException { ResultSetMetaData metadata = rs.getMetaData(); int columnCount = metadata.getColumnCount(); if (printHeader) { for (int columnIndex = 1; columnIndex <= columnCount; ++columnIndex) { if (columnIndex != 1) { out.print(seperator); } out.print(metadata.getColumnName(columnIndex)); } } out.println(); while (rs.next()) { for (int columnIndex = 1; columnIndex <= columnCount; ++columnIndex) { if (columnIndex != 1) { out.print(seperator); } int type = metadata.getColumnType(columnIndex); if (type == Types.VARCHAR || type == Types.CHAR || type == Types.NVARCHAR || type == Types.NCHAR) { out.print(rs.getString(columnIndex)); } else if (type == Types.DATE) { Date date = rs.getDate(columnIndex); if (rs.wasNull()) { out.print("null"); } else { out.print(date.toString()); } } else if (type == Types.BIT) { boolean value = rs.getBoolean(columnIndex); if (rs.wasNull()) { out.print("null"); } else { out.print(Boolean.toString(value)); } } else if (type == Types.BOOLEAN) { boolean value = rs.getBoolean(columnIndex); if (rs.wasNull()) { out.print("null"); } else { out.print(Boolean.toString(value)); } } else if (type == Types.TINYINT) { byte value = rs.getByte(columnIndex); if (rs.wasNull()) { out.print("null"); } else { out.print(Byte.toString(value)); } } else if (type == Types.SMALLINT) { short value = rs.getShort(columnIndex); if (rs.wasNull()) { out.print("null"); } else { out.print(Short.toString(value)); } } else if (type == Types.INTEGER) { int value = rs.getInt(columnIndex); if (rs.wasNull()) { out.print("null"); } else { out.print(Integer.toString(value)); } } else if (type == Types.BIGINT) { long value = rs.getLong(columnIndex); if (rs.wasNull()) { out.print("null"); } else { out.print(Long.toString(value)); } } else if (type == Types.TIMESTAMP) { out.print(String.valueOf(rs.getTimestamp(columnIndex))); } else if (type == Types.DECIMAL) { out.print(String.valueOf(rs.getBigDecimal(columnIndex))); } else if (type == Types.CLOB) { out.print(String.valueOf(rs.getString(columnIndex))); } else if (type == Types.JAVA_OBJECT) { Object object = rs.getObject(columnIndex); if (rs.wasNull()) { out.print("null"); } else { out.print(String.valueOf(object)); } } else if (type == Types.LONGVARCHAR) { Object object = rs.getString(columnIndex); if (rs.wasNull()) { out.print("null"); } else { out.print(String.valueOf(object)); } } else if (type == Types.NULL) { out.print("null"); } else { Object object = rs.getObject(columnIndex); if (rs.wasNull()) { out.print("null"); } else { if (object instanceof byte[]) { byte[] bytes = (byte[]) object; String text = HexBin.encode(bytes); out.print(text); } else { out.print(String.valueOf(object)); } } } } out.println(); } } public static String getTypeName(int sqlType) { switch (sqlType) { case Types.ARRAY: return "ARRAY"; case Types.BIGINT: return "BIGINT"; case Types.BINARY: return "BINARY"; case Types.BIT: return "BIT"; case Types.BLOB: return "BLOB"; case Types.BOOLEAN: return "BOOLEAN"; case Types.CHAR: return "CHAR"; case Types.CLOB: return "CLOB"; case Types.DATALINK: return "DATALINK"; case Types.DATE: return "DATE"; case Types.DECIMAL: return "DECIMAL"; case Types.DISTINCT: return "DISTINCT"; case Types.DOUBLE: return "DOUBLE"; case Types.FLOAT: return "FLOAT"; case Types.INTEGER: return "INTEGER"; case Types.JAVA_OBJECT: return "JAVA_OBJECT"; case Types.LONGNVARCHAR: return "LONGNVARCHAR"; case Types.LONGVARBINARY: return "LONGVARBINARY"; case Types.NCHAR: return "NCHAR"; case Types.NCLOB: return "NCLOB"; case Types.NULL: return "NULL"; case Types.NUMERIC: return "NUMERIC"; case Types.NVARCHAR: return "NVARCHAR"; case Types.REAL: return "REAL"; case Types.REF: return "REF"; case Types.ROWID: return "ROWID"; case Types.SMALLINT: return "SMALLINT"; case Types.SQLXML: return "SQLXML"; case Types.STRUCT: return "STRUCT"; case Types.TIME: return "TIME"; case Types.TIMESTAMP: return "TIMESTAMP"; case Types.TINYINT: return "TINYINT"; case Types.VARBINARY: return "VARBINARY"; case Types.VARCHAR: return "VARCHAR"; default: return "OTHER"; } } public static String getDriverClassName(String rawUrl) throws SQLException { if (rawUrl == null) { return null; } if (rawUrl.startsWith("jdbc:derby:")) { return "org.apache.derby.jdbc.EmbeddedDriver"; } else if (rawUrl.startsWith("jdbc:mysql:")) { if (mysql_driver_version_6 == null) { mysql_driver_version_6 = Utils.loadClass("com.mysql.cj.jdbc.Driver") != null; } if (mysql_driver_version_6) { return MYSQL_DRIVER_6; } else { return MYSQL_DRIVER; } } else if (rawUrl.startsWith("jdbc:log4jdbc:")) { return LOG4JDBC_DRIVER; } else if (rawUrl.startsWith("jdbc:mariadb:")) { return MARIADB_DRIVER; } else if (rawUrl.startsWith("jdbc:oracle:") // || rawUrl.startsWith("JDBC:oracle:")) { return ORACLE_DRIVER; } else if (rawUrl.startsWith("jdbc:alibaba:oracle:")) { return ALI_ORACLE_DRIVER; } else if (rawUrl.startsWith("jdbc:microsoft:")) { return "com.microsoft.jdbc.sqlserver.SQLServerDriver"; } else if (rawUrl.startsWith("jdbc:sqlserver:")) { return "com.microsoft.sqlserver.jdbc.SQLServerDriver"; } else if (rawUrl.startsWith("jdbc:sybase:Tds:")) { return "com.sybase.jdbc2.jdbc.SybDriver"; } else if (rawUrl.startsWith("jdbc:jtds:")) { return "net.sourceforge.jtds.jdbc.Driver"; } else if (rawUrl.startsWith("jdbc:fake:") || rawUrl.startsWith("jdbc:mock:")) { return "com.alibaba.druid.mock.MockDriver"; } else if (rawUrl.startsWith("jdbc:postgresql:")) { return POSTGRESQL_DRIVER; } else if (rawUrl.startsWith("jdbc:edb:")) { return ENTERPRISEDB_DRIVER; } else if (rawUrl.startsWith("jdbc:odps:")) { return ODPS_DRIVER; } else if (rawUrl.startsWith("jdbc:hsqldb:")) { return "org.hsqldb.jdbcDriver"; } else if (rawUrl.startsWith("jdbc:db2:")) { return DB2_DRIVER; } else if (rawUrl.startsWith("jdbc:sqlite:")) { return "org.sqlite.JDBC"; } else if (rawUrl.startsWith("jdbc:ingres:")) { return "com.ingres.jdbc.IngresDriver"; } else if (rawUrl.startsWith("jdbc:h2:")) { return H2_DRIVER; } else if (rawUrl.startsWith("jdbc:mckoi:")) { return "com.mckoi.JDBCDriver"; } else if (rawUrl.startsWith("jdbc:cloudscape:")) { return "COM.cloudscape.core.JDBCDriver"; } else if (rawUrl.startsWith("jdbc:informix-sqli:")) { return "com.informix.jdbc.IfxDriver"; } else if (rawUrl.startsWith("jdbc:timesten:")) { return "com.timesten.jdbc.TimesTenDriver"; } else if (rawUrl.startsWith("jdbc:as400:")) { return "com.ibm.as400.access.AS400JDBCDriver"; } else if (rawUrl.startsWith("jdbc:sapdb:")) { return "com.sap.dbtech.jdbc.DriverSapDB"; } else if (rawUrl.startsWith("jdbc:JSQLConnect:")) { return "com.jnetdirect.jsql.JSQLDriver"; } else if (rawUrl.startsWith("jdbc:JTurbo:")) { return "com.newatlanta.jturbo.driver.Driver"; } else if (rawUrl.startsWith("jdbc:firebirdsql:")) { return "org.firebirdsql.jdbc.FBDriver"; } else if (rawUrl.startsWith("jdbc:interbase:")) { return "interbase.interclient.Driver"; } else if (rawUrl.startsWith("jdbc:pointbase:")) { return "com.pointbase.jdbc.jdbcUniversalDriver"; } else if (rawUrl.startsWith("jdbc:edbc:")) { return "ca.edbc.jdbc.EdbcDriver"; } else if (rawUrl.startsWith("jdbc:mimer:multi1:")) { return "com.mimer.jdbc.Driver"; } else if (rawUrl.startsWith("jdbc:dm:")) { return JdbcConstants.DM_DRIVER; } else if (rawUrl.startsWith("jdbc:kingbase:")) { return JdbcConstants.KINGBASE_DRIVER; } else if (rawUrl.startsWith("jdbc:hive:")) { return JdbcConstants.HIVE_DRIVER; } else if (rawUrl.startsWith("jdbc:hive2:")) { return JdbcConstants.HIVE_DRIVER; } else if (rawUrl.startsWith("jdbc:phoenix:thin:")) { return "org.apache.phoenix.queryserver.client.Driver"; } else if (rawUrl.startsWith("jdbc:phoenix://")) { return JdbcConstants.PHOENIX_DRIVER; } else { throw new SQLException("unkow jdbc driver : " + rawUrl); } } public static String getDbType(String rawUrl, String driverClassName) { if (rawUrl == null) { return null; } if (rawUrl.startsWith("jdbc:derby:") || rawUrl.startsWith("jdbc:log4jdbc:derby:")) { return DERBY; } else if (rawUrl.startsWith("jdbc:mysql:") || rawUrl.startsWith("jdbc:cobar:") || rawUrl.startsWith("jdbc:log4jdbc:mysql:")) { return MYSQL; } else if (rawUrl.startsWith("jdbc:mariadb:")) { return MARIADB; } else if (rawUrl.startsWith("jdbc:oracle:") || rawUrl.startsWith("jdbc:log4jdbc:oracle:")) { return ORACLE; } else if (rawUrl.startsWith("jdbc:alibaba:oracle:")) { return ALI_ORACLE; } else if (rawUrl.startsWith("jdbc:microsoft:") || rawUrl.startsWith("jdbc:log4jdbc:microsoft:")) { return SQL_SERVER; } else if (rawUrl.startsWith("jdbc:sqlserver:") || rawUrl.startsWith("jdbc:log4jdbc:sqlserver:")) { return SQL_SERVER; } else if (rawUrl.startsWith("jdbc:sybase:Tds:") || rawUrl.startsWith("jdbc:log4jdbc:sybase:")) { return SYBASE; } else if (rawUrl.startsWith("jdbc:jtds:") || rawUrl.startsWith("jdbc:log4jdbc:jtds:")) { return JTDS; } else if (rawUrl.startsWith("jdbc:fake:") || rawUrl.startsWith("jdbc:mock:")) { return MOCK; } else if (rawUrl.startsWith("jdbc:postgresql:") || rawUrl.startsWith("jdbc:log4jdbc:postgresql:")) { return POSTGRESQL; } else if (rawUrl.startsWith("jdbc:edb:")) { return ENTERPRISEDB; } else if (rawUrl.startsWith("jdbc:hsqldb:") || rawUrl.startsWith("jdbc:log4jdbc:hsqldb:")) { return HSQL; } else if (rawUrl.startsWith("jdbc:odps:")) { return ODPS; } else if (rawUrl.startsWith("jdbc:db2:")) { return DB2; } else if (rawUrl.startsWith("jdbc:sqlite:")) { return "sqlite"; } else if (rawUrl.startsWith("jdbc:ingres:")) { return "ingres"; } else if (rawUrl.startsWith("jdbc:h2:") || rawUrl.startsWith("jdbc:log4jdbc:h2:")) { return H2; } else if (rawUrl.startsWith("jdbc:mckoi:")) { return "mckoi"; } else if (rawUrl.startsWith("jdbc:cloudscape:")) { return "cloudscape"; } else if (rawUrl.startsWith("jdbc:informix-sqli:") || rawUrl.startsWith("jdbc:log4jdbc:informix-sqli:")) { return "informix"; } else if (rawUrl.startsWith("jdbc:timesten:")) { return "timesten"; } else if (rawUrl.startsWith("jdbc:as400:")) { return "as400"; } else if (rawUrl.startsWith("jdbc:sapdb:")) { return "sapdb"; } else if (rawUrl.startsWith("jdbc:JSQLConnect:")) { return "JSQLConnect"; } else if (rawUrl.startsWith("jdbc:JTurbo:")) { return "JTurbo"; } else if (rawUrl.startsWith("jdbc:firebirdsql:")) { return "firebirdsql"; } else if (rawUrl.startsWith("jdbc:interbase:")) { return "interbase"; } else if (rawUrl.startsWith("jdbc:pointbase:")) { return "pointbase"; } else if (rawUrl.startsWith("jdbc:edbc:")) { return "edbc"; } else if (rawUrl.startsWith("jdbc:mimer:multi1:")) { return "mimer"; } else if (rawUrl.startsWith("jdbc:dm:")) { return JdbcConstants.DM; } else if (rawUrl.startsWith("jdbc:kingbase:")) { return JdbcConstants.KINGBASE; } else if (rawUrl.startsWith("jdbc:log4jdbc:")) { return LOG4JDBC; } else if (rawUrl.startsWith("jdbc:hive:")) { return HIVE; } else if (rawUrl.startsWith("jdbc:hive2:")) { return HIVE; } else if (rawUrl.startsWith("jdbc:phoenix:")) { return PHOENIX; } else { return null; } } public static Driver createDriver(String driverClassName) throws SQLException { return createDriver(null, driverClassName); } public static Driver createDriver(ClassLoader classLoader, String driverClassName) throws SQLException { Class<?> clazz = null; if (classLoader != null) { try { clazz = classLoader.loadClass(driverClassName); } catch (ClassNotFoundException e) { // skip } } if (clazz == null) { try { ClassLoader contextLoader = Thread.currentThread().getContextClassLoader(); if (contextLoader != null) { clazz = contextLoader.loadClass(driverClassName); } } catch (ClassNotFoundException e) { // skip } } if (clazz == null) { try { clazz = Class.forName(driverClassName); } catch (ClassNotFoundException e) { throw new SQLException(e.getMessage(), e); } } try { return (Driver) clazz.newInstance(); } catch (IllegalAccessException e) { throw new SQLException(e.getMessage(), e); } catch (InstantiationException e) { throw new SQLException(e.getMessage(), e); } } public static int executeUpdate(DataSource dataSource, String sql, Object... parameters) throws SQLException { return executeUpdate(dataSource, sql, Arrays.asList(parameters)); } public static int executeUpdate(DataSource dataSource, String sql, List<Object> parameters) throws SQLException { Connection conn = null; try { conn = dataSource.getConnection(); return executeUpdate(conn, sql, parameters); } finally { close(conn); } } public static int executeUpdate(Connection conn, String sql, List<Object> parameters) throws SQLException { PreparedStatement stmt = null; int updateCount; try { stmt = conn.prepareStatement(sql); setParameters(stmt, parameters); updateCount = stmt.executeUpdate(); } finally { JdbcUtils.close(stmt); } return updateCount; } public static void execute(DataSource dataSource, String sql, Object... parameters) throws SQLException { execute(dataSource, sql, Arrays.asList(parameters)); } public static void execute(DataSource dataSource, String sql, List<Object> parameters) throws SQLException { Connection conn = null; try { conn = dataSource.getConnection(); execute(conn, sql, parameters); } finally { close(conn); } } public static void execute(Connection conn, String sql, List<Object> parameters) throws SQLException { PreparedStatement stmt = null; try { stmt = conn.prepareStatement(sql); setParameters(stmt, parameters); stmt.executeUpdate(); } finally { JdbcUtils.close(stmt); } } public static List<Map<String, Object>> executeQuery( DataSource dataSource, String sql, Object... parameters) throws SQLException { return executeQuery(dataSource, sql, Arrays.asList(parameters)); } public static List<Map<String, Object>> executeQuery( DataSource dataSource, String sql, List<Object> parameters) throws SQLException { Connection conn = null; try { conn = dataSource.getConnection(); return executeQuery(conn, sql, parameters); } finally { close(conn); } } public static List<Map<String, Object>> executeQuery( Connection conn, String sql, List<Object> parameters) throws SQLException { List<Map<String, Object>> rows = new ArrayList<Map<String, Object>>(); PreparedStatement stmt = null; ResultSet rs = null; try { stmt = conn.prepareStatement(sql); setParameters(stmt, parameters); rs = stmt.executeQuery(); ResultSetMetaData rsMeta = rs.getMetaData(); while (rs.next()) { Map<String, Object> row = new LinkedHashMap<String, Object>(); for (int i = 0, size = rsMeta.getColumnCount(); i < size; ++i) { String columName = rsMeta.getColumnLabel(i + 1); Object value = rs.getObject(i + 1); row.put(columName, value); } rows.add(row); } } finally { JdbcUtils.close(rs); JdbcUtils.close(stmt); } return rows; } private static void setParameters(PreparedStatement stmt, List<Object> parameters) throws SQLException { for (int i = 0, size = parameters.size(); i < size; ++i) { Object param = parameters.get(i); stmt.setObject(i + 1, param); } } public static void insertToTable( DataSource dataSource, String tableName, Map<String, Object> data) throws SQLException { Connection conn = null; try { conn = dataSource.getConnection(); insertToTable(conn, tableName, data); } finally { close(conn); } } public static void insertToTable(Connection conn, String tableName, Map<String, Object> data) throws SQLException { String sql = makeInsertToTableSql(tableName, data.keySet()); List<Object> parameters = new ArrayList<Object>(data.values()); execute(conn, sql, parameters); } public static String makeInsertToTableSql(String tableName, Collection<String> names) { StringBuilder sql = new StringBuilder() // .append("insert into ") // .append(tableName) // .append("("); // int nameCount = 0; for (String name : names) { if (nameCount > 0) { sql.append(","); } sql.append(name); nameCount++; } sql.append(") values ("); for (int i = 0; i < nameCount; ++i) { if (i != 0) { sql.append(","); } sql.append("?"); } sql.append(")"); return sql.toString(); } }
/** @author wenshao<*****@*****.**> */ public final class DruidConnectionHolder { private static final Log LOG = LogFactory.getLog(DruidConnectionHolder.class); private final DruidAbstractDataSource dataSource; private final Connection conn; private final List<ConnectionEventListener> connectionEventListeners = new CopyOnWriteArrayList<ConnectionEventListener>(); private final List<StatementEventListener> statementEventListeners = new CopyOnWriteArrayList<StatementEventListener>(); private final long connectTimeMillis; private transient long lastActiveTimeMillis; private long useCount = 0; private PreparedStatementPool statementPool; private final List<Statement> statementTrace = new ArrayList<Statement>(2); private final boolean defaultReadOnly; private final int defaultHoldability; private final int defaultTransactionIsolation; private final boolean defaultAutoCommit; private boolean underlyingReadOnly; private int underlyingHoldability; private int underlyingTransactionIsolation; private boolean underlyingAutoCommit; private boolean discard = false; public static boolean holdabilityUnsupported = false; public DruidConnectionHolder(DruidAbstractDataSource dataSource, Connection conn) throws SQLException { this.dataSource = dataSource; this.conn = conn; this.connectTimeMillis = System.currentTimeMillis(); this.lastActiveTimeMillis = connectTimeMillis; this.underlyingAutoCommit = conn.getAutoCommit(); { boolean initUnderlyHoldability = !holdabilityUnsupported; if (JdbcConstants.SYBASE.equals(dataSource.getDbType()) // || JdbcConstants.DB2.equals(dataSource.getDbType()) // ) { initUnderlyHoldability = false; } if (initUnderlyHoldability) { try { this.underlyingHoldability = conn.getHoldability(); } catch (UnsupportedOperationException e) { holdabilityUnsupported = true; LOG.warn("getHoldability unsupported", e); } catch (SQLFeatureNotSupportedException e) { holdabilityUnsupported = true; LOG.warn("getHoldability unsupported", e); } catch (SQLException e) { // bug fixed for hive jdbc-driver if ("Method not supported".equals(e.getMessage())) { holdabilityUnsupported = true; } LOG.warn("getHoldability error", e); } } } this.underlyingReadOnly = conn.isReadOnly(); try { this.underlyingTransactionIsolation = conn.getTransactionIsolation(); } catch (SQLException e) { // compartible for alibaba corba if (!"com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException" .equals(e.getClass().getName())) { throw e; } } this.defaultHoldability = underlyingHoldability; this.defaultTransactionIsolation = underlyingTransactionIsolation; this.defaultAutoCommit = underlyingAutoCommit; this.defaultReadOnly = underlyingReadOnly; } public boolean isUnderlyingReadOnly() { return underlyingReadOnly; } public void setUnderlyingReadOnly(boolean underlyingReadOnly) { this.underlyingReadOnly = underlyingReadOnly; } public int getUnderlyingHoldability() { return underlyingHoldability; } public void setUnderlyingHoldability(int underlyingHoldability) { this.underlyingHoldability = underlyingHoldability; } public int getUnderlyingTransactionIsolation() { return underlyingTransactionIsolation; } public void setUnderlyingTransactionIsolation(int underlyingTransactionIsolation) { this.underlyingTransactionIsolation = underlyingTransactionIsolation; } public boolean isUnderlyingAutoCommit() { return underlyingAutoCommit; } public void setUnderlyingAutoCommit(boolean underlyingAutoCommit) { this.underlyingAutoCommit = underlyingAutoCommit; } public long getLastActiveTimeMillis() { return lastActiveTimeMillis; } public void setLastActiveTimeMillis(long lastActiveMillis) { this.lastActiveTimeMillis = lastActiveMillis; } public void addTrace(DruidPooledStatement stmt) { statementTrace.add(stmt); } public void removeTrace(DruidPooledStatement stmt) { statementTrace.remove(stmt); } public List<ConnectionEventListener> getConnectionEventListeners() { return connectionEventListeners; } public List<StatementEventListener> getStatementEventListeners() { return statementEventListeners; } public PreparedStatementPool getStatementPool() { if (statementPool == null) { statementPool = new PreparedStatementPool(this); } return statementPool; } public PreparedStatementPool getStatementPoolDirect() { return statementPool; } public void clearStatementCache() { if (this.statementPool == null) { return; } this.statementPool.clear(); } public DruidAbstractDataSource getDataSource() { return dataSource; } public boolean isPoolPreparedStatements() { return dataSource.isPoolPreparedStatements(); } public Connection getConnection() { return conn; } public long getTimeMillis() { return connectTimeMillis; } public long getUseCount() { return useCount; } public void incrementUseCount() { useCount++; } public void reset() throws SQLException { // reset default settings if (underlyingReadOnly != defaultReadOnly) { conn.setReadOnly(defaultReadOnly); underlyingReadOnly = defaultReadOnly; } if (underlyingHoldability != defaultHoldability) { conn.setHoldability(defaultHoldability); underlyingHoldability = defaultHoldability; } if (underlyingTransactionIsolation != defaultTransactionIsolation) { conn.setTransactionIsolation(defaultTransactionIsolation); underlyingTransactionIsolation = defaultTransactionIsolation; } if (underlyingAutoCommit != defaultAutoCommit) { conn.setAutoCommit(defaultAutoCommit); underlyingAutoCommit = defaultAutoCommit; } connectionEventListeners.clear(); statementEventListeners.clear(); for (Object item : statementTrace.toArray()) { Statement stmt = (Statement) item; JdbcUtils.close(stmt); } statementTrace.clear(); conn.clearWarnings(); } public boolean isDiscard() { return discard; } public void setDiscard(boolean discard) { this.discard = discard; } public String toString() { StringBuilder buf = new StringBuilder(); buf.append("{ID:"); buf.append(System.identityHashCode(conn)); buf.append(", ConnectTime:\""); buf.append(Utils.toString(new Date(this.connectTimeMillis))); buf.append("\", UseCount:"); buf.append(useCount); if (lastActiveTimeMillis > 0) { buf.append(", LastActiveTime:\""); buf.append(Utils.toString(new Date(this.lastActiveTimeMillis))); buf.append("\""); } if (statementPool != null && statementPool.getMap().size() > 0) { buf.append("\", CachedStatementCount:"); buf.append(statementPool.getMap().size()); } buf.append("}"); return buf.toString(); } }
/** @author wenshao<*****@*****.**> */ public class DruidDriver implements Driver, DruidDriverMBean { private static final Log LOG = LogFactory.getLog(DruidDriver.class); private static final DruidDriver instance = new DruidDriver(); private static final ConcurrentMap<String, DataSourceProxyImpl> proxyDataSources = new ConcurrentHashMap<String, DataSourceProxyImpl>(); private static final AtomicInteger dataSourceIdSeed = new AtomicInteger(0); private static final AtomicInteger sqlStatIdSeed = new AtomicInteger(0); public static final String DEFAULT_PREFIX = "jdbc:wrap-jdbc:"; public static final String DRIVER_PREFIX = "driver="; public static final String PASSWORD_CALLBACK_PREFIX = "passwordCallback="; public static final String NAME_PREFIX = "name="; public static final String JMX_PREFIX = "jmx="; public static final String FILTERS_PREFIX = "filters="; private final AtomicLong connectCount = new AtomicLong(0); private String acceptPrefix = DEFAULT_PREFIX; private int majorVersion = 4; private int minorVersion = 0; private static final String MBEAN_NAME = "com.alibaba.druid:type=DruidDriver"; static { registerDriver(instance); } public static boolean registerDriver(Driver driver) { try { DriverManager.registerDriver(driver); try { MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer(); ObjectName objectName = new ObjectName(MBEAN_NAME); if (!mbeanServer.isRegistered(objectName)) { mbeanServer.registerMBean(instance, objectName); } } catch (Exception ex) { LOG.error("register druid-driver mbean error", ex); } return true; } catch (Exception e) { LOG.error("registerDriver error", e); } return false; } public DruidDriver() {} public static DruidDriver getInstance() { return instance; } public static int createDataSourceId() { return dataSourceIdSeed.incrementAndGet(); } public static int createSqlStatId() { return sqlStatIdSeed.incrementAndGet(); } @Override public boolean acceptsURL(String url) throws SQLException { if (url == null) { return false; } if (url.startsWith(acceptPrefix)) { return true; } return false; } @Override public Connection connect(String url, Properties info) throws SQLException { if (!acceptsURL(url)) { return null; } connectCount.incrementAndGet(); DataSourceProxyImpl dataSource = getDataSource(url, info); return dataSource.connect(info); } /** * 参数定义: com.alibaba.druid.log.LogFilter=filter com.alibaba.druid.log.LogFilter.p1=prop-value * com.alibaba.druid.log.LogFilter.p2=prop-value * * @param url * @return * @throws SQLException */ private DataSourceProxyImpl getDataSource(String url, Properties info) throws SQLException { DataSourceProxyImpl dataSource = proxyDataSources.get(url); if (dataSource == null) { DataSourceProxyConfig config = parseConfig(url, info); Driver rawDriver = createDriver(config.getRawDriverClassName()); DataSourceProxyImpl newDataSource = new DataSourceProxyImpl(rawDriver, config); { String property = System.getProperty("druid.filters"); if (property != null && property.length() > 0) { for (String filterItem : property.split(",")) { FilterManager.loadFilter(config.getFilters(), filterItem); } } } { int dataSourceId = createDataSourceId(); newDataSource.setId(dataSourceId); for (Filter filter : config.getFilters()) { filter.init(newDataSource); } } DataSourceProxy oldDataSource = proxyDataSources.putIfAbsent(url, newDataSource); if (oldDataSource == null) { if (config.isJmxOption()) { JMXUtils.register("com.alibaba.druid:type=JdbcStat", JdbcStatManager.getInstance()); } } dataSource = proxyDataSources.get(url); } return dataSource; } public static DataSourceProxyConfig parseConfig(String url, Properties info) throws SQLException { String restUrl = url.substring(DEFAULT_PREFIX.length()); DataSourceProxyConfig config = new DataSourceProxyConfig(); if (restUrl.startsWith(DRIVER_PREFIX)) { int pos = restUrl.indexOf(':', DRIVER_PREFIX.length()); String driverText = restUrl.substring(DRIVER_PREFIX.length(), pos); if (driverText.length() > 0) { config.setRawDriverClassName(driverText.trim()); } restUrl = restUrl.substring(pos + 1); } if (restUrl.startsWith(FILTERS_PREFIX)) { int pos = restUrl.indexOf(':', FILTERS_PREFIX.length()); String filtersText = restUrl.substring(FILTERS_PREFIX.length(), pos); for (String filterItem : filtersText.split(",")) { FilterManager.loadFilter(config.getFilters(), filterItem); } restUrl = restUrl.substring(pos + 1); } if (restUrl.startsWith(NAME_PREFIX)) { int pos = restUrl.indexOf(':', NAME_PREFIX.length()); String name = restUrl.substring(NAME_PREFIX.length(), pos); config.setName(name); restUrl = restUrl.substring(pos + 1); } if (restUrl.startsWith(JMX_PREFIX)) { int pos = restUrl.indexOf(':', JMX_PREFIX.length()); String jmxOption = restUrl.substring(JMX_PREFIX.length(), pos); config.setJmxOption(jmxOption); restUrl = restUrl.substring(pos + 1); } String rawUrl = restUrl; config.setRawUrl(rawUrl); if (config.getRawDriverClassName() == null) { String rawDriverClassname = JdbcUtils.getDriverClassName(rawUrl); config.setRawDriverClassName(rawDriverClassname); } config.setUrl(url); return config; } public Driver createDriver(String className) throws SQLException { Class<?> rawDriverClass = JdbcUtils.loadDriverClass(className); if (rawDriverClass == null) { throw new SQLException("jdbc-driver's class not found. '" + className + "'"); } Driver rawDriver; try { rawDriver = (Driver) rawDriverClass.newInstance(); } catch (InstantiationException e) { throw new SQLException("create driver instance error, driver className '" + className + "'"); } catch (IllegalAccessException e) { throw new SQLException("create driver instance error, driver className '" + className + "'"); } return rawDriver; } @Override public int getMajorVersion() { return this.majorVersion; } @Override public int getMinorVersion() { return this.minorVersion; } @Override public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException { DataSourceProxyImpl dataSource = getDataSource(url, info); return dataSource.getRawDriver().getPropertyInfo(dataSource.getConfig().getRawUrl(), info); } @Override public boolean jdbcCompliant() { return true; } @Override public long getConnectCount() { return connectCount.get(); } public String getAcceptPrefix() { return acceptPrefix; } @Override public String[] getDataSourceUrls() { return proxyDataSources.keySet().toArray(new String[proxyDataSources.size()]); } public static ConcurrentMap<String, DataSourceProxyImpl> getProxyDataSources() { return proxyDataSources; } public Logger getParentLogger() throws SQLFeatureNotSupportedException { throw new SQLFeatureNotSupportedException(); } @Override public void resetStat() { connectCount.set(0); } @Override public String getDruidVersion() { return VERSION.getVersionNumber(); } }
/** * 通过 ID 获取解密器 * * @author Jonas Yang */ public class DecrypterFactory { private static Log log = LogFactory.getLog(DecrypterFactory.class); private static ConcurrentHashMap<String, Decrypter> decrypters = new ConcurrentHashMap<String, Decrypter>(); static { RsaDecrypter rsa = new RsaDecrypter(); AesDecrypter aes = new AesDecrypter(); decrypters.put(rsa.getId(), rsa); decrypters.put(aes.getId(), aes); } private DecrypterFactory() {} // static void initDecrypters(String resource, ClassLoader classLoader) { // if (resource == null) { // return; // } // // InputStream inStream = null; // // try { // inStream = classLoader.getResourceAsStream(resource); // if (inStream == null) { // return; // } // // Properties p = new Properties(); // p.load(inStream); // // for (String key : p.stringPropertyNames()) { // String clazzName = p.getProperty(key); // Class clazz = classLoader.loadClass(clazzName); // Decrypter decrypter = (Decrypter) clazz.newInstance(); // // addDecrypter(decrypter); // } // } catch (Exception e) { // log.warn("Fail to init config loaders.", e); // } finally { // JdbcUtils.close(inStream); // } // } /** * 通过 ID 获取解密器, 如果没有找到, 返回 <code>null</code> * * @param id * @return */ public static Decrypter getDecrypter(String id) { return decrypters.get(id); } public static void addDecrypter(Decrypter decrypter) { Decrypter oldDecrypter = decrypters.putIfAbsent(decrypter.getId(), decrypter); if (oldDecrypter != null) { log.warn( "Replace decrypter [" + decrypter.getId() + ", " + oldDecrypter.getClass() + "] with [" + decrypter.getClass() + "]"); } } public static Decrypter[] getDecrypters() { return decrypters.values().toArray(new Decrypter[0]); } }