OJ判题系统第6期之判题逻辑开发——设计思路、实现步骤、代码实现(策略模式)

在看这期之前,建议先看前五期:

Java 原生实现代码沙箱(OJ判题系统第1期)——设计思路、实现步骤、代码实现-CSDN博客

Java 原生实现代码沙箱之Java 程序安全控制(OJ判题系统第2期)——设计思路、实现步骤、代码实现-CSDN博客

Java 原生实现代码沙箱之代码沙箱 Docker 实现(OJ判题系统第3期)——设计思路、实现步骤、代码实现-CSDN博客

OJ判题系统第4期之判题机模块架构——设计思路、实现步骤、代码实现(工厂模式、代理模式的实践)-CSDN博客 

OJ判题系统第5期之判题服务开发——设计思路、实现步骤、代码实现-CSDN博客 

判题逻辑的主要指责

定义

  • 判题逻辑 是具体判断用户提交的代码是否正确的核心算法或规则集。它专注于解析沙箱返回的结果,并根据预定义的标准(如测试用例、时间限制、内存限制等)判断代码的正确性。
  • 这是一个低层次的模块,主要关注具体的判题细节。

主要职责

  1. 解析沙箱输出:从沙箱返回的结果中提取关键信息(如输出、错误信息、耗时、内存占用等)。
  2. 比对测试用例:将沙箱的输出与题目提供的标准答案进行比对,判断每个测试用例是否通过。
  3. 生成判题报告:根据比对结果生成详细的判题报告(如哪些测试用例通过了,哪些失败了,失败的原因是什么)。
  4. 性能评估:根据资源消耗情况(如时间、内存)评估代码的效率。

策略模式优化

什么是策略模式(Strategy Pattern)?

策略模式是一种行为型设计模式,它定义了一系列算法或策略,并将每一个算法封装起来,使它们可以互相替换,独立于使用它们的客户端。

简单理解:

  • 把不同的“处理方式”封装成一个个独立的类。
  • 客户端在运行时决定使用哪一种策略。
  • 这样可以让程序更灵活、更易扩展、更易维护。

问题背景:判题逻辑复杂,存在多种判断方式 

在你的在线判题系统中,可能会遇到以下几种情况:

情况描述
Java 执行较慢Java 程序启动沙箱需要额外耗时(如 10 秒),总执行时间不能只看用户代码运行时间
Python 内存限制宽松不同语言对内存的消耗不同,判题标准也要变化
C++ 要求输出完全一致对输出格式要求严格,必须完全匹配才算通过
时间/内存限制动态调整根据题目难度、语言类型等自动调整阈值

❌ 如果不用策略模式,会出现什么问题?

  • 判题逻辑中会充斥大量 if...else 或 switch...case
  • 新增一个语言或规则时,要修改原有逻辑,违反开闭原则
  • 各种语言规则混在一起,可读性差,容易出错
  • 难以复用、难以测试、难以维护

解决方案:使用策略模式统一管理判题规则 

🔧 设计思路

我们将“如何根据沙箱执行结果和语言特性来判定是否通过”的逻辑抽象为一个接口,然后为每种语言提供一个具体的实现类。

这样做的好处是:

  • 每个语言的判题规则彼此隔离,互不干扰
  • 可以随时新增、修改某种语言的判题规则,不影响其他逻辑
  • 在运行时可以根据提交的语言类型动态选择对应的策略

总结一句话 

策略模式就像给系统装上了一个“可插拔的大脑”,你可以根据不同情况(比如语言类型)自动选择最合适的判题规则,而无需改动主流程代码。

策略模式的优势总结 

优势描述
✅ 解耦将判题逻辑与业务流程分离
✅ 易扩展新增语言只需添加策略类,符合开闭原则
✅ 易维护每种语言的规则独立,便于阅读和调试
✅ 动态切换支持运行时根据条件选择不同策略
✅ 清晰结构每个策略职责单一,符合单一职责原则

 实现步骤

定义判题策略接口,让代码更加通用化:

/*** 判题策略*/
public interface JudgeStrategy {/*** 执行判题* @param judgeContext* @return*/JudgeInfo doJudge(JudgeContext judgeContext);
}

定义判题上下文对象,用于定义在策略中传递的参数(可以理解为一种 DTO):

