当前位置: 首页 > news >正文

JavaScript系列(62)--实时通信系统实现详解

JavaScript实时通信系统实现详解 🔄

今天,让我们深入探讨JavaScript的实时通信系统实现。实时通信是现代Web应用中不可或缺的一部分,它能够提供即时的数据交互和更好的用户体验。

WebSocket通信基础 🌟

💡 小知识:WebSocket是HTML5开始提供的一种在单个TCP连接上进行全双工通讯的协议。相比HTTP,它能够提供持久连接和双向通信能力。

// 1. WebSocket连接管理器
class WebSocketManager {constructor(url, options = {}) {this.url = url;this.options = {reconnectAttempts: 5,reconnectDelay: 1000,heartbeatInterval: 30000,...options};this.connection = null;this.reconnectCount = 0;this.listeners = new Map();this.heartbeatTimer = null;}// 建立连接connect() {try {this.connection = new WebSocket(this.url);this.setupEventListeners();this.startHeartbeat();} catch (error) {this.handleConnectionError(error);}}// 设置事件监听器setupEventListeners() {this.connection.onopen = () => {this.reconnectCount = 0;this.emit('connected');};this.connection.onclose = () => {this.handleDisconnect();};this.connection.onerror = (error) => {this.handleConnectionError(error);};this.connection.onmessage = (event) => {this.handleMessage(event.data);};}// 启动心跳检测startHeartbeat() {this.heartbeatTimer = setInterval(() => {if (this.connection.readyState === WebSocket.OPEN) {this.send('heartbeat', { timestamp: Date.now() });}}, this.options.heartbeatInterval);}// 处理断开连接handleDisconnect() {this.stopHeartbeat();this.emit('disconnected');if (this.reconnectCount < this.options.reconnectAttempts) {setTimeout(() => {this.reconnectCount++;this.connect();}, this.options.reconnectDelay * this.reconnectCount);} else {this.emit('maxReconnectAttemptsReached');}}// 发送消息send(type, data) {if (this.connection.readyState !== WebSocket.OPEN) {throw new Error('Connection is not open');}const message = JSON.stringify({ type, data });this.connection.send(message);}// 停止心跳检测stopHeartbeat() {if (this.heartbeatTimer) {clearInterval(this.heartbeatTimer);this.heartbeatTimer = null;}}
}// 2. 消息处理器
class MessageHandler {constructor() {this.handlers = new Map();}// 注册消息处理器register(type, handler) {if (!this.handlers.has(type)) {this.handlers.set(type, new Set());}this.handlers.get(type).add(handler);}// 处理消息async handle(message) {const { type, data } = JSON.parse(message);const handlers = this.handlers.get(type);if (handlers) {const promises = Array.from(handlers).map(handler => handler(data));await Promise.all(promises);}}
}// 3. 重连管理器
class ReconnectionManager {constructor(options = {}) {this.options = {maxAttempts: 5,baseDelay: 1000,maxDelay: 30000,...options};this.attempts = 0;this.currentDelay = this.options.baseDelay;}// 计算下一次重连延迟getNextDelay() {const delay = Math.min(this.currentDelay * Math.pow(2, this.attempts),this.options.maxDelay);this.attempts++;return delay;}// 重置重连状态reset() {this.attempts = 0;this.currentDelay = this.options.baseDelay;}// 检查是否可以继续重连canReconnect() {return this.attempts < this.options.maxAttempts;}
}

消息队列系统 📨

