一个html实现数据库自定义查询
使用场景
应用上线后甲方频繁的找开发查询数据库数据,且没有固定的查询规律,产品经理也没有规划报表需求。
实现方案
后端开放自定义sql查询,屏蔽所有数据库的高危操作,将常用查询的sql放在一个html中的js中直接查询,功能满足以下需求:
- 可动态设置接口地址,方便查看测试和正式数据库
- 可预设常用查询sql
- 支持cte查询,支持sql注释
- 动态表头,分页显示总条数
- 保留查询历史记录
- 预览长文本支持单机常看详情
- 最重要的,尽量简单,单页面实现,无其他依赖
效果图
实现代码
后端java接口
@Autowiredprivate JdbcTemplate jdbcTemplate;@PostMapping("/query/sql/page")@Operation(summary = "通用SQL分页查询", description = "仅允许执行SELECT语句并支持分页")public ResponseResult<PageResponse> executePagedQuery(@RequestBody SqlQueryRequest request) {String sql = request.getSql();Integer pageSize = request.getPageSize();Integer pageIndex = request.getPageIndex();try {// 校验参数if (sql == null || sql.trim().isEmpty() || !isSafeSelectSql(sql)) {return ResponseResult.fail(400, "无效的SQL语句或非SELECT查询");}if (pageSize == null || pageSize <= 0) {pageSize = 10;}if (pageIndex == null || pageIndex < 1) {pageIndex = 1;}// 构建 count SQL// 修改 executePagedQuery 方法中调用 buildCountSql 的部分:String safeSql = removeSingleLineComments(sql);String countSql = buildCountSql(safeSql);// 执行 count 查询Long total = jdbcTemplate.queryForObject(countSql, Long.class);// 添加分页条件String pagedSql = safeSql + " LIMIT " + pageSize + " OFFSET " + ((pageIndex - 1) * pageSize);// 执行分页查询List<Map<String, Object>> result = jdbcTemplate.queryForList(pagedSql);// 返回分页结果return ResponseResult.success(PageResponse.of(result, total, pageIndex, pageSize));} catch (Exception e) {log.error("执行分页SQL失败: {}", e.getMessage(), e);return ResponseResult.fail(500, "SQL执行异常:" + e.getMessage());}}// 构建 COUNT SQLprivate String buildCountSql(String originalSql) {return "SELECT COUNT(*) FROM (" + originalSql + ") AS tmp";}/*** 移除 SQL 中的单行注释(以 "--" 开头的部分)*/private String removeSingleLineComments(String sql) {if (sql == null) {return null;}// 使用正则表达式匹配 "--" 注释并移除整行return sql.replaceAll("--[^\n]*", "");}/*** 判断是否为安全的 SELECT 查询(支持 CTE)*/private boolean isSafeSelectSql(String sql) {if (sql == null || sql.trim().isEmpty()) {return false;}String trimmedSql = sql.trim().toLowerCase();// 使用正则判断是否是以 SELECT 或 WITH 开头,并且不包含危险关键词return trimmedSql.matches("(?s:^(select|with).*$)")&& !containsForbiddenKeywords(trimmedSql);}/*** 检查 SQL 是否包含非法关键字*/private boolean containsForbiddenKeywords(String sql) {List<String> forbiddenKeywords = Arrays.asList("\\b(delete|update|insert|drop|truncate|merge|exec|execute|create|alter|grant|revoke|call|load|replace|upsert|copy)\\b","into","for update");for (String pattern : forbiddenKeywords) {if (Pattern.compile(pattern, Pattern.CASE_INSENSITIVE).matcher(sql).find()) {return true;}}return false;}
为了解决跨域问题,还需要添加如下代码
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {@Overridepublic void addCorsMappings(CorsRegistry registry) {registry.addMapping("/test/**") // 允许跨域的路径.allowedOrigins("*") // 允许所有来源.allowedMethods("GET", "POST", "PUT", "OPTIONS").allowedHeaders("*") // 允许所有头部.exposedHeaders("*").allowCredentials(false) // 关闭凭据支持.maxAge(3600); // 预检请求的有效期}
}
单页面
<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"/><title>通用SQL查询页面</title><!-- 引入 Element Plus 样式 --><link rel="stylesheet" href="https://unpkg.com/element-plus/dist/index.css"/><style>body {margin: 20px;}.form-container {margin-bottom: 20px;}.table-wrapper {max-height: 500px;overflow-y: auto;}.split-container {display: flex;gap: 20px;}.left-panel {flex: 1;}.right-panel {margin-top: 1rem;width: 100px;display: flex;flex-direction: column;gap: 15px;align-items: center;}</style>
</head>
<body>
<div id="app"><!-- SQL 查询表单 --><el-card class="form-container"><el-form label-position="top" :model="form" @submit.prevent="fetchData"><div class="split-container"><!-- 左边 SQL 输入区 --><div class="left-panel"><el-form-item label="SQL语句" style="margin-bottom: 0;"><template #label>SQL语句<span style="color: red; font-size: 12px; margin-left: 10px;">(不可输入任何修改和删除相关的语句)</span><span style="color: #00d28c; font-size: 12px; margin-left: 10px;">(“--” 可以忽略单行语句,移除可添加筛选条件)</span></template><el-input v-model="form.sql" type="textarea" rows="8" placeholder="请输入SQL语句"></el-input></el-form-item></div><!-- 右边参数+按钮 --><div class="right-panel"><el-button type="primary" @click="showApiRootDialog = true" style="width: 100%;">接口地址</el-button><!-- 内置查询按钮 --><el-popover placement="left" trigger="click" width="250px"><template #reference><el-button type="primary" style="width: 100%;">内置查询</el-button></template><div><h4 style="margin-top: 0;">预设查询列表</h4><ul style="list-style: none; padding-left: 0;"><li v-for="(preset, index) in presetQueries" :key="index"><el-link @click="usePresetQuery(preset)" type="primary">{{ preset.name }}</el-link></li></ul></div></el-popover><!-- 历史按钮 --><el-button plain @click="showHistoryDialog = true" style="width: 100%;">历史查询</el-button><!-- 查询按钮 --><el-button type="success" native-type="submit" style="width: 100%;">查询</el-button></div></div></el-form></el-card><!-- 表格展示 --><el-table :data="tableData" border class="table-wrapper" v-loading="loading"><el-table-column v-for="(col, index) in columns" :key="index" :label="col"><template #default="scope"><span:title="scope.row[col]"@click="showFullContentDialog(scope.row[col])"style="display: inline-block; max-width: 300px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; cursor: pointer;">{{ scope.row[col] }}</span></template></el-table-column></el-table><!-- 查看完整内容弹窗 --><el-dialog v-model="showContentDialog" title="完整内容" width="60%"><pre style="white-space: pre-wrap; word-wrap: break-word;">{{ fullContent }}</pre></el-dialog><!-- 分页组件 --><div style="display: flex; justify-content: flex-end; align-items: center; margin-top: 20px;"><span style="margin-right: 15px; font-size: 14px;">共 {{ pageInfo.total }} 条</span><el-paginationlayout="prev, pager, next":total="pageInfo.total"v-model:current-page="form.pageIndex":page-size="form.pageSize"@current-change="handlePageChange"background/></div><!-- 接口设置弹窗 --><el-dialog v-model="showApiRootDialog" title="api设置"><el-form label-position="top"><!-- 接口地址 --><el-form-item label="后端接口地址"><el-input v-model="apiUrl" placeholder="请输入后端接口地址"></el-input></el-form-item><!-- 每页条数 + 历史缓存条数 并排布局 --><div style="display: flex; gap: 10px;"><el-form-item label="每页条数" style="flex: 1;"><el-input-number v-model="form.pageSize" :min="1" :max="100" style="width: 100%;"></el-input-number></el-form-item><el-form-item label="历史缓存条数" style="flex: 1;"><el-input-number v-model="historyCacheSize" :min="1" :max="50" style="width: 100%;"></el-input-number></el-form-item></div></el-form><template #footer><el-button @click="showApiRootDialog = false">取消</el-button><el-button type="primary" @click="saveRootPath">确定</el-button></template></el-dialog><!-- 历史记录弹窗 --><el-dialog v-model="showHistoryDialog" title="历史查询记录"><el-scrollbar style="height: 300px;"><ul style="list-style: none; padding-left: 0; margin: 0;"><li v-for="(item, index) in historyList" :key="index" style="padding: 8px 0 4px;"><el-link @click="useHistory(item)" type="primary">{{ item }}</el-link><div v-if="index < historyList.length - 1"style="border-bottom: 1px solid #eee; margin: 4px 0;"></div></li></ul></el-scrollbar><template #footer><el-button @click="clearHistory">清空历史</el-button><el-button @click="showHistoryDialog = false">关闭</el-button></template></el-dialog>
</div><!-- 引入 Vue 3 -->
<script src="https://unpkg.com/vue@3.4.15/dist/vue.global.prod.js"></script>
<!-- 引入 axios -->
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<!-- 引入 Element Plus 组件库 -->
<script src="https://unpkg.com/element-plus/dist/index.full.min.js"></script><script>const {createApp} = Vue;createApp({data() {// 预设查询const presetQueries = [{name: "设施查询", sql: " SELECT a.id AS \"设施Id\",a.name AS \"设施名称\",bt.name AS \"设施类型\",cc.CITY_NAME AS \"城市名称\",a.PROPERTIES as \"详细属性\",a.DISTRICT AS \"区县\"\n" +" FROM building a\n" +" LEFT JOIN BUILDING_TYPE bt ON a.TYPE=bt.ID\n" +" LEFT JOIN CITY_CONFIG cc ON a.city = cc.city_code\n" +" -- where bt.name = '供水厂'"},{name: "城市信息", sql: " SELECT city_code AS \"城市编码\",city_name AS \"城市名称\",DISTRICTS AS \"区县\",CITY_CONFIG.SMS_ENABLE AS \"短信开关\"\n" +" FROM city_config"},{name: "指定时间区间预警数量统计", sql: "SELECT \"LEVEL\" AS \"预警等级\" ,count(1) AS \"触发次数\"\n" +"FROM FORECAST_RAIN_LOG frl \n" +"WHERE frl.CREATE_TIME BETWEEN '2025-06-01 22:00:00.000' AND '2025-06-02 01:00:00.000' \n" +"-- AND frl.\"LEVEL\" >0\n" +"-- AND frl.RAIN_ID = 184\n" +"GROUP BY frl.LEVEL"},{name: "短信发送记录", sql: "SELECT sl.CITY_CODE AS \"城市编码\",sl.CITY_NAME AS \"城市\",TO_CHAR(sl.SEND_TIME, 'YYYY-MM-DD HH24:MI:SS') AS \"发送时间\",sl.USERNAME AS \"接收人\",sl.PHONE AS \"手机号\",sl.CONTENT AS \"短信内容\",sl.WARNING_LEVEL AS \"预警等级\"\n" +"FROM SMS_LOG sl\n" +"WHERE 1=1 \n" +"-- AND sl.CITY_NAME = '百色市' \n" +"-- AND sl.SEND_TIME BETWEEN '2025-05-01 22:00:00.000' AND '2025-06-02 01:00:00.000'\n" +"-- AND sl.USERNAME = '黄科谕'\n" +"ORDER BY sl.SEND_TIME DESC"},{name: "设施降雨预警历史记录", sql: "SELECT \n" +" b.id AS \"设施id\",b.name AS \"设施名称\",\n" +" a.val AS \"降雨量\", a.LEVEL AS \"预警等级\",\n" +" TO_CHAR(a.CREATE_TIME, 'yyyy-MM-dd HH24:mi:ss') as \"预警时间\",\n" +" cc.CITY_NAME AS \"城市\", cc.city_code AS \"城市编码\"\n" +"FROM FORECAST_RAIN_LOG a \n" +"LEFT JOIN building b ON a.RAIN_ID = b.id\n" +"LEFT JOIN CITY_CONFIG cc ON cc.city_code = b.city\n" +"WHERE a.create_time > '2025-06-01 09:30:00' \n" +" AND a.create_time < '2025-06-03 14:30:30' \n" +" AND a.level > 0\n" +" --筛选i设施\n" +" -- AND b.id = 826\n" +" --筛选预警等级\n" +" -- AND a.level = 2\n" +"ORDER BY a.CREATE_TIME ASC"},{name: "指定时间区间发生预警的设施", sql: "SELECT b.id AS \"设施id\",cc.CITY_NAME AS \"城市\",b.name AS \"设施名称\",b.PROPERTIES AS \"详细属性\"\n" +"FROM building b \n" +"LEFT JOIN CITY_CONFIG cc ON b.city = cc.CITY_CODE\n" +"WHERE b.id in (\n" +"\tSELECT DISTINCT frl.RAIN_ID FROM FORECAST_RAIN_LOG frl \n" +"WHERE frl.\"LEVEL\" >0 AND frl.CREATE_TIME BETWEEN '2025-06-01 22:00:00.000' AND '2025-06-02 01:00:00.000' \n" +")\n" +"ORDER BY CITY_NAME"},{name: "当前触发短信预警的设施", sql: "WITH three_hour_records AS (\n" +" SELECT\n" +" frl.*,\n" +" ROW_NUMBER() OVER (PARTITION BY frl.RAIN_ID ORDER BY frl.CREATE_TIME DESC) as rn\n" +" FROM FORECAST_RAIN_LOG frl\n" +" WHERE frl.DURATION = 3\n" +" -- 筛选最近3小时的数据\n" +" AND frl.CREATE_TIME >= DATEADD(HOUR, -3, SYSDATE)\n" +" )\n" +" -- 查询降雨预警>0且三小时内没发短信的设施\n" +" ,constant_alert AS (\n" +" SELECT\n" +" t.RAIN_ID\n" +" FROM three_hour_records t\n" +" -- 最新预警等级大于0\n" +" WHERE t.rn =1 and t.LEVEL > 0\n" +" -- 且三小时内没有短信记录\n" +" AND NOT EXISTS (\n" +" SELECT 1 FROM SMS_LOG s\n" +" WHERE s.SEND_TIME >= DATEADD(HOUR, -3, SYSDATE)\n" +" AND s.building_ids LIKE '%'||t.RAIN_ID||'%'\n" +" )\n" +" )\n" +" -- 检测最新预警等级大于3小时内已发短信的预警等级的设施\n" +" ,risk_increased AS (\n" +" SELECT\n" +" l1.RAIN_ID\n" +" FROM three_hour_records l1\n" +" LEFT JOIN (\n" +" SELECT \n" +" building_ids,\n" +" WARNING_LEVEL,\n" +" ROW_NUMBER() OVER (PARTITION BY building_ids ORDER BY SEND_TIME DESC) as sms_rn\n" +" FROM SMS_LOG\n" +" WHERE SEND_TIME >= DATEADD(HOUR, -3, SYSDATE)\n" +" ) s ON s.building_ids LIKE '%'||l1.RAIN_ID||'%' AND s.sms_rn = 1\n" +" WHERE l1.rn = 1\n" +" AND l1.LEVEL > s.WARNING_LEVEL\n" +" )\n" +" -- 合并两类需要发送短信的设施\n" +" SELECT\n" +" b.id, b.city AS cityCode, c.CITY_NAME AS cityName,\n" +" b.name, b.PROPERTIES,\n" +" lr.CREATE_TIME AS updatedAt,\n" +" lr.val as val,\n" +" lr.level as level\n" +" FROM building b\n" +" INNER JOIN (\n" +" \t-- 设施ID去重合并\n" +" SELECT RAIN_ID FROM risk_increased\n" +" UNION\n" +" SELECT RAIN_ID FROM constant_alert\n" +" ) combined ON b.id = combined.RAIN_ID\n" +" INNER JOIN three_hour_records lr ON b.id = lr.RAIN_ID AND lr.rn = 1\n" +" LEFT JOIN city_config c ON b.city = c.CITY_CODE\n" +" -- 只给内涝设施发送短信且城市开关打开\n" +" where b.type in (3,36) and c.sms_enable = 1"},];// 获取本地缓存的 SQL,默认为空字符串const lastSql = localStorage.getItem('lastSql') || '';// 获取默认 SQL:优先用本地缓存,否则用第一个预设 SQLconst defaultSql = lastSql || (presetQueries.length > 0 ? presetQueries[0].sql : '');return {apiUrl: localStorage.getItem('apiUrl') || 'http://192.168.10.160:9876/test/query/sql/page',form: {sql: defaultSql,pageSize: parseInt(localStorage.getItem('pageSize')) || 10,pageIndex: 1},tableData: [],columns: [],pageInfo: {total: 0,pages: 0},loading: false,presetQueries: presetQueries,// 控制弹窗showApiRootDialog: false,showHistoryDialog: false,// 历史查询historyList: JSON.parse(localStorage.getItem('historySqls') || '[]'),historyCacheSize: parseInt(localStorage.getItem('historyCacheSize')) || 10,//单元格详情fullContent: '',showContentDialog: false};},methods: {async fetchData() {this.loading = true;if (!this.apiUrl || !this.form.sql.trim()) {this.$message.warning("请填写完整的后端地址和SQL语句");this.loading = false;return;}try {const res = await axios.post(this.apiUrl, {sql: this.form.sql,pageSize: this.form.pageSize,pageIndex: this.form.pageIndex});if (res.data.code === 0 && res.data.data) {this.tableData = res.data.data.records || [];this.pageInfo.total = res.data.data.total || 0;this.pageInfo.pages = res.data.data.pages || 0;this.columns = this.tableData.length > 0 ? Object.keys(this.tableData[0]) : [];// 只有在 SQL 不同的情况下才添加历史const lastSql = localStorage.getItem('lastSql');if (this.form.sql.trim() !== (lastSql || '')) {this.addToHistory(this.form.sql);localStorage.setItem('lastSql', this.form.sql);}} else {this.$message.error(res.data.msg || '查询失败');}} catch (err) {this.$message.error('接口调用失败,请检查网络或SQL语句');console.error(err);} finally {this.loading = false;}},handlePageChange(page) {this.form.pageIndex = page;this.fetchData();},saveRootPath() {localStorage.setItem('apiUrl', this.apiUrl);localStorage.setItem('pageSize', this.form.pageSize);localStorage.setItem('historyCacheSize', this.historyCacheSize);this.showApiRootDialog = false;},useHistory(sql) {this.form.sql = sql;this.showHistoryDialog = false;this.fetchData();},showFullContentDialog(content) {this.fullContent = content;this.showContentDialog = true;},addToHistory(sql) {let index = this.historyList.indexOf(sql);if (index !== -1) {this.historyList.splice(index, 1); // 移除旧的}this.historyList.unshift(sql);// 使用 historyCacheSize 控制最大缓存条数this.historyList = this.historyList.slice(0, this.historyCacheSize);localStorage.setItem('historySqls', JSON.stringify(this.historyList));},clearHistory() {this.historyList = [];localStorage.removeItem('historySqls');},usePresetQuery(preset) {this.form.sql = preset.sql;this.fetchData(); // 可选:点击即自动查询},}}).use(ElementPlus).mount('#app');
</script>
</body>
</html>
相关文章:

一个html实现数据库自定义查询
使用场景 应用上线后甲方频繁的找开发查询数据库数据,且没有固定的查询规律,产品经理也没有规划报表需求。 实现方案 后端开放自定义sql查询,屏蔽所有数据库的高危操作,将常用查询的sql放在一个html中的js中直接查询࿰…...
OCC笔记:TopoDS_Edge上是否一定存在Geom_Curve
1. 问题 写occt代码时,访问边的几何数据,通常有以下代码,若边不为空,BRep_Tool::Curve函数是否能返回Curve的有效对象指针呢? //其他略...const TopoDS_Edge& curEdge TopoDS::Edge(edgeExp.Current()); if( cu…...
Python aiohttp 全面指南:异步HTTP客户端/服务器框架
边写代码零食不停口 盼盼麦香鸡味块 、卡乐比(Calbee)薯条三兄弟 独立小包、好时kisses多口味巧克力糖、老金磨方【黑金系列】黑芝麻丸 边写代码边贴面膜 事业美丽两不误 DR. YS 野森博士【AOUFSE/澳芙雪特证】377专研美白淡斑面膜组合 优惠劵 别光顾写…...
更新已打包好的 Spring Boot JAR 文件中的 class 文件
# 1. 解压原始 JAR unzip -q original-app.jar -d temp # 2. 替换 class 文件 cp ~/projects/new-classes/*.class temp/BOOT-INF/classes/com/example/ # 3. 保留原始清单 cp temp/META-INF/MANIFEST.MF . # 4. 重新打包 jar -cf0m new-app.jar MANIFEST.MF -C temp/ . # …...
容器(如 Docker)中,通常不建议运行多个进程或要求进程必须运行在前台
在容器(如Docker)中,通常不建议运行多个进程或要求进程必须运行在前台,这与容器的设计理念、资源管理和生命周期管理机制密切相关。以下是具体原因和深入解析: 一、容器的设计理念:单一职责原则 容器的核…...
conda管理环境指令综合(随时更新)
创建环境和删除环境 #创建环境 conda create --name envname#删除环境 conda env remove --name envname克隆环境 # 查看现有环境列表 conda env list# 执行克隆操作 conda create --name 新环境名称 --clone 原环境名称# 示例:将名为"tf2"的环境克隆…...
从Java的JDK源码中学设计模式之装饰器模式
装饰器模式是一种极具弹性的结构型设计模式,它允许我们通过组合的方式动态扩展对象功能而无需修改原有结构。本文将通过JDK源码中的实际应用和通俗易懂的代码示例,带你深入了解这一强大模式的精髓。 装饰器模式核心原理 装饰器模式的核心思想ÿ…...

鸿蒙电脑会在国内逐渐取代windows电脑吗?
点击上方关注 “终端研发部” 设为“星标”,和你一起掌握更多数据库知识 10年内应该不会 用Windows、MacOS操作系统的后果是你的个人信息可能会被美国FBI看到,但绝大多数人的信息FBI没兴趣去看 你用某家公司的电脑系统,那就得做好被某些人监视的下场,相信…...

持续领跑中国异地组网路由器市场,贝锐蒲公英再次登顶销量榜首
作为国产远程连接SaaS服务的创领者,贝锐持续引领行业发展,旗下贝锐蒲公英异地组网路由器,凭借出色的技术实力和市场表现,斩获2024年线上电商平台市场销量份额中国第一的佳绩,充分彰显了其在网络解决方案与异地组网领域…...

Spring AI 系列3: Promt提示词
一、Promt提示词 Promt提示是引导 AI 模型生成特定输出的输入, 提示的设计和措辞会显著影响模型的响应。 在 Spring AI 中与 AI 模型交互的最低层级,处理提示有点类似于在 Spring MVC 中管理”视图”。 这涉及创建带有动态内容占位符的大段文本。 这些占…...
Nginx 的配置文件
核心概念: 指令 (Directives): 配置文件的基本构建块。每条指令以分号 ; 结束。指令可以设置参数(如 worker_processes auto;)。 上下文 (Contexts): 指令被组织在特定的块(用花括号 {} 包围)中,称为上下文…...

Redis:安装与常用命令
🌈 个人主页:Zfox_ 🔥 系列专栏:Redis 🔥 安装 Redis 使⽤apt安装 apt install redis -y⽀持远程连接 修改 /etc/redis/redis.conf 修改 bind 127.0.0.1 为 bind 0.0.0.0 修改 protected-mode yes 为 protected-mo…...
[原创](Windows使用技巧): Windwos11如何设置局域网共享访问? (多图详解)
[作者] 常用网名: 猪头三 出生日期: 1981.XX.XX 企鹅交流: 643439947 个人网站: 80x86汇编小站 编程生涯: 2001年~至今[共24年] 职业生涯: 22年 开发语言: C/C++、80x86ASM、Object Pascal、Objective-C、C#、R、Python、PHP、Perl、 开发工具: Visual Studio、Delphi、XCode、…...

Mac 芯片系列 安装cocoapod 教程
安装声明: 本人是在搭梯子的环境下安装成功,前提是必须安装好安装homebrew环境。 1.检测rudy的源 2.查看源(目的:检测rudy的源) gem sources - l 3.移除源(目的:移除rudy自带的源) gem sources --remove https://rubygems.org/ 4.更换源(目的:替换成国…...

智启未来:AI重构制造业供应链的五大革命性突破
一、需求预测:让供应链“未卜先知” 1.1 从经验判断到数据预言 传统供应链依赖人工分析历史数据,但面对市场波动、设备突发故障等不确定性,往往反应滞后。AI通过整合工业物联网(IIoT)传感器数据、生产排程、供应商交…...

Linux进程间通信----简易进程池实现
进程池的模拟实现 1.进程池的原理: 是什么 进程池是一种多进程编程模式,核心思想是先创建好一定数量的子进程用作当作资源,这些进程可以帮助完成任务并且重复利用,避免频繁的进程的创建和销毁的开销。 下面我们举例子来帮助理…...

解锁Java多级缓存:性能飞升的秘密武器
一、引言 文末有彩蛋 在当今高并发、低延迟的应用场景中,传统的单级缓存策略往往难以满足性能需求。随着系统规模扩大,数据访问的瓶颈逐渐显现,如何高效管理缓存成为开发者面临的重大挑战。多级缓存架构应运而生,通过分层缓存设…...

(纳芯微)NCA9548- DTSXR 具有复位功能的八通道 I²C 开关、所有I/O端子均可承受5.5V输入电压
深圳市润泽芯电子有限公司 推荐NOVOSENSE(纳芯微)品牌 NCA9548- DTSXR TSSOP-24封装 NCA9548- DTSXR 具有复位功能的八通道 IC 开关、所有I/O端子均可承受5.5V输入电压 产品描述 NCA9548是通过I2C总线控制的八路双向转换开关。 SCL / SDA上行数据分散到八对下行数据或通道。…...

013旅游网站设计技术详解:打造一站式旅游服务平台
旅游网站设计技术详解:打造一站式旅游服务平台 在互联网与旅游业深度融合的时代,旅游网站成为人们规划行程、预订服务的重要工具。一个功能完备的旅游网站,通过用户管理、订单管理等核心模块,实现用户与管理员的高效交互。本文将…...

2024 CKA模拟系统制作 | Step-By-Step | 12、题目搭建-创建多容器Pod
目录 免费获取题库配套 CKA_v1.31_模拟系统 一、题目 二、考点分析 1. 多容器 Pod 的理解 2. YAML 配置规范 3. 镜像版本控制 三、考点详细讲解 1. 多容器 Pod 的工作原理 2. 容器端口冲突处理 3. 资源隔离机制 四、实验环境搭建步骤 总结 免费获取题库配套 CKA_v…...

优化 Spring Boot API 性能:利用 GZIP 压缩处理大型有效载荷
引言 在构建需要处理和传输大量数据的API服务时,响应时间是一个关键的性能指标。一个常见的场景是,即使后端逻辑和数据库查询已得到充分优化,当API端点返回大型数据集(例如,数千条记录的列表)时࿰…...
PostgreSQL 修改表结构卡住不动
[] 查找卡住的进程 ID(PID) -- 查看当前所有数据库连接及进程信息 SELECTpid,usename,query,age(clock_timestamp(), query_start) AS query_duration FROMpg_stat_activity WHEREquery LIKE %ALTER TABLE%; -- 过滤出正在执行 ALTER TABLE 的语句今天遇…...

【C盘瘦身】给DevEco Studio中HarmonyOSEmulator(鸿蒙模拟器)换个地方,一键移动给C盘瘦身
文章目录 一、HarmonyOSEmulator的安装路径二、修改路径 一、HarmonyOSEmulator的安装路径 之前安装了华为的DevEco Studio,当时没注意,后来C盘告急,想着估计是鸿蒙的模拟器占用空间比较大,一检查还真是躺在C盘。路径如下&#x…...
AutoCompose - 携程自动编排【开源】
AutoCompose - 携程自动编排【开源】 AutoCompose是一款单事件驱动(无状态)的流程引擎。使用本框架,能够轻松实现复杂服务的自动化编排【零配置、零编码】,能够显著提高开发维护效率。支持同步编程、异步编程(已支持Co…...
mybatis和hibernate区别
MyBatis 和 Hibernate 都是 Java 生态中主流的持久层框架,但设计理念和适用场景有显著区别。以下是核心对比: 1. 本质区别 特性HibernateMyBatis框架类型全自动 ORM(对象关系映射)框架半自动 SQL 映射框架核心思想对象优先&#…...

ORACLE 缺失 OracleDBConsoleorcl服务导致https://xxx:port/em 不能访问
这个原因是,操作过一下 ORCL的服务配置变更导致的。 再PATH中添加个环境变量,路径如下 管理员权限运行cmd 等待创建完成 大概3分钟 查看服务 点击第一个访问,下图登录后的截图...
unix/linux source 命令,其历史争议、兼容性、生态、未来展望
现在把目光投向unix/linux source命令的历史争议、兼容性、生态和未来展望,这能让我们更全面地理解一个技术点在更广阔的图景中所处的位置。 一、历史争议与设计权衡 虽然 source (或 .) 命令功能强大且不可或缺,但在其发展和使用过程中,也存在一些微妙的争议或设计上的权衡…...
day42 简单CNN
目录 一、从图像分类任务谈起 二、CNN架构解剖实验室 2.1 卷积层:空间特征的魔法师 2.2 归一化层:加速收敛的隐形推手 2.3 激活函数:非线性的灵魂 三、工程实践避坑指南 3.1 数据增强工程 3.2 调度器工程实战 四、典型问题排查手册 …...

VScode自动添加指定内容
在 VS Code 中,可以通过配置 用户代码片段(User Snippets) 或使用 文件模板扩展 来实现新建指定文件类型时自动添加指定内容。以下是具体方法: 方法 1:使用 VS Code 内置的「用户代码片段」 适用场景:适用…...

Ubuntu 22.04 安装 Nacos 记录
Ubuntu 22.04 安装 Nacos 记录 本文记录了在 Ubuntu 22.04 系统上安装 Nacos 的完整过程,适用于本地测试或生产部署的基础搭建。 一、官方资源 官网下载地址:https://nacos.io/download/nacos-server/官网文档:https://nacos.io/docs/lates…...