/*** 上下文类(Context Class)** JudgeContext 用于封装和传递在不同判题策略中需要用到的所有参数。* 它作为数据容器,确保各个判题策略能够访问到所需的信息,而不必直接依赖外部对象。*/
@Data // Lombok 注解,自动生成 getter 和 setter 方法
public class JudgeContext {/*** 沙箱执行结果信息** 包含了用户提交代码在沙箱中运行时的各项指标,如耗时、内存占用等。* 这些信息对于判断代码的正确性和性能至关重要。*/private JudgeInfo judgeInfo;/*** 测试用例输入列表** 包含了题目定义的所有测试用例的输入数据。* 在判题过程中,这些输入将被传入用户提交的代码,并与输出结果进行比对。*/private List<String> inputList;/*** 用户代码的实际输出列表** 当用户提交的代码在沙箱中运行时,根据不同的测试用例输入,会生成相应的输出结果。* 这些输出结果会被收集起来,用于后续的比对和判断。*/private List<String> outputList;/*** 题目定义的标准测试用例列表** 每个标准测试用例包含了输入和期望的输出。* 判题逻辑需要将用户的实际输出与这些期望输出进行比对,以确定是否通过该测试用例。*/private List<JudgeCase> judgeCaseList;/*** 当前题目对象** 包含了题目的所有相关信息,如题目描述、难度等级、附加说明等。* 虽然在大多数情况下,具体的判题逻辑可能不会直接使用这些信息,但它们可能会在某些特定场景下有用。*/private Question question;/*** 用户提交记录对象** 包含了用户提交的详细信息,如提交时间、编程语言、用户代码等。* 这些信息对于跟踪和记录用户的提交历史非常重要。*/private QuestionSubmit questionSubmit;
}

实现默认判题策略

DefaultJudgeStrategy.java

/*** 默认判题策略实现类** 该策略用于处理通用语言(如 C++、JavaScript 等)的标准判题逻辑。* 包括:* - 判断输出数量是否匹配* - 判断每个测试用例的输出是否与预期一致* - 检查内存和时间是否超出题目限制*/
public class DefaultJudgeStrategy implements JudgeStrategy {/*** 执行判题逻辑的核心方法** @param judgeContext 判题上下文对象,包含所有需要的数据* @return 返回最终的判题结果信息(是否通过、错误类型、耗时、内存等)*/@Overridepublic JudgeInfo doJudge(JudgeContext judgeContext) {

从上下文中提取关键数据

        // 从上下文中获取沙箱返回的执行信息(如时间、内存)JudgeInfo judgeInfo = judgeContext.getJudgeInfo();Long memory = judgeInfo.getMemory();   // 用户程序使用的内存大小(单位:字节)Long time = judgeInfo.getTime();       // 用户程序运行的时间(单位:毫秒)// 获取输入列表和输出列表List<String> inputList = judgeContext.getInputList();   // 测试用例的输入数据List<String> outputList = judgeContext.getOutputList(); // 用户程序的实际输出结果// 获取题目信息和测试用例列表Question question = judgeContext.getQuestion();                     // 当前题目对象List<JudgeCase> judgeCaseList = judgeContext.getJudgeCaseList();    // 题目定义的标准测试用例// 初始化判题结果为“接受”状态JudgeInfoMessageEnum judgeInfoMessageEnum = JudgeInfoMessageEnum.ACCEPTED;// 创建一个新的 JudgeInfo 对象用于封装最终的判题结果JudgeInfo judgeInfoResponse = new JudgeInfo();judgeInfoResponse.setMemory(memory); // 设置实际使用内存judgeInfoResponse.setTime(time);     // 设置实际运行时间

初步校验输出数量是否与输入一致

        // 如果输出数量不等于输入数量,说明至少有一个测试用例没有正确输出if (outputList.size() != inputList.size()) {// 设置为“答案错误”judgeInfoMessageEnum = JudgeInfoMessageEnum.WRONG_ANSWER;judgeInfoResponse.setMessage(judgeInfoMessageEnum.getValue());return judgeInfoResponse; // 直接返回错误结果}

举例说明:
假设题目有 3 个测试用例,但用户只输出了 2 条结果,说明至少有一个用例未通过,无需继续比对。

 逐条比对输出与预期是否一致