// 1. 消息队列
class MessageQueue {constructor() {this.queue = [];this.processing = false;this.maxRetries = 3;}// 添加消息enqueue(message) {this.queue.push({message,retries: 0,timestamp: Date.now()});this.processQueue();}// 处理队列async processQueue() {if (this.processing || this.queue.length === 0) return;this.processing = true;while (this.queue.length > 0) {const item = this.queue[0];try {await this.processMessage(item.message);this.queue.shift();} catch (error) {if (item.retries < this.maxRetries) {item.retries++;// 移到队列末尾this.queue.push(this.queue.shift());} else {// 放入死信队列this.moveToDeadLetter(item);this.queue.shift();}}}this.processing = false;}// 移动到死信队列moveToDeadLetter(item) {// 实现死信队列逻辑}
}// 2. 优先级队列
class PriorityMessageQueue {constructor() {this.queues = new Map();this.priorities = ['high', 'medium', 'low'];}// 添加消息enqueue(message, priority = 'medium') {if (!this.queues.has(priority)) {this.queues.set(priority, []);}this.queues.get(priority).push({message,timestamp: Date.now()});}// 获取下一个消息dequeue() {for (const priority of this.priorities) {const queue = this.queues.get(priority);if (queue && queue.length > 0) {return queue.shift();}}return null;}
}// 3. 消息持久化管理器
class MessagePersistenceManager {constructor() {this.storage = new Map();this.initStorage();}// 初始化存储async initStorage() {try {const stored = localStorage.getItem('message_queue');if (stored) {const data = JSON.parse(stored);this.storage = new Map(Object.entries(data));}} catch (error) {console.error('Failed to initialize storage:', error);}}// 保存消息async persistMessage(id, message) {this.storage.set(id, {message,timestamp: Date.now()});await this.saveToStorage();}// 保存到存储async saveToStorage() {try {const data = Object.fromEntries(this.storage);localStorage.setItem('message_queue', JSON.stringify(data));} catch (error) {console.error('Failed to save to storage:', error);}}
}

实时数据同步 🔄

// 1. 实时数据同步器
class RealtimeDataSync {constructor(options = {}) {this.options = {syncInterval: 1000,batchSize: 100,...options};this.changes = new Map();this.syncTimer = null;}// 记录变更recordChange(key, value) {this.changes.set(key, {value,timestamp: Date.now()});this.scheduleSyncIfNeeded();}// 调度同步scheduleSyncIfNeeded() {if (!this.syncTimer && this.changes.size > 0) {this.syncTimer = setTimeout(() => {this.performSync();}, this.options.syncInterval);}}// 执行同步async performSync() {const batch = this.prepareSyncBatch();if (batch.size > 0) {try {await this.sendChanges(batch);this.clearSyncedChanges(batch);} catch (error) {this.handleSyncError(error);}}this.syncTimer = null;this.scheduleSyncIfNeeded();}// 准备同步批次prepareSyncBatch() {const batch = new Map();let count = 0;for (const [key, value] of this.changes) {if (count >= this.options.batchSize) break;batch.set(key, value);count++;}return batch;}
}// 2. 冲突解决器
class ConflictResolver {constructor() {this.strategies = new Map();this.setupDefaultStrategies();}// 设置默认策略setupDefaultStrategies() {this.strategies.set('lastWriteWins', (local, remote) => {return local.timestamp > remote.timestamp ? local : remote;});this.strategies.set('merge', (local, remote) => {return {...local,...remote,timestamp: Math.max(local.timestamp, remote.timestamp)};});}// 解决冲突resolve(local, remote, strategy = 'lastWriteWins') {const resolver = this.strategies.get(strategy);if (!resolver) {throw new Error(`Unknown strategy: ${strategy}`);}return resolver(local, remote);}
}// 3. 版本控制管理器
class VersionManager {constructor() {this.versions = new Map();this.history = new Map();}// 更新版本updateVersion(key, value) {const currentVersion = this.versions.get(key) || 0;const newVersion = currentVersion + 1;this.versions.set(key, newVersion);this.recordHistory(key, value, newVersion);return newVersion;}// 记录历史recordHistory(key, value, version) {if (!this.history.has(key)) {this.history.set(key, new Map());}const keyHistory = this.history.get(key);keyHistory.set(version, {value,timestamp: Date.now()});}// 获取特定版本getVersion(key, version) {const keyHistory = this.history.get(key);if (!keyHistory) return null;return keyHistory.get(version);}
}

性能优化策略 ⚡

