From 5b39cfe2f106d1f340f71f67aee89f6706eba40e Mon Sep 17 00:00:00 2001 From: diantu Date: Tue, 17 Jan 2023 13:57:12 +0800 Subject: [PATCH] =?UTF-8?q?1.=E4=BF=AE=E5=A4=8Dmysql=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E5=BA=93=E5=9B=A0=E6=95=B0=E6=8D=AE=E5=BA=93=E5=90=8D=E5=8C=85?= =?UTF-8?q?=E5=90=AB=E7=89=B9=E6=AE=8A=E5=AD=97=E7=AC=A6=E5=AF=BC=E8=87=B4?= =?UTF-8?q?=E7=9A=84=E6=8A=A5=E9=94=99=E9=97=AE=E9=A2=98=202.=E4=BF=AE?= =?UTF-8?q?=E5=A4=8Doracle=E5=88=86=E9=A1=B5=E8=AF=AD=E5=8F=A5=E9=94=99?= =?UTF-8?q?=E8=AF=AF=203.oracle=E8=A1=A8=E4=BF=A1=E6=81=AFsql=E8=A1=A5?= =?UTF-8?q?=E5=85=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../db/mapper/oracle/OracleBaseMapper.xml | 129 ++++---- .../db/service/database/MysqlServiceImpl.java | 289 +++++++++++------- .../service/database/OracleServiceImpl.java | 52 +++- 3 files changed, 280 insertions(+), 190 deletions(-) diff --git a/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/framework/db/mapper/oracle/OracleBaseMapper.xml b/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/framework/db/mapper/oracle/OracleBaseMapper.xml index 2a67b23b..453cc24c 100644 --- a/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/framework/db/mapper/oracle/OracleBaseMapper.xml +++ b/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/framework/db/mapper/oracle/OracleBaseMapper.xml @@ -3,80 +3,89 @@ - - - - - - + + + + + + - - - - + + + + - + - + - - + + - - + + - - + + - - + + - - comment on table ${dbName}.${tableName} is #{new Desc} - + + comment on table ${dbName}.${tableName} is #{new Desc} + - - comment on column ${dbName}.${tableName}.${columnName} is #{new Desc} - + + comment on column ${dbName}.${tableName}.${columnName} is #{new Desc} + - - delete from ${dbName}.${tableName} where - - ${key} = #{value} - - + + delete from ${dbName}.${tableName} where + + ${key} = #{value} + + diff --git a/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/service/database/MysqlServiceImpl.java b/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/service/database/MysqlServiceImpl.java index 8f6bd78b..d02e585c 100644 --- a/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/service/database/MysqlServiceImpl.java +++ b/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/service/database/MysqlServiceImpl.java @@ -2,6 +2,7 @@ package com.zyplayer.doc.db.service.database; import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.RandomUtil; +import com.zyplayer.doc.db.controller.param.DataViewParam; import com.zyplayer.doc.db.controller.vo.TableDdlVo; import com.zyplayer.doc.db.framework.db.dto.ColumnInfoDto; import com.zyplayer.doc.db.framework.db.dto.ProcedureDto; @@ -29,126 +30,180 @@ import java.util.Optional; @Service public class MysqlServiceImpl extends DbBaseService { - @Override - public DatabaseProductEnum getDatabaseProduct() { - return DatabaseProductEnum.MYSQL; - } + @Override + public DatabaseProductEnum getDatabaseProduct() { + return DatabaseProductEnum.MYSQL; + } - /** - * mysql数据库名中含有 - 等特殊字符,需要用反引号包裹 - * - * @author diantu - * @since 2023年1月16日 - */ - @Override - public String getUseDbSql(String dbName) { - if (StringUtils.isNotBlank(dbName)) { - return "use " + "`" + dbName + "`"; - } - return null; - } + /** + * mysql数据库名中含有 - 等特殊字符,需要用反引号包裹 + * + * @author diantu + * @since 2023年1月16日 + */ + @Override + public String getUseDbSql(String dbName) { + if (StringUtils.isNotBlank(dbName)) { + return "use " + "`" + dbName + "`"; + } + return null; + } - @Override - public TableDdlVo getTableDdl(Long sourceId, String dbName, String tableName) { - BaseMapper baseMapper = this.getViewAuthBaseMapper(sourceId); - List> tableDdlList = baseMapper.getTableDdl(dbName, tableName); - TableDdlVo tableDdlVo = new TableDdlVo(); - tableDdlVo.setCurrent(DatabaseProductEnum.MYSQL.name().toLowerCase()); - tableDdlVo.setMysql("// 生成失败"); - tableDdlVo.setOracle("// TODO 等待大佬来实现转换"); - // TODO 将建表语句转换为其他数据库的,还不知道怎么做,先这样留着,看有没大佬来实现 - if (CollectionUtils.isNotEmpty(tableDdlList)) { - tableDdlVo.setMysql(tableDdlList.get(0).get("Create Table") + ";"); - } - return tableDdlVo; - } + /** + * 获取查询总条数的SQL(mysql数据库名中含有 - 等特殊字符,需要用反引号包裹) + * + * @author diantu + * @since 2023年1月16日 + */ + @Override + public String getQueryCountSql(DataViewParam dataViewParam) { + StringBuilder sqlSb = new StringBuilder(); + sqlSb.append(String.format("select count(1) as counts from %s.%s", "`"+dataViewParam.getDbName()+"`", dataViewParam.getTableName())); + if (StringUtils.isNotBlank(dataViewParam.getCondition())) { + sqlSb.append(String.format(" where %s", dataViewParam.getCondition())); + } + return sqlSb.toString(); + } - @Override - public void updateTableColumnDesc(Long sourceId, String dbName, String tableName, String columnName, String newDesc) { - BaseMapper baseMapper = this.getViewAuthBaseMapper(sourceId); - // mysql要同时修改类型默认值等,所以先查出来 - MysqlMapper mysqlMapper = databaseRegistrationBean.getBaseMapper(sourceId, MysqlMapper.class); - ColumnInfoDto columnInfo = mysqlMapper.getColumnInfo(dbName, tableName, columnName); - String isNullable = Optional.ofNullable(columnInfo.getIsNullable()).orElse(""); - columnInfo.setIsNullable("yes".equalsIgnoreCase(isNullable) ? "null" : "not null"); - String columnDefault = columnInfo.getColumnDefault(); - if (StringUtils.isNotBlank(columnDefault)) { - columnInfo.setColumnDefault("DEFAULT " + columnDefault); - } else { - columnInfo.setColumnDefault(""); - } - String extra = columnInfo.getExtra(); - columnInfo.setExtra(StringUtils.isBlank(extra) ? "" : extra); - baseMapper.updateTableColumnDesc(dbName, tableName, columnName, newDesc, columnInfo); - } + /** + * 获取全量数据查询的SQL(mysql数据库名中含有 - 等特殊字符,需要用反引号包裹) + * + * @author diantu + * @since 2023年1月17日 + */ + @Override + public String getQueryAllSql(DataViewParam dataViewParam) { + String queryColumns = StringUtils.defaultIfBlank(dataViewParam.getRetainColumn(), "*"); + StringBuilder sqlSb = new StringBuilder(); + sqlSb.append(String.format("select %s from %s.%s", queryColumns, "`" + dataViewParam.getDbName() + "`", dataViewParam.getTableName())); + if (StringUtils.isNotBlank(dataViewParam.getCondition())) { + sqlSb.append(String.format(" where %s", dataViewParam.getCondition())); + } + return sqlSb.toString(); + } - @Override - public ProcedureDto getProcedureDetail(Long sourceId, String dbName, String typeName, String procName) { - BaseMapper baseMapper = this.getViewAuthBaseMapper(sourceId); - ProcedureDto procedureDetail = baseMapper.getProcedureDetail(dbName, typeName, procName); - if (procedureDetail == null) { - // 新建的时候 - ProcedureDto procedureDetailNew = new ProcedureDto(); - if (Objects.equals(typeName, "FUNCTION")) { - procedureDetailNew.setBody("CREATE DEFINER = CURRENT_USER " + typeName + " `" + dbName + "`.`" + procName + "`() RETURNS integer\n" + - "BEGIN\n" + - "\t#Routine body goes here...\n" + - "\tRETURN 0;\n" + - "END;"); - } else { - procedureDetailNew.setBody("CREATE DEFINER = CURRENT_USER " + typeName + " `" + dbName + "`.`" + procName + "`()\n" + - "BEGIN\n" + - "\t#Routine body goes here...\n" + - "END;"); - } - procedureDetailNew.setDb(dbName); - procedureDetailNew.setDefiner("CURRENT_USER"); - procedureDetailNew.setType(typeName); - return procedureDetailNew; - } - // 组装好SQL - String type = procedureDetail.getType(); - String name = procedureDetail.getName(); - String db = procedureDetail.getDb(); - String paramList = StringUtils.defaultIfBlank(procedureDetail.getParamList(), ""); - String[] definerArr = procedureDetail.getDefiner().split("@"); - String createStr = String.format("CREATE DEFINER=`%s`@`%s` %s `%s`.`%s`(%s)", definerArr[0], definerArr[1], type, db, name, paramList); - if (Objects.equals(procedureDetail.getType(), "FUNCTION")) { - createStr += " RETURNS " + procedureDetail.getReturns(); - } - procedureDetail.setBody(createStr + "\r\n" + procedureDetail.getBody()); - return procedureDetail; - } + /** + * 获取分页查询的SQL(mysql数据库名中含有 - 等特殊字符,需要用反引号包裹) + * + * @author diantu + * @since 2023年1月17日 + */ + @Override + public String getQueryPageSql(DataViewParam dataViewParam) { + String queryColumns = StringUtils.defaultIfBlank(dataViewParam.getRetainColumn(), "*"); + StringBuilder sqlSb = new StringBuilder(); + sqlSb.append(String.format("select %s from %s.%s", queryColumns, "`" + dataViewParam.getDbName() + "`", dataViewParam.getTableName())); + if (StringUtils.isNotBlank(dataViewParam.getCondition())) { + sqlSb.append(String.format(" where %s", dataViewParam.getCondition())); + } + if (StringUtils.isNotBlank(dataViewParam.getOrderColumn()) && StringUtils.isNotBlank(dataViewParam.getOrderType())) { + sqlSb.append(String.format(" order by %s %s", dataViewParam.getOrderColumn(), dataViewParam.getOrderType())); + } + sqlSb.append(String.format(" limit %s offset %s", dataViewParam.getPageSize(), dataViewParam.getOffset())); + return sqlSb.toString(); + } - @Override - public ExecuteResult saveProcedure(Long sourceId, String dbName, String typeName, String procName, String procSql) { - String firstLine = procSql.split("\n")[0]; - // 看函数名是否被修改了,修改会导致函数名的不确定,有认知上的成本,明确的先删再建吧 - if (!firstLine.contains("`" + procName + "`(") && !firstLine.contains(" " + procName + "(") && !firstLine.contains("." + procName + "(")) { - return ExecuteResult.error("在编辑页面不允许修改函数名,如需新建或修改,请到列表页删除后再新建函数", procSql); - } - ProcedureDto procedureDetail = this.getProcedureDetail(sourceId, dbName, typeName, procName); - // 按MySQL的来是先删除再创建,如果其他数据库不是这个逻辑,需要重写本方法实现自己的逻辑 - BaseMapper baseMapper = this.getViewAuthBaseMapper(sourceId); - baseMapper.deleteProcedure(dbName, typeName, procName); - // 执行创建SQL - ExecuteParam executeParam = new ExecuteParam(); - executeParam.setDatasourceId(sourceId); - executeParam.setExecuteId(IdUtil.randomUUID()); - executeParam.setExecuteType(ExecuteType.ALL); - executeParam.setSql(procSql); - executeParam.setMaxRows(1000); - try { - return sqlExecutor.execute(executeParam); - } catch (Exception e) { - try { - // 尝试恢复函数 - executeParam.setSql(procedureDetail.getBody()); - sqlExecutor.execute(executeParam); - } catch (Exception e1) { - return ExecuteResult.error("执行和恢复函数均失败,请先备份您的SQL,以防丢失\n" + e.getMessage(), procSql); - } - return ExecuteResult.error(e.getMessage(), procSql); - } - } + @Override + public TableDdlVo getTableDdl(Long sourceId, String dbName, String tableName) { + BaseMapper baseMapper = this.getViewAuthBaseMapper(sourceId); + List> tableDdlList = baseMapper.getTableDdl(dbName, tableName); + TableDdlVo tableDdlVo = new TableDdlVo(); + tableDdlVo.setCurrent(DatabaseProductEnum.MYSQL.name().toLowerCase()); + tableDdlVo.setMysql("// 生成失败"); + tableDdlVo.setOracle("// TODO 等待大佬来实现转换"); + // TODO 将建表语句转换为其他数据库的,还不知道怎么做,先这样留着,看有没大佬来实现 + if (CollectionUtils.isNotEmpty(tableDdlList)) { + tableDdlVo.setMysql(tableDdlList.get(0).get("Create Table") + ";"); + } + return tableDdlVo; + } + + @Override + public void updateTableColumnDesc(Long sourceId, String dbName, String tableName, String columnName, String newDesc) { + BaseMapper baseMapper = this.getViewAuthBaseMapper(sourceId); + // mysql要同时修改类型默认值等,所以先查出来 + MysqlMapper mysqlMapper = databaseRegistrationBean.getBaseMapper(sourceId, MysqlMapper.class); + ColumnInfoDto columnInfo = mysqlMapper.getColumnInfo(dbName, tableName, columnName); + String isNullable = Optional.ofNullable(columnInfo.getIsNullable()).orElse(""); + columnInfo.setIsNullable("yes".equalsIgnoreCase(isNullable) ? "null" : "not null"); + String columnDefault = columnInfo.getColumnDefault(); + if (StringUtils.isNotBlank(columnDefault)) { + columnInfo.setColumnDefault("DEFAULT " + columnDefault); + } else { + columnInfo.setColumnDefault(""); + } + String extra = columnInfo.getExtra(); + columnInfo.setExtra(StringUtils.isBlank(extra) ? "" : extra); + baseMapper.updateTableColumnDesc(dbName, tableName, columnName, newDesc, columnInfo); + } + + @Override + public ProcedureDto getProcedureDetail(Long sourceId, String dbName, String typeName, String procName) { + BaseMapper baseMapper = this.getViewAuthBaseMapper(sourceId); + ProcedureDto procedureDetail = baseMapper.getProcedureDetail(dbName, typeName, procName); + if (procedureDetail == null) { + // 新建的时候 + ProcedureDto procedureDetailNew = new ProcedureDto(); + if (Objects.equals(typeName, "FUNCTION")) { + procedureDetailNew.setBody("CREATE DEFINER = CURRENT_USER " + typeName + " `" + dbName + "`.`" + procName + "`() RETURNS integer\n" + + "BEGIN\n" + + "\t#Routine body goes here...\n" + + "\tRETURN 0;\n" + + "END;"); + } else { + procedureDetailNew.setBody("CREATE DEFINER = CURRENT_USER " + typeName + " `" + dbName + "`.`" + procName + "`()\n" + + "BEGIN\n" + + "\t#Routine body goes here...\n" + + "END;"); + } + procedureDetailNew.setDb(dbName); + procedureDetailNew.setDefiner("CURRENT_USER"); + procedureDetailNew.setType(typeName); + return procedureDetailNew; + } + // 组装好SQL + String type = procedureDetail.getType(); + String name = procedureDetail.getName(); + String db = procedureDetail.getDb(); + String paramList = StringUtils.defaultIfBlank(procedureDetail.getParamList(), ""); + String[] definerArr = procedureDetail.getDefiner().split("@"); + String createStr = String.format("CREATE DEFINER=`%s`@`%s` %s `%s`.`%s`(%s)", definerArr[0], definerArr[1], type, db, name, paramList); + if (Objects.equals(procedureDetail.getType(), "FUNCTION")) { + createStr += " RETURNS " + procedureDetail.getReturns(); + } + procedureDetail.setBody(createStr + "\r\n" + procedureDetail.getBody()); + return procedureDetail; + } + + @Override + public ExecuteResult saveProcedure(Long sourceId, String dbName, String typeName, String procName, String procSql) { + String firstLine = procSql.split("\n")[0]; + // 看函数名是否被修改了,修改会导致函数名的不确定,有认知上的成本,明确的先删再建吧 + if (!firstLine.contains("`" + procName + "`(") && !firstLine.contains(" " + procName + "(") && !firstLine.contains("." + procName + "(")) { + return ExecuteResult.error("在编辑页面不允许修改函数名,如需新建或修改,请到列表页删除后再新建函数", procSql); + } + ProcedureDto procedureDetail = this.getProcedureDetail(sourceId, dbName, typeName, procName); + // 按MySQL的来是先删除再创建,如果其他数据库不是这个逻辑,需要重写本方法实现自己的逻辑 + BaseMapper baseMapper = this.getViewAuthBaseMapper(sourceId); + baseMapper.deleteProcedure(dbName, typeName, procName); + // 执行创建SQL + ExecuteParam executeParam = new ExecuteParam(); + executeParam.setDatasourceId(sourceId); + executeParam.setExecuteId(IdUtil.randomUUID()); + executeParam.setExecuteType(ExecuteType.ALL); + executeParam.setSql(procSql); + executeParam.setMaxRows(1000); + try { + return sqlExecutor.execute(executeParam); + } catch (Exception e) { + try { + // 尝试恢复函数 + executeParam.setSql(procedureDetail.getBody()); + sqlExecutor.execute(executeParam); + } catch (Exception e1) { + return ExecuteResult.error("执行和恢复函数均失败,请先备份您的SQL,以防丢失\n" + e.getMessage(), procSql); + } + return ExecuteResult.error(e.getMessage(), procSql); + } + } } diff --git a/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/service/database/OracleServiceImpl.java b/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/service/database/OracleServiceImpl.java index 2c2fefc7..3b1ee6ec 100644 --- a/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/service/database/OracleServiceImpl.java +++ b/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/service/database/OracleServiceImpl.java @@ -1,6 +1,8 @@ package com.zyplayer.doc.db.service.database; +import com.zyplayer.doc.db.controller.param.DataViewParam; import com.zyplayer.doc.db.framework.db.enums.DatabaseProductEnum; +import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; /** @@ -12,18 +14,42 @@ import org.springframework.stereotype.Service; @Service public class OracleServiceImpl extends DbBaseService { - @Override - public DatabaseProductEnum getDatabaseProduct() { - return DatabaseProductEnum.ORACLE; - } + @Override + public DatabaseProductEnum getDatabaseProduct() { + return DatabaseProductEnum.ORACLE; + } - /** - * oracle数据库中没有也不需要use语句,指定数据库名的情况下直接返回空即可 - * @author diantu - * @since 2023年1月16日 - */ - @Override - public String getUseDbSql(String dbName) { - return null; - } + /** + * oracle数据库中没有也不需要use语句,指定数据库名的情况下直接返回空即可 + * @author diantu + * @since 2023年1月16日 + */ + @Override + public String getUseDbSql(String dbName) { + return null; + } + + /** + * 获取分页查询的SQL(oracle分页) + * + * @author diantu + * @since 2023年1月17日 + */ + @Override + public String getQueryPageSql(DataViewParam dataViewParam) { + String queryColumns = StringUtils.defaultIfBlank(dataViewParam.getRetainColumn(), "*"); + StringBuilder sqlSb = new StringBuilder(); + sqlSb.append(String.format("select %s from %s.%s", queryColumns, dataViewParam.getDbName(), dataViewParam.getTableName())); + if (StringUtils.isNotBlank(dataViewParam.getCondition())) { + sqlSb.append(String.format(" where %s", dataViewParam.getCondition())); + } + if (StringUtils.isNotBlank(dataViewParam.getOrderColumn()) && StringUtils.isNotBlank(dataViewParam.getOrderType())) { + sqlSb.append(String.format(" order by %s %s", dataViewParam.getOrderColumn(), dataViewParam.getOrderType())); + } + StringBuilder sqlSbFinal = new StringBuilder(); + Integer pageSize = dataViewParam.getPageSize() * dataViewParam.getPageNum(); + Integer offsetSize = dataViewParam.getPageSize() * (dataViewParam.getPageNum() - 1) + 1; + sqlSbFinal.append(String.format("select * from ( select %s from %s", queryColumns + ",rownum rn", "(" + sqlSb + ") where rownum<=" + pageSize + " ) t2 where t2.rn >=" + offsetSize)); + return sqlSbFinal.toString(); + } }