        // 遍历所有测试用例,检查每一条输出是否与期望输出相等for (int i = 0; i < judgeCaseList.size(); i++) {JudgeCase judgeCase = judgeCaseList.get(i); // 获取第 i 个标准测试用例String expectedOutput = judgeCase.getOutput(); // 期望输出String actualOutput = outputList.get(i);       // 实际输出// 如果两者不一致,则判定为“答案错误”if (!expectedOutput.equals(actualOutput)) {judgeInfoMessageEnum = JudgeInfoMessageEnum.WRONG_ANSWER;judgeInfoResponse.setMessage(judgeInfoMessageEnum.getValue());return judgeInfoResponse; // 只要有一个测试用例失败,就直接返回错误}}

检查是否超过题目设定的资源限制

        // 从题目对象中获取判题配置(例如内存限制、时间限制)String judgeConfigStr = question.getJudgeConfig(); // JSON 字符串格式的配置JudgeConfig judgeConfig = JSONUtil.toBean(judgeConfigStr, JudgeConfig.class);// 获取题目要求的最大内存和最大运行时间Long needMemoryLimit = judgeConfig.getMemoryLimit(); // 内存限制(单位:MB)Long needTimeLimit = judgeConfig.getTimeLimit();     // 时间限制(单位:毫秒)// 将 MB 转换为字节进行比较(注意单位一致性)if (memory > needMemoryLimit * 1024L * 1024L) { // 1 MB = 1024 KB = 1024*1024 bytesjudgeInfoMessageEnum = JudgeInfoMessageEnum.MEMORY_LIMIT_EXCEEDED;judgeInfoResponse.setMessage(judgeInfoMessageEnum.getValue());return judgeInfoResponse;}// 检查是否超时if (time > needTimeLimit) {judgeInfoMessageEnum = JudgeInfoMessageEnum.TIME_LIMIT_EXCEEDED;judgeInfoResponse.setMessage(judgeInfoMessageEnum.getValue());return judgeInfoResponse;}

全部通过,返回成功结果

        // 所有条件都满足,设置最终消息为“接受”judgeInfoResponse.setMessage(judgeInfoMessageEnum.getValue());// 返回完整的判题结果return judgeInfoResponse;}
}

总结一下这个类的职责:

步骤功能
1️⃣ 提取参数从 JudgeContext 中提取所有判题所需的信息
2️⃣ 输出数量校验判断输出数量是否与输入数量一致
3️⃣ 输出内容比对比较每个测试用例的实际输出与期望输出是否一致
4️⃣ 资源限制判断判断是否超出内存或时间限制
5️⃣ 返回结果构建并返回最终的判题结果

定义 JudgeManager

为什么要定义 JudgeManager

1. 集中管理判题逻辑

  • 问题背景: 在没有 JudgeManager 的情况下,每个地方调用判题逻辑时都需要手动判断使用哪种策略,这会导致大量的重复代码,增加维护成本。
  • 解决方案JudgeManager 将所有的判题逻辑集中管理,使得外部调用者只需传递 JudgeContext 对象即可完成判题操作,无需关心具体的实现细节。

2. 提高代码的可维护性和扩展性

  • 问题背景: 如果未来需要支持更多的编程语言或引入新的判题规则,直接修改现有代码容易引发潜在的风险。
  • 解决方案: 使用 JudgeManager 和策略模式,可以轻松地添加新的策略类而不需要修改原有代码,符合开闭原则(对扩展开放,对修改封闭)。

3. 简化客户端调用

  • 问题背景: 客户端代码如果直接与各种判题策略打交道,会显得非常复杂且不易于理解。
  • 解决方案JudgeManager 提供了一个统一的接口,客户端只需要知道如何构建 JudgeContext 并调用 doJudge 方法,极大地简化了调用过程。

4. 增强系统的灵活性