// 1. 消息压缩器
class MessageCompressor {constructor() {this.compressionThreshold = 1024; // 1KB}// 压缩消息async compress(message) {if (typeof message !== 'string') {message = JSON.stringify(message);}if (message.length < this.compressionThreshold) {return message;}const msgBuffer = new TextEncoder().encode(message);const compressed = await gzip(msgBuffer);return compressed;}// 解压消息async decompress(data) {if (!(data instanceof Uint8Array)) {return data;}const decompressed = await ungzip(data);return new TextDecoder().decode(decompressed);}
}// 2. 批处理优化器
class BatchProcessor {constructor(options = {}) {this.options = {maxBatchSize: 100,maxWaitTime: 1000,...options};this.batch = [];this.timer = null;}// 添加项目到批处理add(item) {this.batch.push(item);if (this.batch.length >= this.options.maxBatchSize) {this.flush();} else if (!this.timer) {this.timer = setTimeout(() => this.flush(), this.options.maxWaitTime);}}// 刷新批处理async flush() {if (this.timer) {clearTimeout(this.timer);this.timer = null;}if (this.batch.length === 0) return;const items = [...this.batch];this.batch = [];await this.processBatch(items);}
}// 3. 连接池管理器
class ConnectionPool {constructor(options = {}) {this.options = {maxConnections: 5,idleTimeout: 30000,...options};this.connections = new Set();this.idle = new Set();}// 获取连接async getConnection() {let connection;if (this.idle.size > 0) {connection = this.idle.values().next().value;this.idle.delete(connection);} else if (this.connections.size < this.options.maxConnections) {connection = await this.createConnection();this.connections.add(connection);} else {throw new Error('Connection pool exhausted');}return connection;}// 释放连接releaseConnection(connection) {if (this.connections.has(connection)) {this.idle.add(connection);setTimeout(() => {if (this.idle.has(connection)) {this.closeConnection(connection);}}, this.options.idleTimeout);}}
}

安全性考虑 🔒

// 1. 消息加密器
class MessageEncryptor {constructor() {this.keyPair = null;this.initializeKeyPair();}// 初始化密钥对async initializeKeyPair() {this.keyPair = await window.crypto.subtle.generateKey({name: 'RSA-OAEP',modulusLength: 2048,publicExponent: new Uint8Array([1, 0, 1]),hash: 'SHA-256'},true,['encrypt', 'decrypt']);}// 加密消息async encrypt(message) {const encoded = new TextEncoder().encode(typeof message === 'string' ? message : JSON.stringify(message));return window.crypto.subtle.encrypt({name: 'RSA-OAEP'},this.keyPair.publicKey,encoded);}// 解密消息async decrypt(encrypted) {const decrypted = await window.crypto.subtle.decrypt({name: 'RSA-OAEP'},this.keyPair.privateKey,encrypted);return new TextDecoder().decode(decrypted);}
}// 2. 认证管理器
class AuthenticationManager {constructor() {this.tokens = new Map();}// 验证令牌async validateToken(token) {if (!token) return false;const tokenInfo = this.tokens.get(token);if (!tokenInfo) return false;if (tokenInfo.expiresAt < Date.now()) {this.tokens.delete(token);return false;}return true;}// 生成新令牌async generateToken(userId) {const token = await this.createSecureToken();this.tokens.set(token, {userId,expiresAt: Date.now() + 24 * 60 * 60 * 1000 // 24小时});return token;}
}// 3. 速率限制器
class RateLimiter {constructor(options = {}) {this.options = {windowMs: 60000, // 1分钟maxRequests: 100,...options};this.requests = new Map();}// 检查请求是否允许async checkLimit(clientId) {this.removeOldRequests(clientId);const requests = this.requests.get(clientId) || [];if (requests.length >= this.options.maxRequests) {return false;}requests.push(Date.now());this.requests.set(clientId, requests);return true;}// 移除过期请求记录removeOldRequests(clientId) {const now = Date.now();const windowStart = now - this.options.windowMs;const requests = this.requests.get(clientId) || [];const validRequests = requests.filter(time => time > windowStart);if (validRequests.length < requests.length) {this.requests.set(clientId, validRequests);}}
}

最佳实践建议 💡

  1. 连接管理模式
// 1. 连接状态管理器
class ConnectionStateManager {constructor() {this.state = 'disconnected';this.listeners = new Set();}// 更新状态setState(newState) {const oldState = this.state;this.state = newState;this.notifyListeners(oldState, newState);}// 添加状态监听器addListener(listener) {this.listeners.add(listener);}// 通知监听器notifyListeners(oldState, newState) {for (const listener of this.listeners) {listener(oldState, newState);}}
}// 2. 重试策略
class RetryStrategy {constructor(options = {}) {this.options = {initialDelay: 1000,maxDelay: 30000,factor: 2,maxAttempts: 5,...options};}// 计算延迟时间getDelay(attempt) {const delay = this.options.initialDelay * Math.pow(this.options.factor, attempt);return Math.min(delay, this.options.maxDelay);}// 检查是否应该重试shouldRetry(attempt, error) {if (attempt >= this.options.maxAttempts) {return false;}// 根据错误类型决定是否重试return this.isRetryableError(error);}
}// 3. 日志记录器
class CommunicationLogger {constructor() {this.logs = [];this.maxLogs = 1000;}// 记录日志log(type, data) {const logEntry = {type,data,timestamp: Date.now()};this.logs.push(logEntry);if (this.logs.length > this.maxLogs) {this.logs.shift();}this.persistLogs();}// 持久化日志persistLogs() {try {localStorage.setItem('communication_logs', JSON.stringify(this.logs));} catch (error) {console.error('Failed to persist logs:', error);}}
}

结语 📝

实时通信系统是现代Web应用中的重要组成部分。通过本文,我们学习了:

