├── README.md ├── Spring-boot-dms.iml ├── pom.xml └── src ├── main ├── java │ └── com │ │ └── dms │ │ ├── DmsApplication.java │ │ ├── controller │ │ └── TestController.java │ │ ├── dynamicdatasource │ │ ├── DynamicDataExeUtils.java │ │ ├── DynamicDataSourceContextHolder.java │ │ ├── DynamicDataSourceUtils.java │ │ ├── DynamicSqlOptionTypeWithDruidControl.java │ │ └── DynamicSqlSyntaxCheck.java │ │ ├── entity │ │ ├── CfDatasource.java │ │ ├── DynamicSqlOptionTypeEntity.java │ │ ├── MetaIndexEntity.java │ │ ├── Result.java │ │ ├── RsSqlExeRecord.java │ │ ├── RsSqlExeResult.java │ │ ├── SqlExeResult.java │ │ ├── TableFieldEntity.java │ │ ├── TableIndexEntity.java │ │ └── TableInfoEntity.java │ │ ├── enums │ │ ├── DatasourceSearchTypeEnum.java │ │ ├── DatasourceTypeEnum.java │ │ ├── SqlExeRecordStatusEnum.java │ │ ├── SqlExeResultStatusEnum.java │ │ ├── SqlOptionTypeEnum.java │ │ └── SqlSyntaxCheckResultEnum.java │ │ ├── mapper │ │ ├── CfDatasourceMapper.java │ │ ├── RsSqlExeRecordMapper.java │ │ └── RsSqlExeResultMapper.java │ │ ├── service │ │ ├── ISqlExeService.java │ │ └── impl │ │ │ └── SqlExeServiceImpl.java │ │ └── utils │ │ ├── DbUtils.java │ │ └── PPStringUtils.java └── resources │ ├── application.yml │ ├── mapper │ ├── CfDatasourceMapper.xml │ ├── RsSqlExeRecordMapper.xml │ └── RsSqlExeResultMapper.xml │ ├── mybatis-config.xml │ ├── sql │ └── sei-dms.sql │ └── t └── test └── java └── com └── dms └── DmsTest.java /README.md: -------------------------------------------------------------------------------- 1 | 基于Springboot开发的数据库管理工具。 2 | 可在线查询数据库及其字段信息 3 | 完美执行DDL\DML语句,语句有修正功能 4 | 无权限等功能,可轻易移植于其他平台。 5 | 异步执行,性能强劲 6 | -------------------------------------------------------------------------------- /Spring-boot-dms.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 1.5.10.RELEASE 9 | 10 | 11 | 4.0.0 12 | 13 | 14 | UTF-8 15 | 1.8 16 | 17 | 18 | Spring-boot-dms 19 | 20 | 21 | 22 | org.mybatis.spring.boot 23 | mybatis-spring-boot-starter 24 | 1.3.1 25 | 26 | 27 | org.springframework.boot 28 | spring-boot-starter-web 29 | 30 | 31 | mysql 32 | mysql-connector-java 33 | 8.0.11 34 | 35 | 36 | com.microsoft.sqlserver 37 | sqljdbc4 38 | 4.0 39 | 40 | 41 | 42 | org.springframework.boot 43 | spring-boot-starter-test 44 | test 45 | 46 | 47 | org.apache.commons 48 | commons-lang3 49 | 3.8.1 50 | 51 | 52 | org.springframework 53 | spring-jdbc 54 | 5.1.9.RELEASE 55 | 56 | 57 | com.alibaba 58 | druid-spring-boot-starter 59 | 1.1.10 60 | 61 | 62 | com.github.jsqlparser 63 | jsqlparser 64 | 1.4 65 | 66 | 67 | com.alibaba 68 | fastjson 69 | 1.2.46 70 | 71 | 72 | 73 | org.projectlombok 74 | lombok 75 | 1.18.10 76 | compile 77 | 78 | 79 | 80 | 81 | org.springframework.boot 82 | spring-boot-starter-test 83 | 2.2.6.RELEASE 84 | test 85 | 86 | 87 | 88 | 89 | 90 | 91 | org.springframework.boot 92 | spring-boot-maven-plugin 93 | 94 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /src/main/java/com/dms/DmsApplication.java: -------------------------------------------------------------------------------- 1 | package com.dms; 2 | 3 | import org.mybatis.spring.annotation.MapperScan; 4 | import org.springframework.boot.SpringApplication; 5 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 6 | import org.springframework.boot.autoconfigure.SpringBootApplication; 7 | import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; 8 | import org.springframework.boot.web.servlet.ServletComponentScan; 9 | import org.springframework.context.annotation.ComponentScan; 10 | 11 | /** 12 | * @author: Luo 13 | * @description: 14 | * @time: 2020/11/29 14:14 15 | * Modified By: 16 | */ 17 | @SpringBootApplication 18 | @ServletComponentScan 19 | @MapperScan("com.dms.mapper") 20 | public class DmsApplication { 21 | public static void main(String[] args) { 22 | SpringApplication.run(DmsApplication.class, args); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/dms/controller/TestController.java: -------------------------------------------------------------------------------- 1 | package com.dms.controller; 2 | 3 | import com.dms.entity.*; 4 | import com.dms.utils.DbUtils; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.apache.commons.lang3.StringUtils; 7 | import org.springframework.stereotype.Controller; 8 | import org.springframework.web.bind.annotation.PathVariable; 9 | import org.springframework.web.bind.annotation.RequestMapping; 10 | 11 | import java.util.List; 12 | 13 | /** 14 | * @author: Luo 15 | * @description: 16 | * @time: 2020/11/29 14:14 17 | * Modified By: 18 | */ 19 | @Slf4j 20 | @Controller 21 | public class TestController { 22 | @RequestMapping(value = "/datasource/{id}/{db}/{table}/_info") 23 | public Object ajax_get_datasource_db_table_info(@PathVariable("id") Integer id, @PathVariable("db") String db, @PathVariable("table") String table) { 24 | 25 | Object response = new Object(); 26 | try { 27 | CfDatasource datasource = CfDatasource.builder().id(1).ip("127.0.0.1").port(3306).username("root").password("123456").type(1).build(); 28 | if (StringUtils.isNotEmpty(table) && table.indexOf(".") != -1) { 29 | table = table.substring(table.lastIndexOf(".") + 1); 30 | } 31 | List fieldList = DbUtils.getColumnNames(datasource.getId(), datasource.getIp(), datasource.getPort(), datasource.getUsername(), datasource.getPassword(), db, table, datasource.getType()); 32 | 33 | List indexEntityList = DbUtils.getTableIndex(datasource.getId(), datasource.getIp(), datasource.getPort(), datasource.getUsername(), datasource.getPassword(), db, table, datasource.getType()); 34 | 35 | TableInfoEntity tableInfoEntity = DbUtils.getTableInfo(datasource.getId(), datasource.getIp(), datasource.getPort(), datasource.getUsername(), datasource.getPassword(), db, datasource.getType(), table); 36 | 37 | } catch (Exception e) { 38 | log.error("获取数据库表详情接口异常:" + e); 39 | } 40 | return response; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/com/dms/dynamicdatasource/DynamicDataExeUtils.java: -------------------------------------------------------------------------------- 1 | package com.dms.dynamicdatasource; 2 | 3 | import com.dms.entity.DynamicSqlOptionTypeEntity; 4 | import com.dms.entity.SqlExeResult; 5 | import com.dms.enums.DatasourceTypeEnum; 6 | import org.springframework.jdbc.core.JdbcTemplate; 7 | import org.springframework.util.CollectionUtils; 8 | 9 | import java.util.*; 10 | 11 | /** 12 | * 13 | * @description: DML 14 | * @author: Luo 15 | * @time: 2020/11/30 19:21 16 | */ 17 | public class DynamicDataExeUtils { 18 | 19 | /** 20 | * 执行DQL queryForList 21 | * 22 | * @param datasource 23 | * @param sql 24 | * @return 25 | */ 26 | private static SqlExeResult>> queryForList(String datasource, String sql) { 27 | 28 | SqlExeResult>> result = SqlExeResult.>>builder().sql(sql).start_time(new Date()).build(); 29 | JdbcTemplate jdbcTemplate = DynamicDataSourceContextHolder.getJdbcTemplate(datasource); 30 | try { 31 | List> resultList = jdbcTemplate.queryForList(sql); 32 | result.setData(resultList); 33 | if (!CollectionUtils.isEmpty(resultList)) { 34 | Map field_type_map = new HashMap<>(); 35 | Integer count=0; 36 | for (Map stringObjectMap : resultList) { 37 | count++; 38 | if(count>=10){ 39 | break; 40 | } 41 | Set keys = stringObjectMap.keySet(); 42 | keys.forEach(k -> { 43 | if (stringObjectMap.get(k) != null) 44 | field_type_map.put(k, stringObjectMap.get(k).getClass().toString()); 45 | } 46 | ); 47 | } 48 | result.setField_type(field_type_map); 49 | } 50 | 51 | result.setSuccess(true); 52 | 53 | } catch (Exception e) { 54 | result.setSuccess(false); 55 | result.setMessage(e.getMessage()); 56 | } 57 | result.setEnd_time(new Date()); 58 | return result; 59 | } 60 | 61 | /** 62 | * 执行DML update 63 | * 64 | * @param datasource 65 | * @param sql 66 | * @return 67 | */ 68 | private static SqlExeResult>> update(String datasource, String sql) { 69 | 70 | SqlExeResult>> result = SqlExeResult.>>builder().sql(sql).start_time(new Date()).build(); 71 | JdbcTemplate jdbcTemplate = DynamicDataSourceContextHolder.getJdbcTemplate(datasource); 72 | try { 73 | 74 | Integer count = jdbcTemplate.update(sql); 75 | List> resultList = new ArrayList<>(); 76 | HashMap resultMap = new HashMap<>(); 77 | resultMap.put("影响行数", count); 78 | resultList.add(resultMap); 79 | result.setData(resultList); 80 | result.setSuccess(true); 81 | 82 | } catch (Exception e) { 83 | result.setSuccess(false); 84 | result.setMessage(e.getMessage()); 85 | } 86 | result.setEnd_time(new Date()); 87 | 88 | return result; 89 | } 90 | 91 | /** 92 | * 执行DDL execute 93 | * 94 | * @param datasource 95 | * @param sql 96 | * @return 97 | */ 98 | private static SqlExeResult execute(String datasource, String sql) { 99 | 100 | SqlExeResult result = SqlExeResult.builder().sql(sql).start_time(new Date()).build(); 101 | JdbcTemplate jdbcTemplate = DynamicDataSourceContextHolder.getJdbcTemplate(datasource); 102 | try { 103 | jdbcTemplate.execute(sql); 104 | result.setSuccess(true); 105 | 106 | } catch (Exception e) { 107 | result.setSuccess(false); 108 | result.setMessage(e.getMessage()); 109 | } 110 | result.setEnd_time(new Date()); 111 | 112 | return result; 113 | } 114 | 115 | /** 116 | * sql执行入口 117 | * 118 | * @param sql 119 | * @param datasource_id 120 | * @param type 121 | * @param ip 122 | * @param port 123 | * @param db 124 | * @param username 125 | * @param password 126 | * @return 127 | */ 128 | public static List exeSql(String sql, Integer datasource_id, Integer type, String ip, Integer port, String db, String username, String password) { 129 | 130 | String dataSource = DynamicDataSourceUtils.addDataSource(datasource_id, type, ip, port, db, username, password); 131 | 132 | List sqlList = DynamicSqlOptionTypeWithDruidControl.dealSqlOptionType(sql, DatasourceTypeEnum.getByType(type)); 133 | 134 | List resultList = new ArrayList<>(); 135 | 136 | for (DynamicSqlOptionTypeEntity sqlOptionTypeEntity : sqlList) { 137 | switch (sqlOptionTypeEntity.getOption_type_enum()) { 138 | case DQL: 139 | resultList.add(queryForList(dataSource, sqlOptionTypeEntity.getSql())); 140 | break; 141 | case DML: 142 | resultList.add(update(dataSource, sqlOptionTypeEntity.getSql())); 143 | break; 144 | case DDL: 145 | resultList.add(execute(dataSource, sqlOptionTypeEntity.getSql())); 146 | break; 147 | case EXEC: 148 | resultList.add(queryForList(dataSource, sqlOptionTypeEntity.getSql())); 149 | break; 150 | 151 | } 152 | } 153 | return resultList; 154 | } 155 | 156 | } 157 | -------------------------------------------------------------------------------- /src/main/java/com/dms/dynamicdatasource/DynamicDataSourceContextHolder.java: -------------------------------------------------------------------------------- 1 | package com.dms.dynamicdatasource; 2 | 3 | import org.springframework.jdbc.core.JdbcTemplate; 4 | 5 | import javax.sql.DataSource; 6 | import java.util.ArrayList; 7 | import java.util.HashMap; 8 | import java.util.List; 9 | import java.util.Map; 10 | /** 11 | * 12 | * @description: 数据源入口 13 | * @author: Luo 14 | * @time: 2020/11/29 19:22 15 | */ 16 | public class DynamicDataSourceContextHolder { 17 | 18 | 19 | private static Map dataSourceMap = new HashMap<>(); 20 | 21 | private static Map jdbcTemplateMap = new HashMap<>(); 22 | 23 | public static List dataSourceNames = new ArrayList<>(); 24 | 25 | private static final ThreadLocal CONTEXT_HOLDER = new ThreadLocal<>(); 26 | 27 | 28 | public static void setDataSource(String dataSourceName) { 29 | if (dataSourceMap.containsKey(dataSourceName)) { 30 | CONTEXT_HOLDER.set(dataSourceName); 31 | } else { 32 | throw new NullPointerException("不存在的dataSourceName:" + dataSourceName); 33 | } 34 | } 35 | 36 | public static String getDataSource() { 37 | return CONTEXT_HOLDER.get(); 38 | } 39 | 40 | public static void clearDataSource() { 41 | CONTEXT_HOLDER.remove(); 42 | } 43 | 44 | 45 | public static void putDataSource(String sourceName, DataSource dataSource) { 46 | dataSourceMap.put(sourceName, dataSource); 47 | } 48 | 49 | public static DataSource getDataSource(String sourceName) { 50 | return dataSourceMap.get(sourceName); 51 | } 52 | 53 | public static boolean containsDataSource(String dataSourceName) { 54 | return dataSourceNames.contains(dataSourceName); 55 | } 56 | 57 | public static void putJdbcTemplate(String dataSourceName, JdbcTemplate jdbcTemplate) { 58 | if (!jdbcTemplateMap.containsKey(dataSourceName)) { 59 | jdbcTemplateMap.put(dataSourceName, jdbcTemplate); 60 | } 61 | } 62 | 63 | public static JdbcTemplate getJdbcTemplate(String dataSourceName) { 64 | if (jdbcTemplateMap.containsKey(dataSourceName)) { 65 | return jdbcTemplateMap.get(dataSourceName); 66 | } 67 | return null; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/com/dms/dynamicdatasource/DynamicDataSourceUtils.java: -------------------------------------------------------------------------------- 1 | package com.dms.dynamicdatasource; 2 | 3 | import com.alibaba.druid.pool.DruidDataSource; 4 | import com.dms.enums.DatasourceTypeEnum; 5 | import org.apache.commons.lang3.StringUtils; 6 | import org.springframework.jdbc.core.JdbcTemplate; 7 | 8 | import javax.sql.DataSource; 9 | import java.util.Properties; 10 | 11 | public class DynamicDataSourceUtils { 12 | 13 | /** 14 | * 添加数据源 15 | * 为了防止多线程添加同一个数据源,这里采用同步,同时会判断是否已存在 16 | * 17 | * @param datasource_id 18 | * @param type 19 | * @param ip 20 | * @param port 21 | * @param db 实例名 22 | * @param username 23 | * @param password 24 | * @return String 新建数据源对应的key,如果已经存在,则返回之前的key。 25 | */ 26 | public static synchronized String addDataSource(Integer datasource_id, Integer type, String ip, 27 | int port, String db, String username, String password) { 28 | 29 | String dataSourceName = getDataSourceName(datasource_id, type, db); 30 | 31 | if (DynamicDataSourceContextHolder.getDataSource(dataSourceName) == null) { 32 | DataSource ds = createDataSource(ip, port, db, username, password, type); 33 | //存储数据源 34 | if (null != ds) { 35 | DynamicDataSourceContextHolder.putDataSource(dataSourceName, ds); 36 | //存储jdbcTemplate 37 | DynamicDataSourceContextHolder.putJdbcTemplate(dataSourceName, new JdbcTemplate(ds)); 38 | } 39 | 40 | } 41 | 42 | return dataSourceName; 43 | } 44 | 45 | 46 | public static String getDataSourceName(Integer datasource_id, Integer type, String db) { 47 | return (DatasourceTypeEnum.getByType(type).getName() + "_" + datasource_id + "_" + db).toUpperCase(); 48 | } 49 | 50 | /** 51 | * 创建一个数据源 52 | * 53 | * @param ip 54 | * @param port 55 | * @param db 56 | * @param username 57 | * @param password 58 | * @return 59 | */ 60 | private static DataSource createDataSource(String ip, int port, String db, String username, String password, Integer type) { 61 | if (StringUtils.isEmpty(db)) { 62 | return null; 63 | } 64 | 65 | Properties properties = new Properties(); 66 | properties.setProperty("remarks", "true"); 67 | properties.setProperty("useInformationSchema", "true"); 68 | DruidDataSource dds = new DruidDataSource(); 69 | dds.setDriverClassName(DatasourceTypeEnum.getByType(type).getDriver()); 70 | dds.setUrl(getConnectionUrlWithDb(ip, port, db, type)); 71 | dds.setUsername(username); 72 | dds.setPassword(password); 73 | dds.setConnectProperties(properties); 74 | dds.setMaxActive(5); 75 | dds.setMinIdle(1); 76 | dds.setInitialSize(1); 77 | dds.setMaxWait(60 * 1000); 78 | return dds; 79 | } 80 | 81 | private static String getConnectionUrlWithDb(String ip, Integer port, String db, Integer type) { 82 | switch (DatasourceTypeEnum.getByType(type)) { 83 | case MYSQL: 84 | return "jdbc:" + DatasourceTypeEnum.MYSQL.getName() + "://" + ip + ":" + port + "/" + db + "?useSSL=false&useUnicode=true&characterEncoding=utf8&tinyInt1isBit=false"; 85 | case SQL_SERVER: 86 | return "jdbc:" + DatasourceTypeEnum.SQL_SERVER.getName() + "://" + ip + ":" + port + ";DatabaseName=" + db; 87 | 88 | } 89 | return null; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/main/java/com/dms/dynamicdatasource/DynamicSqlOptionTypeWithDruidControl.java: -------------------------------------------------------------------------------- 1 | package com.dms.dynamicdatasource; 2 | 3 | import com.alibaba.druid.sql.SQLUtils; 4 | import com.alibaba.druid.sql.ast.SQLStatement; 5 | import com.alibaba.druid.sql.ast.statement.*; 6 | import com.dms.entity.DynamicSqlOptionTypeEntity; 7 | import com.dms.enums.DatasourceTypeEnum; 8 | import com.dms.enums.SqlOptionTypeEnum; 9 | import org.apache.commons.lang3.StringUtils; 10 | import org.springframework.util.CollectionUtils; 11 | 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | /** 15 | * 16 | * @description: 大SQL拆分 17 | * @author: Luo 18 | * @time: 2020/11/30 19:22 19 | */ 20 | public class DynamicSqlOptionTypeWithDruidControl { 21 | 22 | /** 23 | * SQL分割 +分类 24 | * 25 | * @param sql 26 | * @return 27 | */ 28 | public static List dealSqlOptionType(String sql, DatasourceTypeEnum datasourceTypeEnum) { 29 | List sqlOptionTypeEntityList = new ArrayList<>(); 30 | 31 | if (StringUtils.isNotEmpty(sql)) { 32 | 33 | List smList = SQLUtils.parseStatements(sql, datasourceTypeEnum.getName()); 34 | 35 | 36 | if (!CollectionUtils.isEmpty(smList)) { 37 | smList.forEach(s -> { 38 | DynamicSqlOptionTypeEntity sqlOptionTypeEntity = DynamicSqlOptionTypeEntity.builder() 39 | .datasource_type_enum(datasourceTypeEnum) 40 | .origin_sql(s.toString()) 41 | .sql(s.toString()) 42 | .druidObj(s) 43 | .build(); 44 | 45 | if (s instanceof SQLUpdateStatement || s instanceof SQLDeleteStatement || s instanceof SQLInsertStatement) { 46 | sqlOptionTypeEntity.setOption_type_enum(SqlOptionTypeEnum.DML); 47 | 48 | } else if (s instanceof SQLDDLStatement) { 49 | sqlOptionTypeEntity.setOption_type_enum(SqlOptionTypeEnum.DDL); 50 | } else if (s instanceof SQLSelectStatement) { 51 | sqlOptionTypeEntity.setOption_type_enum(SqlOptionTypeEnum.DQL); 52 | } else { 53 | sqlOptionTypeEntity.setOption_type_enum(SqlOptionTypeEnum.EXEC); 54 | } 55 | 56 | sqlOptionTypeEntityList.add(sqlOptionTypeEntity); 57 | 58 | }); 59 | return sqlOptionTypeEntityList; 60 | } 61 | } 62 | return sqlOptionTypeEntityList; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/com/dms/dynamicdatasource/DynamicSqlSyntaxCheck.java: -------------------------------------------------------------------------------- 1 | package com.dms.dynamicdatasource; 2 | 3 | import com.alibaba.druid.sql.ast.statement.SQLDeleteStatement; 4 | import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock; 5 | import com.alibaba.druid.sql.ast.statement.SQLSelectStatement; 6 | import com.alibaba.druid.sql.ast.statement.SQLUpdateStatement; 7 | import com.dms.entity.DynamicSqlOptionTypeEntity; 8 | import com.dms.enums.DatasourceTypeEnum; 9 | import com.dms.enums.SqlSyntaxCheckResultEnum; 10 | import org.apache.commons.lang3.StringUtils; 11 | /** 12 | * 13 | * @description: 主要用于DQL查询限制及DMLwhere控制 14 | * @author: Luo 15 | * @time: 2020/11/30 19:22 16 | */ 17 | public class DynamicSqlSyntaxCheck { 18 | 19 | public final static Integer LIMIT_ROW_NUM = 100; 20 | 21 | /** 22 | * 检查语法 +发现语法问题 修复 23 | * 24 | * @return 25 | */ 26 | 27 | public static void check(DynamicSqlOptionTypeEntity entity) { 28 | if (StringUtils.isNotEmpty(entity.getSql())) { 29 | switch (entity.getOption_type_enum()) { 30 | case DQL: 31 | if (entity.getDatasource_type_enum() == DatasourceTypeEnum.MYSQL) { 32 | if (entity.getDruidObj() instanceof SQLSelectStatement) { 33 | SQLSelectQueryBlock query = ((SQLSelectQueryBlock) (((SQLSelectStatement) entity.getDruidObj()).getSelect().getQuery())); 34 | 35 | if (null == query.getLimit()) { 36 | entity.setSyntax_check_result_enum(SqlSyntaxCheckResultEnum.NO_LIMIT); 37 | query.limit(LIMIT_ROW_NUM, 0); 38 | entity.setSql(query.getParent().toString()); 39 | } 40 | 41 | } 42 | } 43 | 44 | break; 45 | case DML: 46 | if (entity.getDruidObj() instanceof SQLUpdateStatement) { 47 | 48 | if (null == ((SQLUpdateStatement) entity.getDruidObj()).getWhere()) { 49 | entity.setSyntax_check_result_enum(SqlSyntaxCheckResultEnum.NO_WHERE); 50 | } 51 | 52 | } else if (entity.getDruidObj() instanceof SQLDeleteStatement) { 53 | if (null == ((SQLDeleteStatement) entity.getDruidObj()).getWhere()) { 54 | entity.setSyntax_check_result_enum(SqlSyntaxCheckResultEnum.NO_WHERE); 55 | 56 | } 57 | } 58 | break; 59 | } 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/com/dms/entity/CfDatasource.java: -------------------------------------------------------------------------------- 1 | package com.dms.entity; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | import java.util.Date; 9 | @Data 10 | @Builder 11 | @AllArgsConstructor 12 | @NoArgsConstructor 13 | public class CfDatasource { 14 | private Integer id; 15 | 16 | private String name; 17 | 18 | private String description; 19 | // 1. Mysql 2. Sqlserver 3. mongodb 4. Redis 5. mq 20 | private Integer type; 21 | 22 | private String ip; 23 | 24 | private Integer port; 25 | 26 | private String db; 27 | 28 | private String username; 29 | 30 | private String password; 31 | 32 | private String creator_name; 33 | 34 | private String creator_account; 35 | 36 | private Date create_time; 37 | 38 | private Date update_time; 39 | // 开启关闭 40 | private Integer query_switch; 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/com/dms/entity/DynamicSqlOptionTypeEntity.java: -------------------------------------------------------------------------------- 1 | package com.dms.entity; 2 | 3 | import com.dms.enums.DatasourceTypeEnum; 4 | import com.dms.enums.SqlOptionTypeEnum; 5 | import com.dms.enums.SqlSyntaxCheckResultEnum; 6 | import lombok.AllArgsConstructor; 7 | import lombok.Builder; 8 | import lombok.Data; 9 | import lombok.NoArgsConstructor; 10 | 11 | @Data 12 | @Builder 13 | @AllArgsConstructor 14 | @NoArgsConstructor 15 | public class DynamicSqlOptionTypeEntity { 16 | private String origin_sql; 17 | 18 | private String sql; 19 | 20 | private SqlOptionTypeEnum option_type_enum; 21 | 22 | private DatasourceTypeEnum datasource_type_enum; 23 | 24 | private SqlSyntaxCheckResultEnum syntax_check_result_enum; 25 | 26 | private Object druidObj; 27 | 28 | private String table_list; 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/dms/entity/MetaIndexEntity.java: -------------------------------------------------------------------------------- 1 | package com.dms.entity; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | @Data 9 | @Builder 10 | @AllArgsConstructor 11 | @NoArgsConstructor 12 | public class MetaIndexEntity { 13 | private String INDEX_NAME; 14 | private String COLUMN_NAME; 15 | private Boolean NON_UNIQUE; 16 | private Integer ORDINAL_POSITION; 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/dms/entity/Result.java: -------------------------------------------------------------------------------- 1 | package com.dms.entity; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | @Data 9 | @Builder 10 | @AllArgsConstructor 11 | @NoArgsConstructor 12 | public class Result { 13 | private boolean success; 14 | private T data; 15 | private String message; 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/dms/entity/RsSqlExeRecord.java: -------------------------------------------------------------------------------- 1 | package com.dms.entity; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | import java.util.Date; 9 | 10 | @Data 11 | @Builder 12 | @AllArgsConstructor 13 | @NoArgsConstructor 14 | public class RsSqlExeRecord { 15 | private Integer id; 16 | 17 | private String sql_text; 18 | 19 | private Integer datasource_id; 20 | 21 | private String db; 22 | 23 | private Integer status; 24 | 25 | private String create_account; 26 | 27 | private String create_name; 28 | 29 | private Date create_time; 30 | 31 | private Date update_time; 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/dms/entity/RsSqlExeResult.java: -------------------------------------------------------------------------------- 1 | package com.dms.entity; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | import java.util.Date; 9 | 10 | @Data 11 | @Builder 12 | @AllArgsConstructor 13 | @NoArgsConstructor 14 | public class RsSqlExeResult { 15 | private Integer id; 16 | 17 | private Integer sql_exe_record_id; 18 | 19 | private String sql_text; 20 | 21 | private String result; 22 | 23 | private Date create_time; 24 | 25 | private Date update_time; 26 | 27 | private Integer status; 28 | 29 | private Integer syntax_error_type; 30 | 31 | private String syntax_error_sql; 32 | 33 | private String creator_name; 34 | 35 | private String creator_account; 36 | 37 | private Integer sql_option_type; 38 | 39 | private String datasource_name; 40 | 41 | private Integer datasource_type; 42 | 43 | private String db; 44 | 45 | private Integer datasource_id; 46 | 47 | private String table_name_list; 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/dms/entity/SqlExeResult.java: -------------------------------------------------------------------------------- 1 | package com.dms.entity; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | import java.util.Date; 9 | import java.util.Map; 10 | 11 | @Data 12 | @Builder 13 | @AllArgsConstructor 14 | @NoArgsConstructor 15 | public class SqlExeResult { 16 | private Date start_time; 17 | private Date end_time; 18 | private String sql; 19 | private boolean success; 20 | private T data; 21 | private String message; 22 | private Map field_type; 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/dms/entity/TableFieldEntity.java: -------------------------------------------------------------------------------- 1 | package com.dms.entity; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | @Data 9 | @Builder 10 | @AllArgsConstructor 11 | @NoArgsConstructor 12 | public class TableFieldEntity { 13 | 14 | private String column_name; 15 | private Integer ordinal_position; 16 | private String type_name; 17 | private String extra; 18 | @Builder.Default 19 | private Boolean is_nullable = false; 20 | @Builder.Default 21 | private Boolean is_autoincrement = false; 22 | @Builder.Default 23 | private Boolean is_primary_key = false; 24 | @Builder.Default 25 | private Boolean is_unsigned = false; 26 | private String column_def; 27 | private String remarks; 28 | @Builder.Default 29 | private Boolean is_online = true; 30 | 31 | private String online_column_name; 32 | 33 | private String online_after; 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/dms/entity/TableIndexEntity.java: -------------------------------------------------------------------------------- 1 | package com.dms.entity; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | import java.util.List; 9 | 10 | @Data 11 | @Builder 12 | @AllArgsConstructor 13 | @NoArgsConstructor 14 | public class TableIndexEntity { 15 | 16 | private String index_name; 17 | private String index_type; 18 | private String storage_type; 19 | private List index_columns; 20 | private String online_index_name; 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/dms/entity/TableInfoEntity.java: -------------------------------------------------------------------------------- 1 | package com.dms.entity; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | @Data 9 | @Builder 10 | @AllArgsConstructor 11 | @NoArgsConstructor 12 | public class TableInfoEntity { 13 | private String database_name; 14 | private String table_name; 15 | private String engine; 16 | private String character_set; 17 | private String commit; 18 | private String folder; 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/dms/enums/DatasourceSearchTypeEnum.java: -------------------------------------------------------------------------------- 1 | package com.dms.enums; 2 | 3 | public enum DatasourceSearchTypeEnum { 4 | //1. ALL 2. CREATE_BY_ME 5 | ALL(1, "all"), CREATED_BY_ME(2, "created_by_me"), OWNER_BY_ME(3, "owner_by_me"); 6 | 7 | public Integer getType() { 8 | return type; 9 | } 10 | 11 | public String getName() { 12 | return name; 13 | } 14 | 15 | private Integer type; 16 | 17 | private String name; 18 | 19 | 20 | DatasourceSearchTypeEnum(Integer type, String name) { 21 | this.type = type; 22 | this.name = name; 23 | } 24 | 25 | public static DatasourceSearchTypeEnum getByType(Integer type) { 26 | for (DatasourceSearchTypeEnum statusEnum : values()) { 27 | if (statusEnum.getType() == type) { 28 | return statusEnum; 29 | } 30 | } 31 | return null; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/dms/enums/DatasourceTypeEnum.java: -------------------------------------------------------------------------------- 1 | package com.dms.enums; 2 | 3 | public enum DatasourceTypeEnum { 4 | //1. mysql 2. sqlserver 5 | MYSQL(1, "mysql","com.mysql.cj.jdbc.Driver"), SQL_SERVER(2,"sqlserver","com.microsoft.sqlserver.jdbc.SQLServerDriver"); 6 | 7 | public Integer getType() { 8 | return type; 9 | } 10 | 11 | public String getName() { 12 | return name; 13 | } 14 | 15 | public String getDriver() { 16 | return driver; 17 | } 18 | 19 | private Integer type; 20 | 21 | private String name; 22 | 23 | private String driver; 24 | 25 | 26 | DatasourceTypeEnum(Integer type, String name, String driver) { 27 | this.type = type; 28 | this.name = name; 29 | this.driver = driver; 30 | } 31 | 32 | public static DatasourceTypeEnum getByType(Integer type) { 33 | for (DatasourceTypeEnum statusEnum : values()) { 34 | if (statusEnum.getType() == type) { 35 | return statusEnum; 36 | } 37 | } 38 | return null; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/dms/enums/SqlExeRecordStatusEnum.java: -------------------------------------------------------------------------------- 1 | package com.dms.enums; 2 | 3 | public enum SqlExeRecordStatusEnum { 4 | //状态:1 执行中 2. 执行完成 5 | RUNNING(1), COMPLETE(2); 6 | 7 | public Integer getStatus() { 8 | return status; 9 | } 10 | 11 | public void setStatus(Integer status) { 12 | this.status = status; 13 | } 14 | 15 | private Integer status; 16 | 17 | SqlExeRecordStatusEnum(Integer status) { 18 | this.status = status; 19 | } 20 | 21 | public static SqlExeRecordStatusEnum getByStatus(Integer status) { 22 | for (SqlExeRecordStatusEnum statusEnum : values()) { 23 | if (statusEnum.getStatus() == status) { 24 | return statusEnum; 25 | } 26 | } 27 | return null; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/dms/enums/SqlExeResultStatusEnum.java: -------------------------------------------------------------------------------- 1 | package com.dms.enums; 2 | 3 | public enum SqlExeResultStatusEnum { 4 | //状态:1 执行中 2. 执行成功 -1. 执行失败 5 | RUNNING(1), SUCCESS(2), FAIL(-1); 6 | 7 | public Integer getStatus() { 8 | return status; 9 | } 10 | 11 | public void setStatus(Integer status) { 12 | this.status = status; 13 | } 14 | 15 | private Integer status; 16 | 17 | SqlExeResultStatusEnum(Integer status) { 18 | this.status = status; 19 | } 20 | 21 | public static SqlExeResultStatusEnum getByStatus(Integer status) { 22 | for (SqlExeResultStatusEnum statusEnum : values()) { 23 | if (statusEnum.getStatus() == status) { 24 | return statusEnum; 25 | } 26 | } 27 | return null; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/dms/enums/SqlOptionTypeEnum.java: -------------------------------------------------------------------------------- 1 | package com.dms.enums; 2 | 3 | public enum SqlOptionTypeEnum { 4 | //状态:1 执行中 2. 执行完成 5 | DQL(1, "DQL", "查询权限", new String[]{"SELECT"}), DML(2, "DML", "修改数据权限", new String[]{"INSERT", "UPDATE", "DELETE"}), DDL(3, "DDL", "操作表结构权限", new String[]{"CREATE", "ALTER", "DROP", "TRUNCATE", "EXEC", "IF", "DECLARE", "BEGIN"}), EXEC(4, "EXEC", "操作表结构权限", new String[]{}); 6 | 7 | public Integer getType() { 8 | return type; 9 | } 10 | 11 | public void setType(Integer type) { 12 | this.type = type; 13 | } 14 | 15 | 16 | public String[] getCommand() { 17 | return command; 18 | } 19 | 20 | public void setCommand(String[] command) { 21 | this.command = command; 22 | } 23 | 24 | public String getName() { 25 | return name; 26 | } 27 | 28 | public void setName(String name) { 29 | this.name = name; 30 | } 31 | 32 | public String getDesc() { 33 | return desc; 34 | } 35 | 36 | public void setDesc(String desc) { 37 | this.desc = desc; 38 | } 39 | 40 | private Integer type; 41 | 42 | private String[] command; 43 | 44 | private String name; 45 | 46 | private String desc; 47 | 48 | SqlOptionTypeEnum(Integer type, String name, String desc, String[] command) { 49 | this.type = type; 50 | this.command = command; 51 | this.name = name; 52 | this.desc = desc; 53 | } 54 | 55 | public static SqlOptionTypeEnum getByType(Integer type) { 56 | for (SqlOptionTypeEnum typeEnum : values()) { 57 | if (typeEnum.getType() == type) { 58 | return typeEnum; 59 | } 60 | } 61 | return null; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/com/dms/enums/SqlSyntaxCheckResultEnum.java: -------------------------------------------------------------------------------- 1 | package com.dms.enums; 2 | 3 | public enum SqlSyntaxCheckResultEnum { 4 | //状态:0.正常,1 NO_LIMIT 2. NO_WHERE 5 | SUCCESS(0, "没有检测到语法问题", false), NO_LIMIT(1, "SQL缺少返回行数限制!", false), NO_WHERE(2, "SQL缺少WHERE条件限制!", true),NO_PERMISSION(3, "越权操作!", true); 6 | 7 | public Integer getType() { 8 | return type; 9 | } 10 | 11 | public void setType(Integer type) { 12 | this.type = type; 13 | } 14 | 15 | public String getMessage() { 16 | return message; 17 | } 18 | 19 | public void setMessage(String message) { 20 | this.message = message; 21 | } 22 | 23 | public Boolean getStop() { 24 | return stop; 25 | } 26 | 27 | public void setStop(Boolean stop) { 28 | this.stop = stop; 29 | } 30 | 31 | private Integer type; 32 | private String message; 33 | private Boolean stop; 34 | 35 | SqlSyntaxCheckResultEnum(Integer type, String message, Boolean stop) { 36 | this.type = type; 37 | this.message = message; 38 | this.stop = stop; 39 | } 40 | 41 | public static SqlSyntaxCheckResultEnum getByType(Integer type) { 42 | for (SqlSyntaxCheckResultEnum typeEnum : values()) { 43 | if (typeEnum.getType() == type) { 44 | return typeEnum; 45 | } 46 | } 47 | return null; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/dms/mapper/CfDatasourceMapper.java: -------------------------------------------------------------------------------- 1 | package com.dms.mapper; 2 | 3 | 4 | import com.dms.entity.CfDatasource; 5 | import org.apache.ibatis.annotations.Mapper; 6 | 7 | import java.util.List; 8 | @Mapper 9 | public interface CfDatasourceMapper { 10 | int deleteByPrimaryKey(Integer id); 11 | 12 | int insertSelective(CfDatasource record); 13 | 14 | CfDatasource selectByPrimaryKey(Integer id); 15 | 16 | int updateByPrimaryKeySelective(CfDatasource record); 17 | 18 | List selectList(CfDatasource record); 19 | 20 | int selectCount(CfDatasource record); 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/dms/mapper/RsSqlExeRecordMapper.java: -------------------------------------------------------------------------------- 1 | package com.dms.mapper; 2 | 3 | import com.dms.entity.RsSqlExeRecord; 4 | import org.apache.ibatis.annotations.Mapper; 5 | 6 | @Mapper 7 | public interface RsSqlExeRecordMapper { 8 | int deleteByPrimaryKey(Integer id); 9 | 10 | int insertSelective(RsSqlExeRecord record); 11 | 12 | RsSqlExeRecord selectByPrimaryKey(Integer id); 13 | 14 | int updateByPrimaryKeySelective(RsSqlExeRecord record); 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/dms/mapper/RsSqlExeResultMapper.java: -------------------------------------------------------------------------------- 1 | package com.dms.mapper; 2 | 3 | import com.dms.entity.RsSqlExeResult; 4 | import org.apache.ibatis.annotations.Mapper; 5 | 6 | import java.util.List; 7 | @Mapper 8 | public interface RsSqlExeResultMapper { 9 | int deleteByPrimaryKey(Integer id); 10 | 11 | int insertSelective(RsSqlExeResult record); 12 | 13 | RsSqlExeResult selectByPrimaryKey(Integer id); 14 | 15 | int updateByPrimaryKeySelective(RsSqlExeResult record); 16 | 17 | 18 | List selectList(RsSqlExeResult base); 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/dms/service/ISqlExeService.java: -------------------------------------------------------------------------------- 1 | package com.dms.service; 2 | 3 | 4 | import com.dms.entity.RsSqlExeRecord; 5 | import org.springframework.stereotype.Service; 6 | 7 | @Service 8 | public interface ISqlExeService { 9 | void sqlExeAsync(RsSqlExeRecord rsSqlExeRecord, String sql); 10 | 11 | void sqlExe(RsSqlExeRecord rsSqlExeRecord, String sql); 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/dms/service/impl/SqlExeServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.dms.service.impl; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.alibaba.fastjson.serializer.SerializerFeature; 5 | import com.dms.dynamicdatasource.DynamicDataExeUtils; 6 | import com.dms.dynamicdatasource.DynamicSqlOptionTypeWithDruidControl; 7 | import com.dms.dynamicdatasource.DynamicSqlSyntaxCheck; 8 | import com.dms.entity.*; 9 | import com.dms.enums.*; 10 | import com.dms.mapper.CfDatasourceMapper; 11 | import com.dms.mapper.RsSqlExeRecordMapper; 12 | import com.dms.mapper.RsSqlExeResultMapper; 13 | import com.dms.service.ISqlExeService; 14 | import com.dms.utils.PPStringUtils; 15 | import lombok.extern.slf4j.Slf4j; 16 | import org.apache.commons.lang3.StringUtils; 17 | import org.springframework.scheduling.annotation.Async; 18 | import org.springframework.stereotype.Service; 19 | import org.springframework.util.CollectionUtils; 20 | 21 | import javax.annotation.Resource; 22 | import java.util.ArrayList; 23 | import java.util.Date; 24 | import java.util.List; 25 | import java.util.Map; 26 | 27 | /** 28 | * @description sql执行类 29 | * @date 2020/11/30 19:00 30 | * @param 31 | * @return 32 | */ 33 | @Slf4j 34 | @Service 35 | public class SqlExeServiceImpl implements ISqlExeService { 36 | @Resource 37 | private RsSqlExeRecordMapper sqlExeRecordMapper; 38 | @Resource 39 | private RsSqlExeResultMapper sqlExeResultMapper; 40 | @Resource 41 | private CfDatasourceMapper datasourceMapper; 42 | 43 | @Override 44 | @Async("threadExecutor") 45 | public void sqlExeAsync(RsSqlExeRecord rsSqlExeRecord, String sql) { 46 | this.sqlExe(rsSqlExeRecord, sql); 47 | } 48 | 49 | 50 | @Override 51 | public void sqlExe(RsSqlExeRecord rsSqlExeRecord, String sql) { 52 | // 用于数据回滚 53 | sqlExeRecordMapper.insertSelective(rsSqlExeRecord); 54 | 55 | CfDatasource cfDatasource = datasourceMapper.selectByPrimaryKey(rsSqlExeRecord.getDatasource_id()); 56 | 57 | String error_msg = null; 58 | // Sql 拆分 59 | List sqlOptionTypeEntityList = new ArrayList<>(); 60 | try { 61 | sqlOptionTypeEntityList = DynamicSqlOptionTypeWithDruidControl.dealSqlOptionType(sql, DatasourceTypeEnum.getByType(cfDatasource.getType())); 62 | } catch (Exception e) { 63 | error_msg = e.getMessage(); 64 | } 65 | // 如果有错或者sql解析错误 66 | if (StringUtils.isNotEmpty(error_msg) || CollectionUtils.isEmpty(sqlOptionTypeEntityList)) { 67 | SqlExeResult sqlExeResult = SqlExeResult.builder() 68 | .start_time(new Date()) 69 | .end_time(new Date()) 70 | .sql(sql) 71 | .message(StringUtils.isNotEmpty(error_msg) ? error_msg : "请输入要执行的SQL!") 72 | .success(false) 73 | .build(); 74 | sqlExeResultMapper.insertSelective(RsSqlExeResult.builder() 75 | .sql_exe_record_id(rsSqlExeRecord.getId()) 76 | .sql_text(sql) 77 | .create_time(new Date()) 78 | .update_time(new Date()) 79 | .creator_account(rsSqlExeRecord.getCreate_account()) 80 | .creator_name(rsSqlExeRecord.getCreate_name()) 81 | .status(SqlExeResultStatusEnum.FAIL.getStatus()) 82 | .db(rsSqlExeRecord.getDb()) 83 | .datasource_name(cfDatasource.getName()) 84 | .datasource_id(cfDatasource.getId()) 85 | .datasource_type(cfDatasource.getType()) 86 | .sql_option_type(SqlOptionTypeEnum.DQL.getType()) 87 | .result(JSON.toJSONString(sqlExeResult, SerializerFeature.WriteMapNullValue)) 88 | .build()); 89 | 90 | sqlExeRecordMapper.updateByPrimaryKeySelective(RsSqlExeRecord.builder() 91 | .status(SqlExeRecordStatusEnum.COMPLETE.getStatus()) 92 | .id(rsSqlExeRecord.getId()) 93 | .update_time(new Date()) 94 | .build()); 95 | 96 | return; 97 | } 98 | 99 | 100 | sqlOptionTypeEntityList.forEach(sqlOptionTypeEntity -> { 101 | RsSqlExeResult rsSqlExeResult = RsSqlExeResult.builder() 102 | .sql_exe_record_id(rsSqlExeRecord.getId()) 103 | .sql_text(sqlOptionTypeEntity.getOrigin_sql()) 104 | .create_time(new Date()) 105 | .update_time(new Date()) 106 | .creator_account(rsSqlExeRecord.getCreate_account()) 107 | .creator_name(rsSqlExeRecord.getCreate_name()) 108 | .status(SqlExeResultStatusEnum.RUNNING.getStatus()) 109 | .db(rsSqlExeRecord.getDb()) 110 | .datasource_name(cfDatasource.getName()) 111 | .datasource_id(cfDatasource.getId()) 112 | .datasource_type(cfDatasource.getType()) 113 | .sql_option_type(sqlOptionTypeEntity.getOption_type_enum().getType()) 114 | .table_name_list(null != PPStringUtils.getTableNames(sqlOptionTypeEntity.getSql()) ? String.join(",",PPStringUtils.getTableNames(sqlOptionTypeEntity.getSql())) : null) 115 | .build(); 116 | 117 | sqlExeResultMapper.insertSelective(rsSqlExeResult); 118 | 119 | //检查sql语法并修复问题 120 | DynamicSqlSyntaxCheck.check(sqlOptionTypeEntity); 121 | 122 | if (null != sqlOptionTypeEntity.getSyntax_check_result_enum()) { 123 | if (sqlOptionTypeEntity.getSyntax_check_result_enum().getStop()) { 124 | sqlExeResultMapper.updateByPrimaryKeySelective(RsSqlExeResult.builder() 125 | .status(SqlExeResultStatusEnum.FAIL.getStatus()) 126 | .syntax_error_sql(sqlOptionTypeEntity.getOrigin_sql()) 127 | .syntax_error_type(sqlOptionTypeEntity.getSyntax_check_result_enum().getType()) 128 | .update_time(new Date()) 129 | .id(rsSqlExeResult.getId()) 130 | .result(JSON.toJSONString(SqlExeResult.builder().message(sqlOptionTypeEntity.getSyntax_check_result_enum().getMessage()).build(), SerializerFeature.WriteMapNullValue)) 131 | .build()); 132 | } else { 133 | // DML 134 | List exeResultList = DynamicDataExeUtils.exeSql(sqlOptionTypeEntity.getSql(), cfDatasource.getId(), cfDatasource.getType(), cfDatasource.getIp(), cfDatasource.getPort(), rsSqlExeRecord.getDb(), cfDatasource.getUsername(), cfDatasource.getPassword()); 135 | if (!CollectionUtils.isEmpty(exeResultList)) { 136 | SqlExeResult sqlExeResult = exeResultList.get(0); 137 | 138 | RsSqlExeResult result = RsSqlExeResult.builder() 139 | .update_time(new Date()) 140 | .status(sqlExeResult.isSuccess() ? SqlExeResultStatusEnum.SUCCESS.getStatus() : SqlExeResultStatusEnum.FAIL.getStatus()) 141 | .id(rsSqlExeResult.getId()) 142 | .result(JSON.toJSONString(sqlExeResult, SerializerFeature.WriteMapNullValue)) 143 | .build(); 144 | 145 | if (sqlOptionTypeEntity.getSyntax_check_result_enum().getType().equals(SqlSyntaxCheckResultEnum.NO_LIMIT.getType())) { 146 | if (null != sqlExeResult.getData() && ((List>) sqlExeResult.getData()).size() == DynamicSqlSyntaxCheck.LIMIT_ROW_NUM) { 147 | result.setSyntax_error_sql(sqlOptionTypeEntity.getOrigin_sql()); 148 | result.setSyntax_error_type(sqlOptionTypeEntity.getSyntax_check_result_enum().getType()); 149 | } 150 | } 151 | sqlExeResultMapper.updateByPrimaryKeySelective(result); 152 | } 153 | 154 | 155 | } 156 | } else { 157 | List exeResultList = DynamicDataExeUtils.exeSql(sqlOptionTypeEntity.getSql(), cfDatasource.getId(), cfDatasource.getType(), cfDatasource.getIp(), cfDatasource.getPort(), rsSqlExeRecord.getDb(), cfDatasource.getUsername(), cfDatasource.getPassword()); 158 | if (!CollectionUtils.isEmpty(exeResultList)) { 159 | SqlExeResult sqlExeResult = exeResultList.get(0); 160 | sqlExeResultMapper.updateByPrimaryKeySelective(RsSqlExeResult.builder() 161 | .status(sqlExeResult.isSuccess() ? SqlExeResultStatusEnum.SUCCESS.getStatus() : SqlExeResultStatusEnum.FAIL.getStatus()) 162 | .update_time(new Date()) 163 | .id(rsSqlExeResult.getId()) 164 | .result(JSON.toJSONString(sqlExeResult, SerializerFeature.WriteMapNullValue)) 165 | .build()); 166 | } 167 | } 168 | }); 169 | 170 | sqlExeRecordMapper.updateByPrimaryKeySelective(RsSqlExeRecord.builder() 171 | .status(SqlExeRecordStatusEnum.COMPLETE.getStatus()) 172 | .id(rsSqlExeRecord.getId()) 173 | .update_time(new Date()) 174 | .build()); 175 | } 176 | 177 | } 178 | -------------------------------------------------------------------------------- /src/main/java/com/dms/utils/DbUtils.java: -------------------------------------------------------------------------------- 1 | package com.dms.utils; 2 | 3 | import com.dms.dynamicdatasource.DynamicDataSourceContextHolder; 4 | import com.dms.dynamicdatasource.DynamicDataSourceUtils; 5 | import com.dms.entity.*; 6 | import com.dms.enums.DatasourceTypeEnum; 7 | import lombok.extern.slf4j.Slf4j; 8 | import lombok.extern.slf4j.XSlf4j; 9 | import org.springframework.jdbc.core.JdbcTemplate; 10 | import org.springframework.jdbc.support.rowset.SqlRowSet; 11 | import org.springframework.jdbc.support.rowset.SqlRowSetMetaData; 12 | import org.springframework.util.CollectionUtils; 13 | import org.springframework.util.StringUtils; 14 | 15 | import java.sql.*; 16 | import java.util.*; 17 | import java.util.stream.Collectors; 18 | 19 | /** 20 | * @author: Luo 21 | * @description: 22 | * @time: 2020/11/29 14:16 23 | * Modified By: 24 | */ 25 | @Slf4j 26 | public class DbUtils { 27 | private final static String MYSQL_CONNECT_URL = "jdbc:mysql://%s:%s?useSSL=false&serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8"; 28 | 29 | private final static String MYSQL_CONNECT_URL_WITH_DB = "jdbc:mysql://%s:%s/%s?useSSL=false&serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8"; 30 | 31 | private final static String SQL_SERVER_CONNECT_URL = "jdbc:sqlserver://%s:%s"; 32 | 33 | private final static String SQL_SERVER_CONNECT_URL_WITH_DB = "jdbc:sqlserver://%s:%s;DatabaseName=%s"; 34 | 35 | private final static String[] EXCLUDE_DB_LIST_FOR_MYSQL = new String[]{ 36 | "information_schema", "performance_schema", "mysql", "sys" 37 | }; 38 | private final static String[] MYSQL_DATE_TYPE_LIST = new String[] { 39 | "datetime", 40 | "date", 41 | "timestamp", 42 | "time", 43 | "year" 44 | }; 45 | 46 | 47 | private final static String[] MYSQL_TEXT_TYPE_LIST = new String[]{ 48 | "longtext", 49 | "mediumtext", 50 | "text", 51 | "tinytext", 52 | }; 53 | 54 | 55 | private final static String[] SQL_NO_LENGTH_TYPE_LIST = new String[]{ 56 | "text", 57 | "ntext", 58 | "bit", 59 | "tinyint", 60 | "smallint", 61 | "int", 62 | "int identity", 63 | "bigint", 64 | "smallmoney", 65 | "money", 66 | "real", 67 | "datetime", 68 | "datetime2", 69 | "smalldatetime", 70 | "date", 71 | "time", 72 | "datetimeoffset", 73 | "timestamp", 74 | 75 | }; 76 | 77 | /** 78 | * Mysql数据库连接 79 | * 80 | * @param ip 81 | * @param port 82 | * @param username 83 | * @param password 84 | * @return 85 | */ 86 | public static Result connectForMysql(String ip, Integer port, String username, String password) { 87 | return getConnection(ip, port, username, password, DatasourceTypeEnum.MYSQL.getType(), null); 88 | } 89 | 90 | 91 | /** 92 | * 测试数据源连接 93 | * 94 | * @param ip 95 | * @param port 96 | * @param username 97 | * @param password 98 | * @param type 99 | * @return 100 | */ 101 | public static Result testConnect(String ip, Integer port, String username, String password, Integer type) { 102 | Result result = getConnection(ip, port, username, password, type, null); 103 | 104 | if (null != result) { 105 | Connection conn = result.getData(); 106 | if (null != conn) { 107 | try { 108 | conn.close(); 109 | } catch (SQLException e) { 110 | log.error("关闭数据源连接异常!" + e); 111 | } 112 | } 113 | } 114 | return result; 115 | } 116 | 117 | public static Result connectForSqlServer(String ip, Integer port, String username, String password) { 118 | return getConnection(ip, port, username, password, DatasourceTypeEnum.SQL_SERVER.getType(), null); 119 | } 120 | 121 | /** 122 | * 拼接mysql数据库连接地址 123 | * 124 | * @param ip 125 | * @param port 126 | * @return 127 | */ 128 | public static String getMysqlConnectUrl(String ip, Integer port, String db) { 129 | if (!StringUtils.isEmpty(db)) { 130 | return String.format(MYSQL_CONNECT_URL_WITH_DB, ip, port, db); 131 | 132 | } else { 133 | return String.format(MYSQL_CONNECT_URL, ip, port); 134 | } 135 | } 136 | 137 | public static String getMysqlConnectUrl(String ip, Integer port) { 138 | return getMysqlConnectUrl(ip, port, null); 139 | } 140 | 141 | public static String getSqlServerConnectUrl(String ip, Integer port, String db) { 142 | if (!StringUtils.isEmpty(db)) { 143 | return String.format(SQL_SERVER_CONNECT_URL_WITH_DB, ip, port, db); 144 | 145 | } else { 146 | return String.format(SQL_SERVER_CONNECT_URL, ip, port); 147 | } 148 | } 149 | 150 | 151 | public static List getTableNames(String ip, Integer port, String username, String password, String db, Integer type) { 152 | List tableNames = new ArrayList<>(); 153 | Connection conn = getConnection(ip, port, username, password, type, db).getData(); 154 | ResultSet rs = null; 155 | try { 156 | //获取数据库的元数据 157 | DatabaseMetaData metaData = conn.getMetaData(); 158 | //从元数据中获取到所有的表名 159 | rs = metaData.getTables(db, null, null, 160 | new String[]{"TABLE"}); 161 | 162 | while (rs.next()) { 163 | tableNames.add(rs.getString(3)); 164 | } 165 | } catch (SQLException e) { 166 | log.error("获取数据源异常!", e); 167 | } finally { 168 | try { 169 | rs.close(); 170 | conn.close(); 171 | } catch (SQLException e) { 172 | log.error("断开数据源连接异常!", e); 173 | } 174 | } 175 | return tableNames; 176 | } 177 | 178 | 179 | public static TableInfoEntity getTableInfo(Integer datasource_id, String ip, Integer port, String username, String password, String db, Integer type, String tableName) { 180 | TableInfoEntity infoEntity = TableInfoEntity.builder().build(); 181 | try { 182 | String dataSource = DynamicDataSourceUtils.addDataSource(datasource_id, type, ip, port, db, username, password); 183 | JdbcTemplate jdbcTemplate = DynamicDataSourceContextHolder.getJdbcTemplate(dataSource); 184 | 185 | String sql = "select * from information_schema.tables where table_schema='" + db + "' and table_name='" + tableName + "' limit 1"; 186 | 187 | List> resultList = jdbcTemplate.queryForList(sql); 188 | if (resultList.size() > 0) { 189 | Map resultMap = resultList.get(0); 190 | infoEntity.setEngine((String) resultMap.get("ENGINE")); 191 | infoEntity.setCommit((String) resultMap.get("TABLE_COMMENT")); 192 | String charset = (String) resultMap.get("TABLE_COLLATION"); 193 | if (!StringUtils.isEmpty(charset)) { 194 | List charsetList = Arrays.asList(charset.split("_")); 195 | infoEntity.setCharacter_set(charsetList.get(0)); 196 | } 197 | } 198 | 199 | } catch (Exception e) { 200 | log.error("获取数据源异常!", e); 201 | } 202 | return infoEntity; 203 | } 204 | 205 | /** 206 | * 获取字段名称 207 | * 208 | * @param db 209 | * @param tableName 210 | * @return 211 | */ 212 | public static List getColumnNames(Integer datasource_id, String ip, Integer port, String username, String password, String db, String tableName, Integer type) { 213 | List tableFiledEntityList = new ArrayList<>(); 214 | if (StringUtils.isEmpty(tableName)) { 215 | return tableFiledEntityList; 216 | } 217 | 218 | Connection conn = getConnection(ip, port, username, password, type, db).getData(); 219 | ResultSet rs = null; 220 | try { 221 | //获取数据库的元数据 222 | //DatabaseMetaData metaData = conn.getMetaData(); 223 | List primaryKeyList = new ArrayList<>(); 224 | ResultSet primaryKeys = conn.getMetaData().getPrimaryKeys(db, null, tableName); 225 | 226 | while (primaryKeys.next()) { 227 | String primaryKeyColumnName = primaryKeys.getString("COLUMN_NAME"); 228 | primaryKeyList.add(primaryKeyColumnName); 229 | } 230 | ResultSet columns = conn.getMetaData().getColumns(db, "%", tableName, "%"); 231 | 232 | int index = 0; 233 | while (columns.next()) { 234 | index++; 235 | String column_name = columns.getString("COLUMN_NAME"); 236 | Boolean is_unsigned = false; 237 | Integer column_size = columns.getInt("COLUMN_SIZE"); 238 | 239 | String type_name = columns.getString("TYPE_NAME"); 240 | 241 | if (!StringUtils.isEmpty(type_name)) { 242 | if (type_name.toUpperCase().indexOf(" UNSIGNED") != -1) { 243 | is_unsigned = true; 244 | type_name = type_name.replaceAll(" UNSIGNED", ""); 245 | } 246 | } 247 | if (column_size > 0 && !check_is_no_length(type, type_name)) { 248 | type_name += ("(" + column_size + ")"); 249 | } 250 | 251 | tableFiledEntityList.add(TableFieldEntity.builder() 252 | .column_name(column_name) 253 | .is_primary_key(primaryKeyList.contains(columns.getString("COLUMN_NAME")) ? true : false) 254 | .is_unsigned(is_unsigned) 255 | .is_autoincrement(columns.getString("IS_AUTOINCREMENT").equals("YES") ? true : false) 256 | .is_nullable(columns.getString("IS_NULLABLE").equals("YES") ? true : false) 257 | .remarks(columns.getString("REMARKS")) 258 | .type_name(type_name) 259 | .column_def(columns.getString("COLUMN_DEF")) 260 | .is_online(true) 261 | .online_column_name(column_name) 262 | .ordinal_position(index) 263 | .build()); 264 | } 265 | 266 | String dataSource = DynamicDataSourceUtils.addDataSource(datasource_id, type, ip, port, db, username, password); 267 | JdbcTemplate jdbcTemplate = DynamicDataSourceContextHolder.getJdbcTemplate(dataSource); 268 | 269 | String sql = "SELECT * FROM " + tableName; 270 | switch (DatasourceTypeEnum.getByType(type)) { 271 | case SQL_SERVER: 272 | sql = "SELECT TOP 0 * FROM " + tableName; 273 | break; 274 | case MYSQL: 275 | sql = "SELECT * FROM " + tableName + " LIMIT 0"; 276 | break; 277 | } 278 | 279 | SqlRowSet rowSet = jdbcTemplate.queryForRowSet(sql); 280 | SqlRowSetMetaData metaData = rowSet.getMetaData(); 281 | int columnCount = metaData.getColumnCount(); 282 | for (int i = 1; i <= columnCount; i++) { 283 | for (int j = 0; j < tableFiledEntityList.size(); j++) { 284 | 285 | String column_name = metaData.getColumnName(i); 286 | String type_name = metaData.getColumnTypeName(i); 287 | if (type_name.toUpperCase().indexOf(" UNSIGNED") != -1) { 288 | type_name = type_name.replaceAll(" UNSIGNED", ""); 289 | } 290 | if (tableFiledEntityList.get(j).getColumn_name().equals(column_name)) { 291 | TableFieldEntity newTableFieldEntity = tableFiledEntityList.get(j); 292 | newTableFieldEntity.setColumn_name(metaData.getColumnName(i)); 293 | if (metaData.getColumnDisplaySize(i) > 0 && !check_is_no_length(type, type_name)) { 294 | type_name += ("(" + metaData.getColumnDisplaySize(i) + ")"); 295 | newTableFieldEntity.setType_name(type_name); 296 | } 297 | tableFiledEntityList.set(j, newTableFieldEntity); 298 | } 299 | } 300 | 301 | } 302 | 303 | 304 | } catch (SQLException e) { 305 | log.error("获取数据源异常!", e); 306 | } finally { 307 | try { 308 | if (null != rs) 309 | rs.close(); 310 | if (null != conn) 311 | conn.close(); 312 | } catch (SQLException e) { 313 | log.error("断开数据源连接异常!", e); 314 | } 315 | } 316 | return tableFiledEntityList; 317 | } 318 | 319 | 320 | /** 321 | * 获取索引信息 322 | * 323 | * @param db 324 | * @param tableName 325 | * @return 326 | */ 327 | public static List getTableIndex(Integer datasource_id, String ip, Integer port, String username, String password, String db, String tableName, Integer type) { 328 | 329 | Connection conn = getConnection(ip, port, username, password, type).getData(); 330 | List metaIndexEntityList = new ArrayList<>(); 331 | List indexEntityList = new ArrayList<>(); 332 | ResultSet rs = null; 333 | try { 334 | //获取数据库的元数据 335 | DatabaseMetaData metaData = conn.getMetaData(); 336 | //从元数据中获取到表索引信息 337 | rs = metaData.getIndexInfo(db, db, tableName, false, false); 338 | ResultSetMetaData md = rs.getMetaData(); 339 | while (rs.next()) { 340 | MetaIndexEntity metaIndexEntity = MetaIndexEntity.builder().build(); 341 | for (int i = 1; i <= md.getColumnCount(); i++) { 342 | 343 | String name = md.getColumnName(i); 344 | if (name.equals("INDEX_NAME")) { 345 | metaIndexEntity.setINDEX_NAME((String) rs.getObject(i)); 346 | } 347 | 348 | if (name.equals("NON_UNIQUE")) { 349 | metaIndexEntity.setNON_UNIQUE((Boolean) rs.getObject(i)); 350 | } 351 | 352 | if (name.equals("COLUMN_NAME")) { 353 | metaIndexEntity.setCOLUMN_NAME((String) rs.getObject(i)); 354 | } 355 | 356 | if (name.equals("ORDINAL_POSITION")) { 357 | metaIndexEntity.setORDINAL_POSITION((Integer) rs.getObject(i)); 358 | } 359 | 360 | // System.out.println(md.getColumnName(i) + "==" + rs.getObject(i)); 361 | } 362 | 363 | metaIndexEntityList.add(metaIndexEntity); 364 | } 365 | 366 | indexEntityList = deal_meta_index_to_table_index(metaIndexEntityList); 367 | 368 | } catch (SQLException e) { 369 | log.error("获取数据源异常!", e); 370 | } finally { 371 | try { 372 | rs.close(); 373 | conn.close(); 374 | } catch (SQLException e) { 375 | log.error("断开数据源连接异常!", e); 376 | } 377 | } 378 | return indexEntityList; 379 | 380 | } 381 | 382 | 383 | public static List getDbNames(String ip, Integer port, String username, String password, Integer type) { 384 | List dbNameList = new ArrayList<>(); 385 | Connection conn = getConnection(ip, port, username, password, type).getData(); 386 | ResultSet rs = null; 387 | try { 388 | //获取数据库的元数据 389 | DatabaseMetaData metaData = conn.getMetaData(); 390 | //从元数据中获取到所有的表名 391 | rs = metaData.getCatalogs(); 392 | while (rs.next()) { 393 | if (!Arrays.asList(EXCLUDE_DB_LIST_FOR_MYSQL).contains(rs.getString(1))) 394 | dbNameList.add(rs.getString(1)); 395 | } 396 | } catch (SQLException e) { 397 | log.error("获取数据源异常!", e); 398 | } finally { 399 | try { 400 | rs.close(); 401 | conn.close(); 402 | } catch (SQLException e) { 403 | log.error("断开数据源连接异常!", e); 404 | } 405 | } 406 | return dbNameList; 407 | } 408 | 409 | 410 | /** 411 | * 获取数据源连接 412 | * 413 | * @param ip 414 | * @param port 415 | * @param username 416 | * @param password 417 | * @param type 418 | * @return 419 | */ 420 | public static Result getConnection(String ip, Integer port, String username, String password, Integer type, String db) { 421 | Result result = new Result(); 422 | 423 | Properties connectionProps = new Properties(); 424 | connectionProps.put("remarks", "true"); 425 | connectionProps.setProperty("remarksReporting", "true"); 426 | connectionProps.put("user", username); 427 | connectionProps.put("password", password); 428 | try { 429 | switch (DatasourceTypeEnum.getByType(type)) { 430 | case SQL_SERVER: 431 | Class.forName(DatasourceTypeEnum.SQL_SERVER.getDriver()); 432 | result.setData(DriverManager.getConnection(getSqlServerConnectUrl(ip, port, db), connectionProps)); 433 | result.setSuccess(true); 434 | break; 435 | case MYSQL: 436 | Class.forName(DatasourceTypeEnum.MYSQL.getDriver()); 437 | result.setData(DriverManager.getConnection(getMysqlConnectUrl(ip, port, db), connectionProps)); 438 | result.setSuccess(true); 439 | break; 440 | } 441 | 442 | } catch (SQLException e) { 443 | result.setSuccess(false); 444 | result.setMessage("获取数据源连接异常!" + e); 445 | log.error("获取数据源连接异常!" + e); 446 | } catch (ClassNotFoundException e) { 447 | result.setSuccess(false); 448 | result.setMessage("获取Driver异常!" + e); 449 | log.error("获取Driver异常!" + e); 450 | } 451 | return result; 452 | } 453 | 454 | public static Result getConnection(String ip, Integer port, String username, String password, Integer type) { 455 | return getConnection(ip, port, username, password, type, null); 456 | } 457 | 458 | private static boolean check_is_no_length(Integer type, String type_name) { 459 | 460 | if (type.equals(DatasourceTypeEnum.MYSQL.getType())) { 461 | if (Arrays.asList(MYSQL_DATE_TYPE_LIST).contains(type_name.toUpperCase()) || Arrays.asList(MYSQL_DATE_TYPE_LIST).contains(type_name.toLowerCase())) { 462 | return true; 463 | } 464 | 465 | if (Arrays.asList(MYSQL_TEXT_TYPE_LIST).contains(type_name.toUpperCase()) || Arrays.asList(MYSQL_TEXT_TYPE_LIST).contains(type_name.toLowerCase())) { 466 | return true; 467 | } 468 | } 469 | 470 | if (type.equals(DatasourceTypeEnum.SQL_SERVER.getType())) { 471 | if (Arrays.asList(SQL_NO_LENGTH_TYPE_LIST).contains(type_name.toUpperCase()) || Arrays.asList(SQL_NO_LENGTH_TYPE_LIST).contains(type_name.toLowerCase())) { 472 | return true; 473 | } 474 | } 475 | 476 | return false; 477 | } 478 | 479 | 480 | private static List deal_meta_index_to_table_index(List metaIndexEntityList) { 481 | List indexEntityList = new ArrayList<>(); 482 | Map> resultMap = new HashMap<>(); 483 | for (MetaIndexEntity metaIndexEntity : metaIndexEntityList) { 484 | if (!resultMap.containsKey(metaIndexEntity.getINDEX_NAME())) { 485 | List metaIndexEntities = new ArrayList<>(); 486 | metaIndexEntities.add(metaIndexEntity); 487 | resultMap.put(metaIndexEntity.getINDEX_NAME(), metaIndexEntities); 488 | } else { 489 | List metaIndexEntities = resultMap.get(metaIndexEntity.getINDEX_NAME()); 490 | metaIndexEntities.add(metaIndexEntity); 491 | resultMap.put(metaIndexEntity.getINDEX_NAME(), metaIndexEntities); 492 | } 493 | } 494 | 495 | for (String s : resultMap.keySet()) { 496 | List metaIndexEntities = resultMap.get(s); 497 | if (!CollectionUtils.isEmpty(metaIndexEntities)) { 498 | metaIndexEntities = metaIndexEntities.stream().sorted(Comparator.comparing(d -> d.getORDINAL_POSITION(), Comparator.naturalOrder())).collect(Collectors.toList()); 499 | List ids = metaIndexEntities.stream().map(MetaIndexEntity::getCOLUMN_NAME).collect(Collectors.toList()); 500 | indexEntityList.add(TableIndexEntity.builder() 501 | .index_columns(ids) 502 | .index_name(s) 503 | .online_index_name(s) 504 | .index_type(s.equals("PRIMARY") ? "PRIMARY" : (metaIndexEntities.get(0).getNON_UNIQUE() ? "INDEX" : "UNIQUE")) 505 | .build()); 506 | 507 | } 508 | 509 | } 510 | 511 | return indexEntityList; 512 | } 513 | } 514 | -------------------------------------------------------------------------------- /src/main/java/com/dms/utils/PPStringUtils.java: -------------------------------------------------------------------------------- 1 | package com.dms.utils; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import net.sf.jsqlparser.parser.CCJSqlParserManager; 5 | import net.sf.jsqlparser.statement.Statement; 6 | import net.sf.jsqlparser.statement.delete.Delete; 7 | import net.sf.jsqlparser.statement.insert.Insert; 8 | import net.sf.jsqlparser.statement.replace.Replace; 9 | import net.sf.jsqlparser.statement.select.Select; 10 | import net.sf.jsqlparser.statement.update.Update; 11 | import net.sf.jsqlparser.util.TablesNamesFinder; 12 | 13 | import java.io.StringReader; 14 | import java.util.List; 15 | 16 | @Slf4j 17 | public class PPStringUtils { 18 | private static CCJSqlParserManager pm = new CCJSqlParserManager(); 19 | 20 | public static List getTableNames(String sql) { 21 | try { 22 | List tablenames = null; 23 | TablesNamesFinder tablesNamesFinder = new TablesNamesFinder(); 24 | Statement statement = pm.parse(new StringReader(sql)); 25 | if (statement instanceof Select) { 26 | tablenames = tablesNamesFinder.getTableList((Select) statement); 27 | } else if (statement instanceof Update) { 28 | return null; 29 | } else if (statement instanceof Delete) { 30 | return null; 31 | } else if (statement instanceof Replace) { 32 | return null; 33 | } else if (statement instanceof Insert) { 34 | return null; 35 | } 36 | return tablenames; 37 | } catch (Exception e) { 38 | log.error("执行getTableNames异常:" + e); 39 | } 40 | return null; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8080 3 | 4 | spring: 5 | jackson: 6 | date-format: yyyy-MM-dd HH:mm:ss 7 | time-zone: GMT+8 8 | datasource: 9 | url: jdbc:mysql://localhost:3306/sei-dms?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT%2B8 10 | username: root 11 | password: 123456 12 | # 使用druid数据源 13 | type: com.alibaba.druid.pool.DruidDataSource 14 | driver-class-name: com.mysql.cj.jdbc.Driver 15 | # 初始化大小,最小,最大 16 | maxActive: 50 17 | minIdle: 5 18 | initialSize: 5 19 | # 配置获取连接等待超时的时间 20 | maxWait: 60000 21 | # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 22 | timeBetweenEvictionRunsMillis: 60000 23 | # 配置一个连接在池中最小生存的时间,单位是毫秒 24 | minEvictableIdleTimeMillis: 300000 25 | validationQuery: select 'x' 26 | testWhileIdle: true 27 | testOnBorrow: false 28 | testOnReturn: false 29 | # 打开PSCache,并且指定每个连接上PSCache的大小 30 | poolPreparedStatements: true 31 | maxPoolPreparedStatementPerConnectionSize: 20 32 | # maxOpenPreparedStatements: 20 33 | # 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙 34 | filters: stat,wall 35 | 36 | mybatis: 37 | config-location: classpath:mybatis-config.xml 38 | mapper-locations: classpath:mapper/**/*Mapper.xml 39 | type-aliases-package: com.dms.entity 40 | -------------------------------------------------------------------------------- /src/main/resources/mapper/CfDatasourceMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | id, name, description, type, ip, port, db, username, password, 23 | creator_name, creator_account, create_time, update_time,query_switch 24 | 25 | 31 | 32 | delete from cf_datasource 33 | where id = #{id,jdbcType=INTEGER} 34 | 35 | 36 | 38 | insert into cf_datasource 39 | 40 | 41 | id, 42 | 43 | 44 | name, 45 | 46 | 47 | description, 48 | 49 | 50 | type, 51 | 52 | 53 | ip, 54 | 55 | 56 | port, 57 | 58 | 59 | db, 60 | 61 | 62 | username, 63 | 64 | 65 | password, 66 | 67 | 68 | creator_name, 69 | 70 | 71 | creator_account, 72 | 73 | 74 | create_time, 75 | 76 | 77 | update_time, 78 | 79 | 80 | query_switch, 81 | 82 | 83 | 84 | 85 | #{id,jdbcType=INTEGER}, 86 | 87 | 88 | #{name,jdbcType=VARCHAR}, 89 | 90 | 91 | #{description,jdbcType=VARCHAR}, 92 | 93 | 94 | #{type,jdbcType=INTEGER}, 95 | 96 | 97 | #{ip,jdbcType=VARCHAR}, 98 | 99 | 100 | #{port,jdbcType=INTEGER}, 101 | 102 | 103 | #{db,jdbcType=VARCHAR}, 104 | 105 | 106 | #{username,jdbcType=VARCHAR}, 107 | 108 | 109 | #{password,jdbcType=VARCHAR}, 110 | 111 | 112 | #{creator_name,jdbcType=VARCHAR}, 113 | 114 | 115 | #{creator_account,jdbcType=VARCHAR}, 116 | 117 | 118 | #{create_time,jdbcType=TIMESTAMP}, 119 | 120 | 121 | #{update_time,jdbcType=TIMESTAMP}, 122 | 123 | 124 | #{query_switch,jdbcType=INTEGER}, 125 | 126 | 127 | 128 | 129 | update cf_datasource 130 | 131 | 132 | name = #{name,jdbcType=VARCHAR}, 133 | 134 | 135 | description = #{description,jdbcType=VARCHAR}, 136 | 137 | 138 | type = #{type,jdbcType=INTEGER}, 139 | 140 | 141 | ip = #{ip,jdbcType=VARCHAR}, 142 | 143 | 144 | port = #{port,jdbcType=INTEGER}, 145 | 146 | 147 | db = #{db,jdbcType=VARCHAR}, 148 | 149 | 150 | username = #{username,jdbcType=VARCHAR}, 151 | 152 | 153 | password = #{password,jdbcType=VARCHAR}, 154 | 155 | 156 | creator_name = #{creator_name,jdbcType=VARCHAR}, 157 | 158 | 159 | creator_account = #{creator_account,jdbcType=VARCHAR}, 160 | 161 | 162 | create_time = #{create_time,jdbcType=TIMESTAMP}, 163 | 164 | 165 | update_time = #{update_time,jdbcType=TIMESTAMP}, 166 | 167 | 168 | query_switch = #{query_switch,jdbcType=INTEGER}, 169 | 170 | 171 | where id = #{id,jdbcType=INTEGER} 172 | 173 | 174 | 175 | 176 | 186 | 187 | 200 | 201 | -------------------------------------------------------------------------------- /src/main/resources/mapper/RsSqlExeRecordMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | id, sql_text, datasource_id, db, status, create_account, create_name, create_time, update_time 17 | 18 | 24 | 25 | delete from rs_sql_exe_record 26 | where id = #{id,jdbcType=INTEGER} 27 | 28 | 30 | insert into rs_sql_exe_record 31 | 32 | 33 | id, 34 | 35 | 36 | sql_text, 37 | 38 | 39 | datasource_id, 40 | 41 | 42 | db, 43 | 44 | 45 | status, 46 | 47 | 48 | create_account, 49 | 50 | 51 | create_name, 52 | 53 | 54 | create_time, 55 | 56 | 57 | update_time, 58 | 59 | 60 | 61 | 62 | #{id,jdbcType=INTEGER}, 63 | 64 | 65 | #{sql_text,jdbcType=VARCHAR}, 66 | 67 | 68 | #{datasource_id,jdbcType=INTEGER}, 69 | 70 | 71 | #{db,jdbcType=VARCHAR}, 72 | 73 | 74 | #{status,jdbcType=INTEGER}, 75 | 76 | 77 | #{create_account,jdbcType=VARCHAR}, 78 | 79 | 80 | #{create_name,jdbcType=VARCHAR}, 81 | 82 | 83 | #{create_time,jdbcType=TIMESTAMP}, 84 | 85 | 86 | #{update_time,jdbcType=TIMESTAMP}, 87 | 88 | 89 | 90 | 91 | update rs_sql_exe_record 92 | 93 | 94 | sql_text = #{sql_text,jdbcType=VARCHAR}, 95 | 96 | 97 | datasource_id = #{datasource_id,jdbcType=INTEGER}, 98 | 99 | 100 | db = #{db,jdbcType=VARCHAR}, 101 | 102 | 103 | status = #{status,jdbcType=INTEGER}, 104 | 105 | 106 | create_account = #{create_account,jdbcType=VARCHAR}, 107 | 108 | 109 | create_name = #{create_name,jdbcType=VARCHAR}, 110 | 111 | 112 | create_time = #{create_time,jdbcType=TIMESTAMP}, 113 | 114 | 115 | update_time = #{update_time,jdbcType=TIMESTAMP}, 116 | 117 | 118 | where id = #{id,jdbcType=INTEGER} 119 | 120 | 121 | 122 | -------------------------------------------------------------------------------- /src/main/resources/mapper/RsSqlExeResultMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | id, sql_exe_record_id, sql_text, result, create_time, update_time, status,syntax_error_type,syntax_error_sql,creator_name,creator_account, 26 | sql_option_type, datasource_name, datasource_type ,db,datasource_id,group_id,group_name,table_name_list 27 | 28 | 34 | 35 | delete from rs_sql_exe_result 36 | where id = #{id,jdbcType=INTEGER} 37 | 38 | 40 | insert into rs_sql_exe_result 41 | 42 | 43 | id, 44 | 45 | 46 | sql_exe_record_id, 47 | 48 | 49 | sql_text, 50 | 51 | 52 | result, 53 | 54 | 55 | create_time, 56 | 57 | 58 | update_time, 59 | 60 | 61 | status, 62 | 63 | 64 | syntax_error_type, 65 | 66 | 67 | syntax_error_sql, 68 | 69 | 70 | creator_name, 71 | 72 | 73 | creator_account, 74 | 75 | 76 | sql_option_type, 77 | 78 | 79 | datasource_name, 80 | 81 | 82 | datasource_type, 83 | 84 | 85 | db, 86 | 87 | 88 | datasource_id, 89 | 90 | 91 | table_name_list, 92 | 93 | 94 | 95 | 96 | #{id,jdbcType=INTEGER}, 97 | 98 | 99 | #{sql_exe_record_id,jdbcType=INTEGER}, 100 | 101 | 102 | #{sql_text,jdbcType=VARCHAR}, 103 | 104 | 105 | #{result,jdbcType=VARCHAR}, 106 | 107 | 108 | #{create_time,jdbcType=TIMESTAMP}, 109 | 110 | 111 | #{update_time,jdbcType=TIMESTAMP}, 112 | 113 | 114 | #{status,jdbcType=INTEGER}, 115 | 116 | 117 | #{syntax_error_type,jdbcType=INTEGER}, 118 | 119 | 120 | #{syntax_error_sql,jdbcType=VARCHAR}, 121 | 122 | 123 | #{creator_name,jdbcType=VARCHAR}, 124 | 125 | 126 | #{creator_account,jdbcType=VARCHAR}, 127 | 128 | 129 | #{sql_option_type,jdbcType=INTEGER}, 130 | 131 | 132 | #{datasource_name,jdbcType=VARCHAR}, 133 | 134 | 135 | #{datasource_type,jdbcType=INTEGER}, 136 | 137 | 138 | #{db,jdbcType=VARCHAR}, 139 | 140 | 141 | #{datasource_id,jdbcType=INTEGER}, 142 | 143 | 144 | #{table_name_list,jdbcType=VARCHAR}, 145 | 146 | 147 | 148 | 149 | update rs_sql_exe_result 150 | 151 | 152 | sql_exe_record_id = #{sql_exe_record_id,jdbcType=INTEGER}, 153 | 154 | 155 | sql = #{sql_text,jdbcType=VARCHAR}, 156 | 157 | 158 | result = #{result,jdbcType=VARCHAR}, 159 | 160 | 161 | update_time = #{update_time,jdbcType=TIMESTAMP}, 162 | 163 | 164 | status = #{status,jdbcType=INTEGER}, 165 | 166 | 167 | syntax_error_sql = #{syntax_error_sql,jdbcType=VARCHAR}, 168 | 169 | 170 | syntax_error_type = #{syntax_error_type,jdbcType=INTEGER}, 171 | 172 | 173 | where id = #{id,jdbcType=INTEGER} 174 | 175 | 176 | 177 | 187 | 188 | 189 | -------------------------------------------------------------------------------- /src/main/resources/mybatis-config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/main/resources/sql/sei-dms.sql: -------------------------------------------------------------------------------- 1 | /* 2 | Navicat Premium Data Transfer 3 | 4 | Source Server : localhost 5 | Source Server Type : MySQL 6 | Source Server Version : 50730 7 | Source Host : localhost:3306 8 | Source Schema : sei-dms 9 | 10 | Target Server Type : MySQL 11 | Target Server Version : 50730 12 | File Encoding : 65001 13 | 14 | Date: 01/12/2020 21:36:47 15 | */ 16 | 17 | SET NAMES utf8mb4; 18 | SET FOREIGN_KEY_CHECKS = 0; 19 | 20 | -- ---------------------------- 21 | -- Table structure for cf_datasource 22 | -- ---------------------------- 23 | DROP TABLE IF EXISTS `cf_datasource`; 24 | CREATE TABLE `cf_datasource` ( 25 | `id` int(11) NOT NULL AUTO_INCREMENT, 26 | `name` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, 27 | `description` varchar(4096) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, 28 | `type` int(11) NOT NULL COMMENT '1. Mysql 2. Sqlserver 3. mongodb 4. Redis 5. mq', 29 | `ip` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, 30 | `port` int(11) NULL DEFAULT NULL, 31 | `db` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, 32 | `username` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, 33 | `password` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, 34 | `creator_name` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, 35 | `creator_account` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, 36 | `create_time` datetime(0) NOT NULL, 37 | `update_time` datetime(0) NOT NULL, 38 | `query_switch` int(11) NOT NULL DEFAULT 1 COMMENT '1 开启 -1 关闭', 39 | PRIMARY KEY (`id`) USING BTREE 40 | ) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; 41 | 42 | -- ---------------------------- 43 | -- Records of cf_datasource 44 | -- ---------------------------- 45 | INSERT INTO `cf_datasource` VALUES (1, 'localhost', NULL, 1, '127.0.0.1', 3306, NULL, 'root', '123456', '管理员', 'admin', '2020-11-24 10:57:15', '2020-11-24 10:57:36', 1); 46 | 47 | -- ---------------------------- 48 | -- Table structure for rs_sql_exe_record 49 | -- ---------------------------- 50 | DROP TABLE IF EXISTS `rs_sql_exe_record`; 51 | CREATE TABLE `rs_sql_exe_record` ( 52 | `id` int(11) NOT NULL AUTO_INCREMENT, 53 | `sql_text` longtext CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, 54 | `datasource_id` int(11) NOT NULL, 55 | `db` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, 56 | `status` int(11) NOT NULL DEFAULT 1 COMMENT '1. 执行中 2. 执行完成', 57 | `create_account` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, 58 | `create_name` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, 59 | `create_time` datetime(0) NOT NULL, 60 | `update_time` datetime(0) NOT NULL, 61 | PRIMARY KEY (`id`) USING BTREE 62 | ) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; 63 | 64 | -- ---------------------------- 65 | -- Table structure for rs_sql_exe_result 66 | -- ---------------------------- 67 | DROP TABLE IF EXISTS `rs_sql_exe_result`; 68 | CREATE TABLE `rs_sql_exe_result` ( 69 | `id` int(11) NOT NULL AUTO_INCREMENT, 70 | `sql_exe_record_id` int(11) NOT NULL, 71 | `sql_text` longtext CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, 72 | `result` longtext CHARACTER SET utf8 COLLATE utf8_general_ci NULL, 73 | `create_time` datetime(0) NOT NULL, 74 | `update_time` datetime(0) NOT NULL, 75 | `status` int(11) NOT NULL DEFAULT 1 COMMENT '1. 执行中 -1 执行失败 2. 执行成功', 76 | `syntax_error_type` int(11) NULL DEFAULT NULL, 77 | `syntax_error_sql` longtext CHARACTER SET utf8 COLLATE utf8_general_ci NULL, 78 | `creator_name` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, 79 | `creator_account` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, 80 | `sql_option_type` int(11) NULL DEFAULT NULL, 81 | `datasource_name` varchar(1024) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, 82 | `datasource_type` int(11) NULL DEFAULT NULL, 83 | `db` varchar(1024) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, 84 | `datasource_id` int(11) NULL DEFAULT NULL, 85 | `group_id` int(11) NULL DEFAULT NULL, 86 | `group_name` varchar(1024) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, 87 | `table_name_list` varchar(4096) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, 88 | PRIMARY KEY (`id`) USING BTREE 89 | ) ENGINE = InnoDB AUTO_INCREMENT = 12 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; 90 | 91 | SET FOREIGN_KEY_CHECKS = 1; 92 | -------------------------------------------------------------------------------- /src/main/resources/t: -------------------------------------------------------------------------------- 1 | mybatis.config-location=classpath:mybatis-config.xml 2 | mybatis.mapper-locations=classpath:mapper/**/*Mapper.xml 3 | mybatis.type-aliases-package=com.dms.entity 4 | 5 | 6 | spring.datasource.url=jdbc:mysql://localhost:3306/kb-dms?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT%2B8 7 | spring.datasource.username=root 8 | spring.datasource.password=123456 9 | spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver 10 | -------------------------------------------------------------------------------- /src/test/java/com/dms/DmsTest.java: -------------------------------------------------------------------------------- 1 | package com.dms; 2 | 3 | import com.dms.entity.*; 4 | import com.dms.enums.SqlExeRecordStatusEnum; 5 | import com.dms.service.ISqlExeService; 6 | import com.dms.utils.DbUtils; 7 | import org.apache.commons.lang3.StringUtils; 8 | import org.junit.Test; 9 | import org.junit.runner.RunWith; 10 | import org.springframework.boot.test.context.SpringBootTest; 11 | import org.springframework.test.context.junit4.SpringRunner; 12 | 13 | import javax.annotation.Resource; 14 | import java.util.Date; 15 | import java.util.List; 16 | 17 | /** 18 | * @author: Luo 19 | * @description: 20 | * @time: 2020/11/29 15:12 21 | * Modified By: 22 | */ 23 | @RunWith(SpringRunner.class) 24 | @SpringBootTest 25 | public class DmsTest { 26 | 27 | @Resource 28 | ISqlExeService iSqlExeService; 29 | 30 | @Test 31 | public void test() { 32 | System.out.println("test"); 33 | } 34 | @Test 35 | public void test1() { 36 | try { 37 | String db = "test"; 38 | String table = "student"; 39 | CfDatasource datasource = CfDatasource.builder().id(1).ip("127.0.0.1").port(3306).username("root").password("123456").type(1).build(); 40 | if (StringUtils.isNotEmpty(table) && table.indexOf(".") != -1) { 41 | table = table.substring(table.lastIndexOf(".") + 1); 42 | } 43 | List fieldList = DbUtils.getColumnNames(datasource.getId(), datasource.getIp(), datasource.getPort(), datasource.getUsername(), datasource.getPassword(), db, table, datasource.getType()); 44 | 45 | List indexEntityList = DbUtils.getTableIndex(datasource.getId(), datasource.getIp(), datasource.getPort(), datasource.getUsername(), datasource.getPassword(), db, table, datasource.getType()); 46 | 47 | TableInfoEntity tableInfoEntity = DbUtils.getTableInfo(datasource.getId(), datasource.getIp(), datasource.getPort(), datasource.getUsername(), datasource.getPassword(), db, datasource.getType(), table); 48 | System.out.println(); 49 | } catch (Exception e) { 50 | } 51 | } 52 | @Test 53 | public void test2() { 54 | RsSqlExeRecord rsSqlExeRecord = RsSqlExeRecord.builder() 55 | .id(2) 56 | .sql_text("ALTER TABLE cf_bus_group_owners ADD COLUMN `test` VARCHAR(256) NOT NULL COMMENT 'test' AFTER `bus_group_id`;") 57 | .create_account("admin") 58 | .create_name("管理员") 59 | .update_time(new Date()) 60 | .create_time(new Date()) 61 | .datasource_id(1) 62 | .status(SqlExeRecordStatusEnum.RUNNING.getStatus()) 63 | .db("kb-dms") 64 | .build(); 65 | iSqlExeService.sqlExe(rsSqlExeRecord,"ALTER TABLE cf_bus_group_owners ADD COLUMN `test` VARCHAR(256) NOT NULL COMMENT 'test' AFTER `bus_group_id`;"); 66 | } 67 | } 68 | --------------------------------------------------------------------------------