  • 问题背景: 不同编程语言可能有不同的运行环境要求(如启动时间、内存限制等),这些差异需要在判题时特别处理。
  • 解决方案JudgeManager 可以根据编程语言动态选择最适合的判题策略,确保每种语言都能得到公平准确的评判。
/*** 判题管理器** JudgeManager 是整个判题系统的核心组件之一,负责根据用户提交的编程语言,* 动态选择并调用相应的判题策略(JudgeStrategy)。这有助于将复杂的判题逻辑* 进行模块化封装,便于后续维护和扩展。*/
@Service // Spring 注解,标识该类为一个服务层组件
public class JudgeManager {/*** 执行判题操作** 该方法接收一个包含所有必要信息的上下文对象(JudgeContext),* 根据用户提交的编程语言动态选择合适的判题策略,并返回最终的判题结果。** @param judgeContext 包含了题目、用户提交、沙箱执行结果等信息的对象* @return 判题结果信息(如是否通过、错误类型、耗时、内存等)*/public JudgeInfo doJudge(JudgeContext judgeContext) {// 从上下文中获取用户提交的信息QuestionSubmit questionSubmit = judgeContext.getQuestionSubmit();// 获取用户提交的编程语言类型String language = questionSubmit.getLanguage();// 初始化默认的判题策略JudgeStrategy judgeStrategy = new DefaultJudgeStrategy();// 根据编程语言选择不同的判题策略if ("java".equals(language)) {judgeStrategy = new JavaLanguageJudgeStrategy(); // Java 特有的判题策略}// 调用选定的策略执行判题操作return judgeStrategy.doJudge(judgeContext);}
}

执行判题:

整体流程图

用户点击提交按钮
│
├─→ 校验编程语言是否合法
│
├─→ 校验题目是否存在
│
├─→ 构造提交记录对象(包含代码、语言、用户ID、题目ID)
│
├─→ 插入数据库,设置初始状态为 WAITING
│
├─→ 获取提交记录 ID
│
├─→ 异步调用 judgeService.doJudge(questionSubmitId)
│
└─→ 返回 questionSubmitId 给前端

具体实现

方法签名与基本说明

/*** 提交题目** 用户提交代码进行判题的核心方法。* 主要流程包括:* 1. 参数校验(语言合法性、题目是否存在)* 2. 构建提交记录对象并保存到数据库* 3. 异步调用判题服务进行判题** @param questionSubmitAddRequest 提交请求参数封装类* @param loginUser 当前登录用户信息* @return 返回提交记录的 ID,用于后续查询判题结果*/
@Override
public long doQuestionSubmit(QuestionSubmitAddRequest questionSubmitAddRequest, User loginUser) {

获取并校验编程语言是否合法

    // 从请求中获取用户提交的编程语言String language = questionSubmitAddRequest.getLanguage();// 使用枚举工具类判断该语言是否在支持的语言列表中QuestionSubmitLanguageEnum languageEnum = QuestionSubmitLanguageEnum.getEnumByValue(language);// 如果语言不合法,抛出异常if (languageEnum == null) {throw new BusinessException(ErrorCode.PARAMS_ERROR, "编程语言错误");}

为什么需要这一步?

  • 防止用户输入非法或不受支持的编程语言(如 Python3、PHP 等非白名单语言)。
  • 增强系统安全性,避免后续处理出现不可控问题。

检查题目是否存在

    // 获取题目 IDlong questionId = questionSubmitAddRequest.getQuestionId();// 查询题目实体是否存在Question question = questionService.getById(questionId);if (question == null) {throw new BusinessException(ErrorCode.NOT_FOUND_ERROR);}

为什么需要这一步?

  • 确保用户提交的是一个真实存在的题目,防止攻击者通过伪造 ID 操作不存在的数据。
  • 同时也为后续判题逻辑提供必要的题目信息(如测试用例、限制条件等)。

 构造提交记录对象,并设置默认状态

    // 获取当前用户的 IDlong userId = loginUser.getId();// 创建一个新的提交记录对象QuestionSubmit questionSubmit = new QuestionSubmit();questionSubmit.setUserId(userId);               // 设置用户 IDquestionSubmit.setQuestionId(questionId);       // 设置题目 IDquestionSubmit.setCode(questionSubmitAddRequest.getCode()); // 设置用户提交的代码内容questionSubmit.setLanguage(language);           // 设置编程语言// 设置初始状态为“等待中”questionSubmit.setStatus(QuestionSubmitStatusEnum.WAITING.getValue());// 初始 judgeInfo 字段为空 JSON,表示还未判题questionSubmit.setJudgeInfo("{}");

为什么设置初始状态?

  • 表示当前提交正在排队等待判题,前端或其他模块可以根据此状态判断是否已开始执行。
  • 判题完成后会异步更新状态为“成功”或“失败”。

将提交记录保存到数据库 

    // 尝试将提交记录插入数据库boolean save = this.save(questionSubmit);if (!save){throw new BusinessException(ErrorCode.SYSTEM_ERROR, "数据插入失败");}

为什么需要持久化?

  • 记录每一次提交的历史,便于后续查询、统计、审计。
  • 即使系统重启或发生异常,也可以根据数据库恢复状态。

获取提交记录 ID 并异步触发判题服务

    // 获取刚刚插入的提交记录 IDLong questionSubmitId = questionSubmit.getId();// 异步执行判题逻辑,避免阻塞主线程CompletableFuture.runAsync(() -> {judgeService.doJudge(questionSubmitId);});

为什么要异步执行?

  • 判题是一个耗时操作(可能涉及启动沙箱、运行代码、比对输出等),如果同步执行会影响接口响应速度。
  • 使用 CompletableFuture 实现异步处理,提高系统吞吐量和用户体验。

 返回提交记录 ID

    // 返回提交记录 ID,供前端或其他服务使用return questionSubmitId;
}

这个 ID 的用途是什么?