  1. WebSocket通信的基础实现
  2. 消息队列系统的设计
  3. 实时数据同步机制
  4. 性能优化策略
  5. 安全性考虑和最佳实践

💡 学习建议:在实现实时通信系统时,要特别注意连接的可靠性和消息的可靠传递。同时,要根据实际需求选择合适的同步策略,平衡实时性和系统负载。


如果你觉得这篇文章有帮助,欢迎点赞收藏,也期待在评论区看到你的想法和建议!👇

终身学习,共同成长。

咱们下一期见

💻

相关文章:

JavaScript系列(62)--实时通信系统实现详解

JavaScript实时通信系统实现详解 &#x1f504; 今天&#xff0c;让我们深入探讨JavaScript的实时通信系统实现。实时通信是现代Web应用中不可或缺的一部分&#xff0c;它能够提供即时的数据交互和更好的用户体验。 WebSocket通信基础 &#x1f31f; &#x1f4a1; 小知识&am…...

【蓝桥杯嵌入式】2_LED

1、电路图 74HC573是八位锁存器&#xff0c;当控制端LE脚为高电平时&#xff0c;芯片“导通”&#xff0c;LE为低电平时芯片“截止”即将输出状态“锁存”&#xff0c;led此时不会改变状态&#xff0c;所以可通过led对应的八个引脚的电平来控制led的状态&#xff0c;原理图分析…...

代码随想录day06

242.有效的字母异位词 刚学哈希表想着使用unordered_set来实现&#xff0c;结果无法通过&#xff0c;原因是对字母异位词理解有问题&#xff0c;字母异位词是通过重新排列不同单词或短语的字母而形成的单词或短语&#xff0c;并使用所有原字母一次。对字母出现的次数有要求&am…...

Spring @PropertySource:让你的应用配置更加模块化和可维护

PropertySource注解在Spring中的作用&#xff0c;就像是给Spring应用配了一个“外部配置箱”。 想象一下&#xff0c;你在开发一个Spring应用时&#xff0c;有很多配置信息需要设置&#xff0c;比如数据库的连接信息、应用的某些功能开关等。如果这些信息都硬编码在代码中&…...

【Java】MyBatis动态SQL

在MyBatis中使用动态SQL语句。 动态SQL是指根据参数数据动态组织SQL的技术。 生活中的案例&#xff1a; 在京东上买东西时&#xff0c;用户搜索商品&#xff0c;可以选择筛选条件&#xff0c;比如品牌&#xff0c;价格&#xff0c;材质等&#xff0c;也可以不使用筛选条件。这时…...

旅行社项目展示微信小程序功能模块和开发流程

旅行社当前旅游线路的程序(微信小程序),旨在帮助旅行社更高效地管理线下活动预订,同时为客户提供便捷的报名和查看功能。适用于短途游、团队建设等活动,支持在线预订、缴费及订单管理,可根据用户需求定制更多个性化服务,为公司提升品牌知名度与客户体验。通过简洁明了的…...

litemall,又一个小商场系统

litemall Spring Boot后端 Vue管理员前端 微信小程序用户前端 Vue用户移动端 代码地址&#xff1a;litemall: 又一个小商城。 litemall Spring Boot后端 Vue管理员前端 微信小程序用户前端 Vue用户移动端...

WGCLOUD监控系统部署教程

官网地址&#xff1a;下载WGCLOUD安装包 - WGCLOUD官网 第一步、环境配置 #安装jdk 1、安装 EPEL 仓库&#xff1a; sudo yum install -y epel-release 2、安装 OpenJDK 11&#xff1a; sudo yum install java-11-openjdk-devel 3、如果成功&#xff0c;你可以通过运行 java …...

Python大数据可视化:基于Python的王者荣耀战队的数据分析系统设计与实现_flask+hadoop+spider

开发语言&#xff1a;Python框架&#xff1a;flaskPython版本&#xff1a;python3.7.7数据库&#xff1a;mysql 5.7数据库工具&#xff1a;Navicat11开发软件&#xff1a;PyCharm 系统展示 管理员登录 管理员功能界面 比赛信息管理 看板展示 系统管理 摘要 本文使用Python与…...

(苍穹外卖)项目结构

苍穹外卖项目结构 后端工程基于 maven 进行项目构建&#xff0c;并且进行分模块开发。 1). 用 IDEA 打开初始工程&#xff0c;了解项目的整体结构&#xff1a; 对工程的每个模块作用说明&#xff1a; 序号名称说明1sky-take-outmaven父工程&#xff0c;统一管理依赖版本&…...

ASP.NET Core筛选器Filter

目录 什么是Filter&#xff1f; Exception Filter 实现 注意 ActionFilter 注意 案例&#xff1a;自动启用事务的筛选器 事务的使用 TransactionScopeFilter的使用 什么是Filter&#xff1f; 切面编程机制&#xff0c;在ASP.NET Core特定的位置执行我们自定义的代码。…...

ChatGPT怎么回事?

纯属发现&#xff0c;调侃一下~ 这段时间deepseek不是特别火吗&#xff0c;尤其是它的推理功能&#xff0c;突发奇想&#xff0c;想用deepseek回答一些问题&#xff0c;回答一个问题之后就回复服务器繁忙&#xff08;估计还在被攻击吧~_~&#xff09; 然后就转向了GPT&#xf…...

软件工程-可行性研究

包含 技术可行性 使用现有技术能实现这个系统吗&#xff1f; 经济可行性 这个系统的经济效益能超过它的开发成本吗&#xff1f; 操作可行性 系统的操作方式在这个用户组织内行得通吗&#xff1f; 必要时还应该从法律、社会效益等更广泛的方面研究每种解法的可行性 可行性…...

园区网设计与实战

想做一个自己学习的有关的csdn账号&#xff0c;努力奋斗......会更新我计算机网络实验课程的所有内容&#xff0c;还有其他的学习知识^_^&#xff0c;为自己巩固一下所学知识。 我是一个萌新小白&#xff0c;有误地方请大家指正&#xff0c;谢谢^_^ 文章目录 前言 这个实验主…...

spy-debugger + Charles 调试移动端/内嵌小程序H5

简介说明&#xff1a; PC端可以用F12进行console等进行调试&#xff0c;但移动端App中使用webview就无法进行实时调试&#xff0c;针对这种情况 1. 安装 全局安装 spy-debugger sudo npm install spy-debugger -g // window不用加sudo2. spy-debugger 证书 其实spy-debugg…...

4.攻防世界 unseping

进入题目页面如下 直接给出源码&#xff0c;开始代码审计 <?php // 高亮显示当前 PHP 文件的源代码&#xff0c;方便调试和查看代码结构 highlight_file(__FILE__);// 定义一个名为 ease 的类 class ease {// 定义私有属性 $method&#xff0c;用于存储要调用的方法名priv…...

安装和使用 Ollama(实验环境windows)

下载安装 下载 https://ollama.com/download/windows 安装 Windows 安装 如果直接双击 OllamaSetup.exe 安装&#xff0c;默认会安装到 C 盘&#xff0c;如果需要指定安装目录&#xff0c;需要通过命令行指定安装地址&#xff0c;如下&#xff1a; # 切换到安装目录 C:\Use…...

(一)DeepSeek大模型安装部署-Ollama安装

大模型deepseek安装部署 (一)、安装ollama curl -fsSL https://ollama.com/install.sh | sh sudo systemctl start ollama sudo systemctl enable ollama sudo systemctl status ollama(二)、安装ollama遇到网络问题&#xff0c;请手动下载 ollama-linux-amd64.tgz curl -L …...

【大数据技术】搭建完全分布式高可用大数据集群(ZooKeeper)

搭建完全分布式高可用大数据集群(ZooKeeper) apache-zookeeper-3.8.4-bin.tar.gz注:请在阅读本篇文章前,将以上资源下载下来。 写在前面 本文主要介绍搭建完全分布式高可用集群 ZooKeeper 的详细步骤。 注意: 统一约定将软件安装包存放于虚拟机的/software目录下,软件…...

前端学习-tab栏切换改造项目(三十一)

目录 前言 监听代码 思路 代码 事件委托代码 思路 代码 总结 前言 星垂平野阔&#xff0c;月涌大江流 监听代码 思路 等待DOM加载完成 获取所有标签 为每个标签添加鼠标悬停事件监听器 定义showTab函数&#xff1a; 接收一个索引参数index&#xff0c;用于标识当前悬停…...

变量 varablie 声明- Rust 变量 let mut 声明与 C/C++ 变量声明对比分析

一、变量声明设计&#xff1a;let 与 mut 的哲学解析 Rust 采用 let 声明变量并通过 mut 显式标记可变性&#xff0c;这种设计体现了语言的核心哲学。以下是深度解析&#xff1a; 1.1 设计理念剖析 安全优先原则&#xff1a;默认不可变强制开发者明确声明意图 let x 5; …...

大型活动交通拥堵治理的视觉算法应用

大型活动下智慧交通的视觉分析应用 一、背景与挑战 大型活动&#xff08;如演唱会、马拉松赛事、高考中考等&#xff09;期间&#xff0c;城市交通面临瞬时人流车流激增、传统摄像头模糊、交通拥堵识别滞后等问题。以演唱会为例&#xff0c;暖城商圈曾因观众集中离场导致周边…...

CMake基础:构建流程详解

目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...

C++ Visual Studio 2017厂商给的源码没有.sln文件 易兆微芯片下载工具加开机动画下载。

1.先用Visual Studio 2017打开Yichip YC31xx loader.vcxproj&#xff0c;再用Visual Studio 2022打开。再保侟就有.sln文件了。 易兆微芯片下载工具加开机动画下载 ExtraDownloadFile1Info.\logo.bin|0|0|10D2000|0 MFC应用兼容CMD 在BOOL CYichipYC31xxloaderDlg::OnIni…...

大语言模型(LLM)中的KV缓存压缩与动态稀疏注意力机制设计

随着大语言模型&#xff08;LLM&#xff09;参数规模的增长&#xff0c;推理阶段的内存占用和计算复杂度成为核心挑战。传统注意力机制的计算复杂度随序列长度呈二次方增长&#xff0c;而KV缓存的内存消耗可能高达数十GB&#xff08;例如Llama2-7B处理100K token时需50GB内存&a…...

MySQL账号权限管理指南:安全创建账户与精细授权技巧

在MySQL数据库管理中&#xff0c;合理创建用户账号并分配精确权限是保障数据安全的核心环节。直接使用root账号进行所有操作不仅危险且难以审计操作行为。今天我们来全面解析MySQL账号创建与权限分配的专业方法。 一、为何需要创建独立账号&#xff1f; 最小权限原则&#xf…...

Python Einops库:深度学习中的张量操作革命

Einops&#xff08;爱因斯坦操作库&#xff09;就像给张量操作戴上了一副"语义眼镜"——让你用人类能理解的方式告诉计算机如何操作多维数组。这个基于爱因斯坦求和约定的库&#xff0c;用类似自然语言的表达式替代了晦涩的API调用&#xff0c;彻底改变了深度学习工程…...

c++第七天 继承与派生2

这一篇文章主要内容是 派生类构造函数与析构函数 在派生类中重写基类成员 以及多继承 第一部分&#xff1a;派生类构造函数与析构函数 当创建一个派生类对象时&#xff0c;基类成员是如何初始化的&#xff1f; 1.当派生类对象创建的时候&#xff0c;基类成员的初始化顺序 …...

MyBatis中关于缓存的理解

MyBatis缓存 MyBatis系统当中默认定义两级缓存&#xff1a;一级缓存、二级缓存 默认情况下&#xff0c;只有一级缓存开启&#xff08;sqlSession级别的缓存&#xff09;二级缓存需要手动开启配置&#xff0c;需要局域namespace级别的缓存 一级缓存&#xff08;本地缓存&#…...

spring Security对RBAC及其ABAC的支持使用

RBAC (基于角色的访问控制) RBAC (Role-Based Access Control) 是 Spring Security 中最常用的权限模型&#xff0c;它将权限分配给角色&#xff0c;再将角色分配给用户。 RBAC 核心实现 1. 数据库设计 users roles permissions ------- ------…...