package io.dataease.datasource.provider; import com.google.gson.Gson; import com.mchange.v2.c3p0.ComboPooledDataSource; import io.dataease.datasource.constants.DatasourceTypes; import io.dataease.datasource.dto.MysqlConfigration; import io.dataease.datasource.dto.OracleConfigration; import io.dataease.datasource.dto.SqlServerConfigration; import io.dataease.datasource.dto.TableFiled; import io.dataease.datasource.request.DatasourceRequest; import io.dataease.exception.DataEaseException; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; import java.beans.PropertyVetoException; import java.sql.*; import java.util.*; @Service("jdbc") public class JdbcProvider extends DatasourceProvider { private static Map jdbcConnection = new HashMap<>(); private static int initPoolSize = 1; private static int maxConnections = 1; /** * 增加缓存机制 key 由 'provider_sql_' dsr.datasource.id dsr.table dsr.query共4部分组成,命中则使用缓存直接返回不再执行sql逻辑 * @param dsr * @return * @throws Exception */ /** * 这里使用声明式缓存不是很妥当 * 改为chartViewService中使用编程式缓存 @Cacheable( value = JdbcConstants.JDBC_PROVIDER_KEY, key = "'provider_sql_' + #dsr.datasource.id + '_' + #dsr.table + '_' + #dsr.query", condition = "#dsr.pageSize == null || #dsr.pageSize == 0L" ) */ @Override public List getData(DatasourceRequest dsr) throws Exception { List list = new LinkedList<>(); Connection connection = null; try { connection = getConnectionFromPool(dsr); Statement stat = connection.createStatement(); ResultSet rs = stat.executeQuery(dsr.getQuery()); list = fetchResult(rs); } catch (SQLException e) { DataEaseException.throwException(e); } catch (Exception e) { DataEaseException.throwException(e); } finally { if(connection != null){ connection.close(); } } return list; } public void exec(DatasourceRequest datasourceRequest) throws Exception { Connection connection = null; try { connection = getConnectionFromPool(datasourceRequest); Statement stat = connection.createStatement(); Boolean result = stat.execute(datasourceRequest.getQuery()); stat.close(); } catch (SQLException e) { DataEaseException.throwException(e); } catch (Exception e) { DataEaseException.throwException(e); } finally { if(connection != null){ connection.close(); } } } @Override public List fetchResult(DatasourceRequest datasourceRequest) throws Exception { ResultSet rs; Connection connection = null; try { connection = getConnectionFromPool(datasourceRequest); Statement stat = connection.createStatement(); rs = stat.executeQuery(datasourceRequest.getQuery()); return fetchResult(rs); } catch (SQLException e) { DataEaseException.throwException(e); } catch (Exception e) { DataEaseException.throwException(e); } finally { if(connection != null){ connection.close(); } } return new ArrayList<>(); } private List fetchResult(ResultSet rs) throws Exception { List list = new LinkedList<>(); ResultSetMetaData metaData = rs.getMetaData(); int columnCount = metaData.getColumnCount(); while (rs.next()) { String[] row = new String[columnCount]; for (int j = 0; j < columnCount; j++) { int columType = metaData.getColumnType(j + 1); switch (columType) { case Types.DATE: row[j] = rs.getDate(j + 1).toString(); break; default: row[j] = rs.getString(j + 1); break; } } list.add(row); } return list; } @Override public List fetchResultField(DatasourceRequest datasourceRequest) throws Exception { ResultSet rs; Connection connection = null; try { connection = getConnectionFromPool(datasourceRequest); Statement stat = connection.createStatement(); rs = stat.executeQuery(datasourceRequest.getQuery()); return fetchResultField(rs); } catch (SQLException e) { DataEaseException.throwException(e); } catch (Exception e) { DataEaseException.throwException(e); } finally { if(connection != null){ connection.close(); } } return new ArrayList<>(); } @Override public Map fetchResultAndField(DatasourceRequest datasourceRequest) throws Exception { ResultSet rs; Map result = new HashMap<>(); Connection connection = null; List dataList = new LinkedList<>(); List fieldList = new ArrayList<>(); try { connection = getConnectionFromPool(datasourceRequest); Statement stat = connection.createStatement(); rs = stat.executeQuery(datasourceRequest.getQuery()); dataList = fetchResult(rs); fieldList = fetchResultField(rs); result.put("dataList", dataList); result.put("fieldList", fieldList); return result; } catch (SQLException e) { DataEaseException.throwException(e); } catch (Exception e) { DataEaseException.throwException(e); } finally { if(connection != null){ connection.close(); } } return new HashMap<>(); } private List fetchResultField(ResultSet rs) throws Exception { List fieldList = new ArrayList<>(); ResultSetMetaData metaData = rs.getMetaData(); int columnCount = metaData.getColumnCount(); for (int j = 0; j < columnCount; j++) { String f = metaData.getColumnName(j + 1); String l = StringUtils.isNotEmpty(metaData.getColumnLabel(j + 1)) ? metaData.getColumnLabel(j + 1) : f; String t = metaData.getColumnTypeName(j + 1); TableFiled field = new TableFiled(); field.setFieldName(l); field.setRemarks(l); field.setFieldType(t); field.setFieldSize(metaData.getColumnDisplaySize(j + 1)); if(t.equalsIgnoreCase("LONG")){field.setFieldSize(65533);} //oracle LONG fieldList.add(field); } return fieldList; } @Override public List getTables(DatasourceRequest datasourceRequest) throws Exception { List tables = new ArrayList<>(); String queryStr = getTablesSql(datasourceRequest); Connection con = null; try { con = getConnectionFromPool(datasourceRequest); Statement statement = con.createStatement(); ResultSet resultSet = statement.executeQuery(queryStr); while (resultSet.next()) { tables.add(resultSet.getString(1)); } resultSet.close(); statement.close(); return tables; } catch (Exception e) { DataEaseException.throwException(e); } finally { if(con != null){ con.close(); } } return new ArrayList<>(); } @Override public List getTableFileds(DatasourceRequest datasourceRequest) throws Exception { List list = new LinkedList<>(); Connection connection = null; try { connection = getConnectionFromPool(datasourceRequest); DatabaseMetaData databaseMetaData = connection.getMetaData(); ResultSet resultSet = databaseMetaData.getColumns(null, "%", datasourceRequest.getTable(), "%"); while (resultSet.next()) { String tableName = resultSet.getString("TABLE_NAME"); String database = resultSet.getString("TABLE_CAT"); if(database != null){ if (tableName.equals(datasourceRequest.getTable()) && database.equalsIgnoreCase(getDatabase(datasourceRequest))) { TableFiled tableFiled = getTableFiled(resultSet); list.add(tableFiled); } }else { if (tableName.equals(datasourceRequest.getTable())) { TableFiled tableFiled = getTableFiled(resultSet); list.add(tableFiled); } } } resultSet.close(); } catch (SQLException e) { DataEaseException.throwException(e); } catch (Exception e) { DataEaseException.throwException(e); } finally { if(connection != null){ connection.close(); } } return list; } private TableFiled getTableFiled(ResultSet resultSet) throws SQLException { TableFiled tableFiled = new TableFiled(); String colName = resultSet.getString("COLUMN_NAME"); tableFiled.setFieldName(colName); String remarks = resultSet.getString("REMARKS"); if (remarks == null || remarks.equals("")) { remarks = colName; } tableFiled.setRemarks(remarks); tableFiled.setFieldSize(Integer.valueOf(resultSet.getString("COLUMN_SIZE"))); String dbType = resultSet.getString("TYPE_NAME"); tableFiled.setFieldType(dbType); if(dbType.equalsIgnoreCase("LONG")){tableFiled.setFieldSize(65533);} if(StringUtils.isNotEmpty(dbType) && dbType.toLowerCase().contains("date") && tableFiled.getFieldSize() < 50 ){ tableFiled.setFieldSize(50); } return tableFiled; } @Override public void test(DatasourceRequest datasourceRequest) throws Exception { String queryStr = getTablesSql(datasourceRequest); Connection con = null; try { con = getConnection(datasourceRequest); Statement ps = con.createStatement(); ResultSet resultSet = ps.executeQuery(queryStr); resultSet.close(); ps.close(); } catch (Exception e) { DataEaseException.throwException(e); } finally { if(con != null){con.close();} } } public Long count(DatasourceRequest datasourceRequest) throws Exception { Connection con = null; try { con = getConnectionFromPool(datasourceRequest); Statement ps = con.createStatement(); ResultSet resultSet = ps.executeQuery(datasourceRequest.getQuery()); while (resultSet.next()) { return resultSet.getLong(1); } } catch (Exception e) { DataEaseException.throwException( e); } finally { con.close(); } return 0L; } private Connection getConnectionFromPool(DatasourceRequest datasourceRequest) throws Exception { ComboPooledDataSource dataSource = jdbcConnection.get(datasourceRequest.getDatasource().getId()); if (dataSource == null) { initDataSource(datasourceRequest, "add"); } dataSource = jdbcConnection.get(datasourceRequest.getDatasource().getId()); Connection co = dataSource.getConnection(); return co; } @Override public void initDataSource(DatasourceRequest datasourceRequest, String type) throws Exception { switch (type){ case "add": ComboPooledDataSource dataSource = jdbcConnection.get(datasourceRequest.getDatasource().getId()); if (dataSource == null) { extracted(datasourceRequest); } break; case "edit": jdbcConnection.remove(datasourceRequest.getDatasource().getId()); extracted(datasourceRequest); break; case "delete": jdbcConnection.remove(datasourceRequest.getDatasource().getId()); break; default: break; } } private void extracted(DatasourceRequest datasourceRequest) throws PropertyVetoException { ComboPooledDataSource dataSource; dataSource = new ComboPooledDataSource(); setCredential(datasourceRequest, dataSource); dataSource.setMaxIdleTime(30); // 最大空闲时间 dataSource.setAcquireIncrement(5);// 增长数 dataSource.setInitialPoolSize(initPoolSize);// 初始连接数 dataSource.setMinPoolSize(initPoolSize); // 最小连接数 dataSource.setMaxPoolSize(maxConnections); // 最大连接数 dataSource.setAcquireRetryAttempts(30);// 获取连接重试次数 dataSource.setIdleConnectionTestPeriod(60); // 每60s检查数据库空闲连接 dataSource.setMaxStatements(0); // c3p0全局的PreparedStatements缓存的大小 dataSource.setBreakAfterAcquireFailure(false); // 获取连接失败将会引起所有等待连接池来获取连接的线程抛出异常。但是数据源仍有效保留,并在下次调用getConnection()的时候继续尝试获取连接。如果设为true,那么在尝试获取连接失败后该数据源将申明已断开并永久关闭。Default: false dataSource.setTestConnectionOnCheckout(false); // 在每个connection 提交是校验有效性 dataSource.setTestConnectionOnCheckin(true); // 取得连接的同时将校验连接的有效性 dataSource.setCheckoutTimeout(60000); // 从连接池获取连接的超时时间,如设为0则无限期等待。单位毫秒,默认为0 // dataSource.setPreferredTestQuery("SELECT 1"); dataSource.setDebugUnreturnedConnectionStackTraces(true); dataSource.setUnreturnedConnectionTimeout(3600); jdbcConnection.put(datasourceRequest.getDatasource().getId(), dataSource); } private static Connection getConnection(DatasourceRequest datasourceRequest) throws Exception { String username = null; String password = null; String driver = null; String jdbcurl = null; DatasourceTypes datasourceType = DatasourceTypes.valueOf(datasourceRequest.getDatasource().getType()); switch (datasourceType) { case mysql: MysqlConfigration mysqlConfigration = new Gson().fromJson(datasourceRequest.getDatasource().getConfiguration(), MysqlConfigration.class); username = mysqlConfigration.getUsername(); password = mysqlConfigration.getPassword(); driver = mysqlConfigration.getDriver(); jdbcurl = mysqlConfigration.getJdbc(); break; case doris: MysqlConfigration dorisConfigration = new Gson().fromJson(datasourceRequest.getDatasource().getConfiguration(), MysqlConfigration.class); username = dorisConfigration.getUsername(); password = dorisConfigration.getPassword(); driver = dorisConfigration.getDriver(); jdbcurl = dorisConfigration.getJdbc(); break; case sqlServer: SqlServerConfigration sqlServerConfigration = new Gson().fromJson(datasourceRequest.getDatasource().getConfiguration(), SqlServerConfigration.class); username = sqlServerConfigration.getUsername(); password = sqlServerConfigration.getPassword(); driver = sqlServerConfigration.getDriver(); jdbcurl = sqlServerConfigration.getJdbc(); break; case oracle: OracleConfigration oracleConfigration = new Gson().fromJson(datasourceRequest.getDatasource().getConfiguration(), OracleConfigration.class); username = oracleConfigration.getUsername(); password = oracleConfigration.getPassword(); driver = oracleConfigration.getDriver(); jdbcurl = oracleConfigration.getJdbc(); break; default: break; } Class.forName(driver); Properties props = new Properties(); props.setProperty("user", username); if (StringUtils.isNotBlank(password)) { props.setProperty("password", password); } return DriverManager.getConnection(jdbcurl, props); } private void setCredential(DatasourceRequest datasourceRequest, ComboPooledDataSource dataSource) throws PropertyVetoException { DatasourceTypes datasourceType = DatasourceTypes.valueOf(datasourceRequest.getDatasource().getType()); switch (datasourceType) { case mysql: MysqlConfigration mysqlConfigration = new Gson().fromJson(datasourceRequest.getDatasource().getConfiguration(), MysqlConfigration.class); dataSource.setUser(mysqlConfigration.getUsername()); dataSource.setDriverClass(mysqlConfigration.getDriver()); dataSource.setPassword(mysqlConfigration.getPassword()); dataSource.setJdbcUrl(mysqlConfigration.getJdbc()); break; case doris: MysqlConfigration dorisConfigration = new Gson().fromJson(datasourceRequest.getDatasource().getConfiguration(), MysqlConfigration.class); dataSource.setUser(dorisConfigration.getUsername()); dataSource.setDriverClass(dorisConfigration.getDriver()); dataSource.setPassword(dorisConfigration.getPassword()); dataSource.setJdbcUrl(dorisConfigration.getJdbc()); break; case sqlServer: SqlServerConfigration sqlServerConfigration = new Gson().fromJson(datasourceRequest.getDatasource().getConfiguration(), SqlServerConfigration.class); dataSource.setUser(sqlServerConfigration.getUsername()); dataSource.setDriverClass(sqlServerConfigration.getDriver()); dataSource.setPassword(sqlServerConfigration.getPassword()); dataSource.setJdbcUrl(sqlServerConfigration.getJdbc()); break; case oracle: OracleConfigration oracleConfigration = new Gson().fromJson(datasourceRequest.getDatasource().getConfiguration(), OracleConfigration.class); dataSource.setUser(oracleConfigration.getUsername()); dataSource.setDriverClass(oracleConfigration.getDriver()); dataSource.setPassword(oracleConfigration.getPassword()); dataSource.setJdbcUrl(oracleConfigration.getJdbc()); break; default: break; } } private String getDatabase(DatasourceRequest datasourceRequest) { DatasourceTypes datasourceType = DatasourceTypes.valueOf(datasourceRequest.getDatasource().getType()); switch (datasourceType) { case mysql: MysqlConfigration mysqlConfigration = new Gson().fromJson(datasourceRequest.getDatasource().getConfiguration(), MysqlConfigration.class); return mysqlConfigration.getDataBase(); case doris: MysqlConfigration dorisConfigration = new Gson().fromJson(datasourceRequest.getDatasource().getConfiguration(), MysqlConfigration.class); return dorisConfigration.getDataBase(); case sqlServer: SqlServerConfigration sqlServerConfigration = new Gson().fromJson(datasourceRequest.getDatasource().getConfiguration(), SqlServerConfigration.class); return sqlServerConfigration.getDataBase(); default: return null; } } private String getTablesSql(DatasourceRequest datasourceRequest) { DatasourceTypes datasourceType = DatasourceTypes.valueOf(datasourceRequest.getDatasource().getType()); switch (datasourceType) { case mysql: return "show tables;"; case doris: return "show tables;"; case sqlServer: SqlServerConfigration sqlServerConfigration = new Gson().fromJson(datasourceRequest.getDatasource().getConfiguration(), SqlServerConfigration.class); return "SELECT TABLE_NAME FROM DATABASE.INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE';".replace("DATABASE", sqlServerConfigration.getDataBase()); case oracle: return "select TABLE_NAME from USER_TABLES"; default: return "show tables;"; } } }