  • 前端可以通过这个 ID 轮询或 WebSocket 监听判题结果。
  • 判题服务也依赖这个 ID 来查找对应的提交记录和题目信息。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/83048.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

行业趋势与技术创新:驾驭工业元宇宙与绿色智能制造

引言 制造业发展的新格局&#xff1a;创新势在必行 当今制造业正经历深刻变革&#xff0c;面临着供应链波动、个性化需求增长、可持续发展压力以及技能人才短缺等多重挑战。在这样的背景下&#xff0c;技术创新不再是可有可无的选项&#xff0c;而是企业保持竞争力、实现可持…

高效Python开发:uv包管理器全面解析

目录 uv简介亮点与 pip、pip-tools、pipx、poetry、pyenv、virtualenv 对比 安装uv快速开始uv安装pythonuv运行脚本运行无依赖的脚本运行有依赖的脚本创建带元数据的 Python 脚本使用 shebang 创建可执行文件使用其他package indexes锁定依赖提高可复现性指定不同的 Python 版本…

鸿蒙OSUniApp开发富文本编辑器组件#三方框架 #Uniapp

使用UniApp开发富文本编辑器组件 富文本编辑在各类应用中非常常见&#xff0c;无论是内容创作平台还是社交软件&#xff0c;都需要提供良好的富文本编辑体验。本文记录了我使用UniApp开发一个跨平台富文本编辑器组件的过程&#xff0c;希望对有类似需求的开发者有所启发。 背景…

字符串检索算法:KMP和Trie树

目录 1.引言 2.KMP算法 3.Trie树 3.1.简介 3.2.Trie树的应用场景 3.3.复杂度分析 3.4.Trie 树的优缺点 3.5.示例 1.引言 字符串匹配&#xff0c;给定一个主串 S 和一个模式串 P&#xff0c;判断 P 是否是 S 的子串&#xff0c;即找到 P 在 S 中第一次出现的位置。暴力匹…

计算机组成原理:I/O

计算机组成:I/O I/O概述I/O系统构成I/O接口I/O端口两种编址区分I/O数据传送控制方式程序查询方式独占查询中断控制方式硬件判优法(向量中断法)多重中断嵌套DMA控制方式三种DMA方式DMA操作步骤内部异常和中断异常和中断的关系I/O概述 I/O系统构成 一个最基础I/O系统的构成:CPU…

ssti模板注入学习

ssti模板注入原理 ssti模板注入是一种基于服务器的模板引擎的特性和漏洞产生的一种漏洞&#xff0c;通过将而已代码注入模板中实现的服务器的攻击 模板引擎 为什么要有模板引擎 在web开发中&#xff0c;为了使用户界面与业务数据&#xff08;内容&#xff09;分离而产生的&…

NVMe简介2

共分2部分&#xff0c;这里是第2部分。 NVMe数据结构 NVMe协议中规定每个提交命令的大小为64字节&#xff0c;完成命令大小为16字节&#xff0c;NVMe命令分为Admin和IO两类&#xff0c;NVMe的数据块组织方式有PRP和SGL两种。提交命令的格式如图5所示。 图5 提交命令数据格 N…

高压启动电路--学习记录

常见反激的启动电路 优点&#xff1a;电路设计简单&#xff0c;价格便宜 缺点&#xff1a;损坏大&#xff0c;输入宽范围的时候&#xff0c;为了保证低压能正常启动&#xff0c;启动电阻阻值需要选小&#xff0c;那么高压时损耗会非常大&#xff0c;设计的不好很容易在高压时损…

VS打印printf、cout或者Qt的qDebug等传出的打印信息

在vs中打印printf、cout或者Qt的qDebug等常见的打印信息有时也是必要的&#xff0c;简单的叙述一下过程&#xff1a; 1、在vs中打开你的解决方案。 2、鼠标移动到你的项目名称上&#xff0c;点击鼠标右键&#xff0c;再点击属性&#xff0c;此刻会此项目的属性页。 3、在配置…

苍穹外卖--新增菜品

1.需求分析和设计 产品原型 业务规则&#xff1a; 菜品名称必须是唯一的 菜品必须属于某个分类下&#xff0c;不能单独存在 新增菜品时可以根据情况选择菜品的口味 每个菜品必须对应一张图片 接口设计&#xff1a; 根据类型查询分类(已完成) 文件上传 新增菜品 根据类型…

如何高效集成MySQL数据到金蝶云星空

MySQL数据集成到金蝶云星空&#xff1a;SC采购入库-深圳天一-OK案例分享 在企业信息化建设中&#xff0c;数据的高效流转和准确对接是实现业务流程自动化的关键。本文将聚焦于一个具体的系统对接集成案例——“SC采购入库-深圳天一-OK”&#xff0c;详细探讨如何通过轻易云数据…

【springcloud学习(dalston.sr1)】使用Feign实现接口调用(八)

该系列项目整体介绍及源代码请参照前面写的一篇文章【springcloud学习(dalston.sr1)】项目整体介绍&#xff08;含源代码&#xff09;&#xff08;一&#xff09; &#xff08;一&#xff09;Feign的理解 前面文章【springcloud学习(dalston.sr1)】服务消费者通过restTemplat…

SpringbBoot nginx代理获取用户真实IP

为了演示多级代理场景&#xff0c;我们分配了以下服务器资源&#xff1a; 10.1.9.98&#xff1a;充当客户端10.0.3.137&#xff1a;一级代理10.0.4.105&#xff1a;二级代理10.0.4.129&#xff1a;三级代理10.0.4.120&#xff1a;服务器端 各级代理配置 以下是各级代理的基本配…

实验九视图索引

设计性实验 1. 创建视图V_A包括学号&#xff0c;姓名&#xff0c;性别&#xff0c;课程号&#xff0c;课程名、成绩&#xff1b; 一个语句把学号103 课程号3-105 的姓名改为陆君茹1&#xff0c;性别为女 &#xff0c;然后查看学生表的信息变化&#xff0c;再把上述数据改为原…

typeof运算符和深拷贝

typeof运算符 识别所有值类型识别函数判断是否是引用类型&#xff08;不可再细分&#xff09; //判断所有值类型 let a; typeof a //undefined const strabc; typeof str //string const n100; typeof n //number const …

NAT/代理服务器/内网穿透

目录 一 NAT技术 二 内网穿透/内网打洞 三 代理服务器 一 NAT技术 跨网络传输的时候&#xff0c;私网不能直接访问公网&#xff0c;就引入了NAT能讲私网转换为公网进行访问&#xff0c;主要解决IPv4(2^32)地址不足的问题。 1. NAT原理 当某个内网想访问公网&#xff0c;就必…

Git的安装和配置(idea中配置Git)

一、Git的下载和安装 前提条件&#xff1a;IntelliJ IDEA 版本是2023.3 &#xff0c;那么配置 Git 时推荐使用 Git 2.40.x 或更高版本 下载地址&#xff1a;CNPM Binaries Mirror 操作&#xff1a;打开链接 → 滚动到页面底部 → 选择2.40.x或更高版本的 .exe 文件&#xf…

【教程】Docker更换存储位置

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhagn.cn] 如果本文帮助到了你&#xff0c;欢迎[点赞、收藏、关注]哦~ 目录 背景说明 更换教程 1. 停止 Docker 服务 2. 创建新的存储目录 3. 编辑 Docker 配置文件 4. 迁移已有数据到新位置 5. 启动 Docker 服务 6…

PostgreSQL 配置设置函数

PostgreSQL 配置设置函数 PostgreSQL 提供了一组配置设置函数&#xff08;Configuration Settings Functions&#xff09;&#xff0c;用于查询和修改数据库服务器的运行时配置参数。这些函数为数据库管理员提供了动态管理数据库配置的能力&#xff0c;无需重启数据库服务。 …

sql server 2019 将单用户状态修改为多用户状态

记录两种将单用户状态修改为多用户状态&#xff0c;我曾经成功过的方法&#xff0c;供参考 第一种方法 USE master; GO -- 终止所有活动连接 DECLARE kill_connections NVARCHAR(MAX) ; SELECT kill_connections KILL CAST(session_id AS NVARCHAR(10)) ; FROM sys.dm_ex…