修复sql执行器页面取消执行未能正确运行的问题

sse推送模块已知问题修复
This commit is contained in:
diant
2023-07-19 15:07:59 +08:00
parent d27c2b57d1
commit 931a71c54f
13 changed files with 9723 additions and 10622 deletions

View File

@@ -121,7 +121,8 @@ public class DbSqlExecutorController {
return DocDbResponseJson.warn("单次执行最多支持20条语句同时执行当前语句条数" + analysisQuerySqlList.size());
}
List<ColumnExecuteResult> resultList = new LinkedList<>();
for (Map<String, Object> map : analysisQuerySqlList) {
for (int i = 0; i < analysisQuerySqlList.size(); i++) {
Map<String, Object> map = analysisQuerySqlList.get(i);
ColumnExecuteResult executeResult;
ColumnExecuteResult executeCountResult;
//原始sql
@@ -140,6 +141,10 @@ public class DbSqlExecutorController {
if(map.get("sqlType").equals("select")){
if(StrUtil.equals(type,"noPage")){
executeParam = SqlParseUtil.getSingleExecuteParam(executeParam,originalSql, paramMap);
//设置最后一次标志
if(i==analysisQuerySqlList.size()-1){
executeParam.setIsLastTime(true);
}
executeResult = columnSqlExecutor.execute(executeParam);
resultList.add(executeResult);
continue;
@@ -153,6 +158,10 @@ public class DbSqlExecutorController {
if(data!=null){
count = Long.parseLong(data.get(0).get(0)+"");
}
//设置最后一次标志
if(i==analysisQuerySqlList.size()-1){
executeParam.setIsLastTime(true);
}
//总数据量大于1000进行分页
if(count>1000){
String pageSql = dbBaseService.getQueryPageSqlBySql(originalSql,pageSize,pageNum);

View File

@@ -2,8 +2,12 @@ package com.zyplayer.doc.db.framework.db.mapper.base;
import cn.hutool.core.io.IoUtil;
import com.alibaba.druid.pool.DruidPooledConnection;
import com.zyplayer.doc.data.config.security.DocUserDetails;
import com.zyplayer.doc.data.config.security.DocUserUtil;
import com.zyplayer.doc.db.framework.db.bean.DatabaseFactoryBean;
import com.zyplayer.doc.db.framework.db.bean.DatabaseRegistrationBean;
import com.zyplayer.doc.db.framework.sse.service.DbSseEmitterService;
import com.zyplayer.doc.db.framework.sse.util.DbSseCacheUtil;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.mapping.ParameterMapping;
@@ -32,6 +36,9 @@ public class ColumnSqlExecutor {
@Resource
DatabaseRegistrationBean databaseRegistrationBean;
@Resource
DbSseEmitterService dbSseEmitterService;
// 执行中的PreparedStatement信息用于强制取消执行
private static final Map<String, PreparedStatement> statementMap = new ConcurrentHashMap<>();
@@ -136,6 +143,18 @@ public class ColumnSqlExecutor {
}
// 查询的结果集
resultSet = preparedStatement.getResultSet();
//最后一次
if(Boolean.TRUE.equals(executeParam.getIsLastTime())){
//推送查询完成信息
DocUserDetails currentUser = DocUserUtil.getCurrentUser();
String loginId = currentUser.getUserId().toString();
String clientId = DbSseCacheUtil.getClientIdByLoginId(loginId);
if(clientId!=null){
dbSseEmitterService.sendMessageToOneClient(DbSseCacheUtil.getClientIdByLoginId(loginId),"1");
}
}
List<String> headerList = new LinkedList<>();
List<List<Object>> dataList = new LinkedList<>();
if (resultSet != null) {

View File

@@ -21,4 +21,5 @@ public class ExecuteParam {
private String executeId;
private String prefixSql;
private ExecuteType executeType;
private Boolean isLastTime;
}

View File

@@ -125,7 +125,9 @@ public class DbSseCacheUtil {
}
Map<String,Object> map = new ConcurrentHashMap<>();
map.put(DbSseEmitterParameterEnum.EMITTER.getValue(),emitter);
map.put(DbSseEmitterParameterEnum.FUTURE.getValue(), future);
if(future!=null){
map.put(DbSseEmitterParameterEnum.FUTURE.getValue(), future);
}
map.put(DbSseEmitterParameterEnum.LOGINID.getValue(), loginId);
sseCache.put(clientId, map);
}

View File

@@ -1 +1 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="favicon-db.png"><title>数据库文档管理</title><link href="css/chunk-vendors.be60d3b3.css" rel="preload" as="style"><link href="css/index.dd934fd5.css" rel="preload" as="style"><link href="js/chunk-vendors.7871ff07.js" rel="preload" as="script"><link href="js/index.75921495.js" rel="preload" as="script"><link href="css/chunk-vendors.be60d3b3.css" rel="stylesheet"><link href="css/index.dd934fd5.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but zyplayer-db-ui doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div><script src="js/chunk-vendors.7871ff07.js"></script><script src="js/index.75921495.js"></script></body></html>
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="favicon-db.png"><title>数据库文档管理</title><link href="css/chunk-vendors.be60d3b3.css" rel="preload" as="style"><link href="css/index.90584c9a.css" rel="preload" as="style"><link href="js/chunk-vendors.5bc10fd8.js" rel="preload" as="script"><link href="js/index.e9cb8d9c.js" rel="preload" as="script"><link href="css/chunk-vendors.be60d3b3.css" rel="stylesheet"><link href="css/index.90584c9a.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but zyplayer-db-ui doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div><script src="js/chunk-vendors.5bc10fd8.js"></script><script src="js/index.e9cb8d9c.js"></script></body></html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@@ -17,6 +17,7 @@
"core-js": "^3.3.2",
"echarts": "^4.9.0",
"element-ui": "^2.15.0",
"event-source-polyfill": "^1.0.31",
"js-cookie": "^2.2.1",
"node-sass": "4.14.1",
"pouchdb": "^7.1.1",

View File

@@ -35,6 +35,29 @@ export default {
let dataItem = dataList.find(val => val.key === subKey) || {};
return dataItem.value || '';
}
},
data: {
set(key, val) {
const _set = JSON.stringify(val)
return localStorage.setItem(key, _set)
},
get(key) {
let data = localStorage.getItem(key)
try {
data = JSON.parse(data)
} catch (err) {
return null
}
return data
},
remove(key) {
return localStorage.removeItem(key)
},
clear() {
return localStorage.clear()
}
}
}

View File

@@ -11,7 +11,10 @@
<el-button v-if="sqlExecuting" v-on:click="cancelExecutorSql" type="primary" plain size="mini"
icon="el-icon-video-pause">取消执行
</el-button>
<el-tooltip v-else effect="dark" content="Ctrl+R、Ctrl+Enter" placement="top">
<el-button v-if="dataLoading" type="primary" plain size="mini"
:loading="dataLoading">查询完成,数据加载中
</el-button>
<el-tooltip v-if="!sqlExecuting&&!dataLoading" effect="dark" content="Ctrl+R、Ctrl+Enter" placement="top">
<el-button v-on:click="doExecutorSql" type="primary" plain size="mini"
icon="el-icon-video-play">{{ executeButtonText }}
</el-button>
@@ -200,6 +203,8 @@ import aceEditor from "../../common/lib/ace-editor";
import sqlParser from "./parser/SqlParser";
import Clickoutside from 'element-ui/src/utils/clickoutside';
import { throttle, debounce } from '@/common/utils/throttleDebounce.js'
import { EventSourcePolyfill } from "event-source-polyfill";
import storageUtil from "../../common/lib/zyplayer/storageUtil";
export default {
directives: {Clickoutside},
@@ -241,6 +246,7 @@ export default {
currentPage: 1,
sqlExecuting: false,
dataLoading: false,
executeResultList: [],
executeResultInfo: "",
executeShowTable: "tabHistory",
@@ -287,6 +293,49 @@ export default {
this.loadDatasourceList();
},
methods: {
// 创建sse连接
createSseConnect() {
if (window.EventSource) {
let clientId = storageUtil.data.get("CLIENTID") ? storageUtil.data.get("CLIENTID") : "";
let url = process.env.VUE_APP_BASE_API+'/zyplayer-doc-db/doc-db/sse/createConnect?clientId='+clientId;
//heartbeatTimeout:心跳超时监测 30s
let source = new EventSourcePolyfill(url,
{withCredentials: true,heartbeatTimeout: 30000})
// 监听打开事件
source.addEventListener('open', (e) => {
//console.log("设备连接成功",e)
})
// 监听消息事件
source.addEventListener("message", (e) => {
const result = JSON.parse(e.data)
const code = result.errCode
const msg = result.errMsg
const data = result.data
if (code === 200) {
console.log("see推送消息:",data)
this.sqlExecuting = false;
this.dataLoading = true;
source.close();
} else if (code === 0) {
// 初次建立连接客户端id储存本地
storageUtil.data.set("CLIENTID", data)
console.log("客户端id:",data)
}
})
// 监听错误事件
source.addEventListener("error", (e) => {
console.log("发生错误,已断开与服务器的连接:",e)
source.close();
})
} else {
console.log("该浏览器不支持sse")
}
},
sqlExecutorInit(editor) {
this.sqlExecutorEditor = editor;
this.sqlExecutorEditor.setFontSize(16);
@@ -428,6 +477,7 @@ export default {
this.$message.error("请先选择数据库");
return;
}
this.loadingAll = true;
this.executeError = "";
this.executeUseTime = "";
@@ -445,6 +495,7 @@ export default {
sqlValue = this.sqlExecutorEditor.getValue();
}
this.sqlExecuting = true;
this.createSseConnect();
datasourceApi.queryExecuteSql({
sourceId: this.choiceDatasourceId,
dbName: this.choiceDatabase,
@@ -456,6 +507,7 @@ export default {
params: JSON.stringify(sqlParamObj),
}).then(response => {
this.sqlExecuting = false;
this.dataLoading = false;
this.loadingAll = false;
if (response.errCode != 200) {
this.executeShowTable = 'tabError';