php常用设计模式应用场景及示例
单例模式
-
含义描述
应用程序中最多只有该类的一个实例存在
-
应用场景
常应用于数据库类设计,采用单例模式,只连接一次数据库,防止打开多个数据库连接。
-
代码示例
class Singleton {private static $instance; // 定义一个私有的静态变量保存类的实例private function __construct() {} // 将构造函数设为私有,防止外部直接创建对象public static function getInstance() {if (!self::$instance) { // 如果没有实例化则进行实例化操作self::$instance = new self();}return self::$instance; // 返回已经实例化好的对象} }// 调用单例模式获取实例 $obj1 = Singleton::getInstance(); $obj2 = Singleton::getInstance();var_dump($obj1 === $obj2); // true,两次获取到的都是同一个实例
工厂模式
-
含义描述
工厂设计模式常用于根据输入参数的不同或者应用程序配置的不同来创建一种专门用来实例化并返回其对应的类的实例
-
应用场景
1.后台数据导出:比如可导出文件类型有excel、csv、xml等,同样都是实现导出功能,但是要实例化的类是不同的,实现逻辑也不相同;
2.支付系统:根据用户选择的支付方式实例化不同的支付类,比如积分、微信、支付宝等支付
3.缓存功能:一般有文件缓存、session、cookie等,他们的实例也是不同的。
-
代码示例
<?php// 定义接口,定义所有对象的通用方法 interface ShapeInterface {public function draw(); }// 实现接口的具体类,画一个圆形 class Circle implements ShapeInterface {public function draw(){echo "Drawing a circle.\n";} }// 实现接口的具体类,画一个长方形 class Rectangle implements ShapeInterface {public function draw(){echo "Drawing a rectangle.\n";} }// 工厂类 class ShapeFactory {// 根据传入的形状类型生成对应的对象public static function createShape($shapeType){if ($shapeType == 'circle') {return new Circle();} elseif ($shapeType == 'rectangle') {return new Rectangle();} else {throw new Exception("Invalid shape type: " . $shapeType);}} }// 使用工厂类生成对象并调用方法 try {$circle = ShapeFactory::createShape('circle');$circle->draw();$rectangle = ShapeFactory::createShape('rectangle');$rectangle->draw();// 尝试创建无效的形状类型$invalidShape = ShapeFactory::createShape('triangle'); } catch (Exception $e) {echo "Error: " . $e->getMessage(); }输出结果: Drawing a circle. Drawing a rectangle. Error: Invalid shape type: triangle
在这个示例中,我们定义了一个ShapeInterface接口,它包含了一个draw()方法,用于绘制形状。然后,我们创建了两个实现该接口的具体类Circle和Rectangle,它们分别实现了draw()方法来绘制圆形和矩形。
接下来,我们创建了一个ShapeFactory工厂类,它包含一个静态方法createShape(),该方法根据传入的形状类型(字符串)生成相应的对象实例。在createShape()方法中,我们根据传入的形状类型使用条件语句创建对应的对象,并返回该对象。如果传入的形状类型无效,我们将抛出一个异常。
最后,我们使用ShapeFactory类来生成圆形和矩形的对象,并调用它们的draw()方法来绘制形状。同时,我们也尝试创建一个无效的形状类型(三角形),以演示异常处理机制。
策略模式
-
含义描述
策略设计模式是一种行为设计模式,它允许你在运行时改变对象的行为。在策略模式中,一个类的行为或其算法可以在运行时更改应用场景
-
应用场景
- 商城促销方式:对秒杀、满减、打折等不同促销方式用不同的算法计算不同的结算价格
- 日志系统:根据日志的类型做不同的响应
-
代码示例
//我们将以一个简单的日志记录系统为例,其中我们可以选择不同的日志策略来记录信息。//首先,我们定义一个日志策略接口:<?php interface LoggingStrategy {public function log(string $message); }//然后,我们实现几种不同的日志策略,例如控制台日志、文件日志和数据库日志:<?php class ConsoleLog implements LoggingStrategy {public function log(string $message) {echo "Console: " . $message . PHP_EOL;} }class FileLog implements LoggingStrategy {private $file;public function __construct(string $file) {$this->file = $file;}public function log(string $message) {file_put_contents($this->file, "File: " . $message . PHP_EOL, FILE_APPEND);} }class DatabaseLog implements LoggingStrategy {private $pdo;public function __construct(PDO $pdo) {$this->pdo = $pdo;}public function log(string $message) {$stmt = $this->pdo->prepare("INSERT INTO logs (message) VALUES (?)");$stmt->execute([$message]);} }//接下来,我们创建一个Logger类,该类使用策略模式来记录日志:<?php class Logger {private $strategy;public function __construct(LoggingStrategy $strategy) {$this->strategy = $strategy;}public function setStrategy(LoggingStrategy $strategy) {$this->strategy = $strategy;}public function log(string $message) {$this->strategy->log($message);} }//最后,我们在主程序中使用Logger类:<?php // 创建一个PDO实例用于数据库连接(这里仅作示例,实际使用时需要配置数据库连接参数) $pdo = new PDO('mysql:host=localhost;dbname=mydb', 'username', 'password');// 创建不同的日志策略实例 $consoleLog = new ConsoleLog(); $fileLog = new FileLog('path/to/logfile.log'); $databaseLog = new DatabaseLog($pdo);// 创建一个Logger实例,并设置初始的日志策略为控制台日志 $logger = new Logger($consoleLog); $logger->log("This is a console log message.");// 更改日志策略为文件日志 $logger->setStrategy($fileLog); $logger->log("This is a file log message.");// 更改日志策略为数据库日志 $logger->setStrategy($databaseLog); $logger->log("This is a database log message.");在这个例子中,Logger类是一个上下文类,它使用LoggingStrategy接口来定义日志记录的行为。通过setStrategy方法,我们可以动态地更改日志记录的策略,从而在不同的场景下使用不同的日志记录方式。这样,如果我们想要添加新的日志策略,只需要实现LoggingStrategy接口,并在Logger中使用它即可,而不需要修改Logger类的代码。
- 与工厂模式的区别
- 目的不同:工厂模式的目的是创建对象,根据传入的参数或条件返回不同类型的对象;而策略模式的目的是在运行时选择不同的行为或算法。
- 关注点不同:工厂模式关注对象的创建过程,封装了对象的创建逻辑;而策略模式关注行为或算法的选择和切换。
- 使用场景不同:工厂模式通常用于处理对象的创建问题,如多数据库选择、类库文件加载等;而策略模式通常用于处理算法或行为的选择问题,如排序算法的选择、支付方式的选择等。
- 与工厂模式的区别
观察者模式
-
含义描述
观察者模式是一种软件设计模式,属于对象行为模式。它定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
-
应用场景
- 事件处理:观察者模式常被用于事件处理机制,如图形用户界面(GUI)框架中的按钮点击事件、窗口的打开和关闭事件等。观察者对象可以订阅这些特定事件,并在事件发生时接收通知并执行相应的操作。
- 消息通知:在消息通知系统中,如聊天应用、社交媒体平台等需要实时消息传递的场景中,观察者模式也得到了广泛应用。当发布者发布新消息时,订阅该消息的观察者会收到通知并进行相应的处理。
- 股票市场:在股票市场中,观察者模式可以用于实现订阅者监听发布者的状态变化并作出响应。
- 日志记录:观察者模式还可以用于实时日志记录系统。在这种情况下,日志记录器充当被观察者,而观察者可以是日志分析器、报警系统等。当日志发生变化时,观察者会收到通知并执行相应的操作,如生成报告、发送警报等。
- Redis中的发布订阅:Redis中的基于频道的发布订阅也是观察者模式的一个应用实例。
-
代码示例
在 PHP 中实现观察者模式,可以定义一个 Subject 类和一个 Observer 接口。Subject 类维护一个观察者列表,并提供添加、删除和通知观察者的方法。Observer 接口定义了观察者需要实现的方法。下面是一个简单的示例代码,展示了如何在 PHP 中实现观察者模式:<?php // Observer 接口 interface Observer {public function update(Subject $subject); }// ConcreteObserver 类 class ConcreteObserver implements Observer {private $name;public function __construct($name) {$this->name = $name;}public function update(Subject $subject) {echo "Observer {$this->name} received update: {$subject->getState()}\n";} }// Subject 类 class Subject {private $observers = [];private $state;public function attach(Observer $observer) {$this->observers[] = $observer;}public function detach(Observer $observer) {$key = array_search($observer, $this->observers);if ($key !== false) {unset($this->observers[$key]);}}public function notify() {foreach ($this->observers as $observer) {$observer->update($this);}}public function setState($state) {$this->state = $state;$this->notify();}public function getState() {return $this->state;} }// 使用示例 $subject = new Subject();$observer1 = new ConcreteObserver('Observer 1'); $observer2 = new ConcreteObserver('Observer 2');$subject->attach($observer1); $subject->attach($observer2);$subject->setState('New state');$subject->detach($observer1);$subject->setState('Another state');在上面的示例中,我们定义了一个 Observer 接口,它包含了一个 update 方法,用于接收主题的状态更新。ConcreteObserver 类实现了 Observer 接口,并在 update 方法中打印接收到的更新信息。Subject 类维护了一个观察者列表($observers),并提供了 attach 方法用于添加观察者,detach 方法用于移除观察者,以及 notify 方法用于通知所有观察者。setState 方法用于设置主题的状态,并在状态改变时调用 notify 方法通知观察者。getState 方法用于获取当前的主题状态。在使用示例中,我们创建了一个主题对象 $subject,并将两个观察者对象 $observer1 和 $observer2 添加到主题中。然后,我们通过调用 setState 方法改变主题的状态,并观察者的 update 方法将被调用,打印接收到的更新信息。最后,我们通过调用 detach 方法移除了一个观察者,并再次改变主题的状态,观察者的更新信息将不再打印。
装饰器模式
-
含义描述
装饰器设计模式是一种结构型设计模式,它允许动态地给一个对象添加一些额外的职责或功能
-
应用场景
- 游戏开发:装备各种不同的武器装备增加各种属性,如攻击力、HP和防御等
- 点餐系统:根据用户选择的不同商品规格和配料,计算价格和满减优惠
-
代码示例
// 定义一个接口,表示被装饰的对象 interface Coffee {public function getCost();public function getIngredients(); }// 创建一个实现了Coffee接口的具体对象,即被装饰的对象 class SimpleCoffee implements Coffee {public function getCost() {return 1.99;}public function getIngredients() {return "Coffee";} }// 创建一个加奶咖啡装饰器类,它包装了Coffee对象 class CoffeeWithMilk extends SimpleCoffee implements Coffee {private $coffee;public function __construct(Coffee $coffee) {$this->coffee = $coffee;}public function getCost() {return $this->coffee->getCost() + 0.30;}public function getIngredients() {return $this->coffee->getIngredients() . ", Milk";} }// 创建一个加糖咖啡的装饰器类,它也为Coffee对象添加额外的行为 class CoffeeWithSugar extends CoffeeWithMilk {public function getCost() {return parent::getCost() + 0.20;}public function getIngredients() {return parent::getIngredients() . ", Sugar";} }// 使用装饰器 $coffee = new SimpleCoffee(); echo "Cost: " . $coffee->getCost() . "\n"; echo "Ingredients: " . $coffee->getIngredients() . "\n";$coffeeWithMilk = new CoffeeWithMilk($coffee); echo "Cost: " . $coffeeWithMilk->getCost() . "\n"; echo "Ingredients: " . $coffeeWithMilk->getIngredients() . "\n";$coffeeWithSugar = new CoffeeWithSugar($coffeeWithMilk); echo "Cost: " . $coffeeWithSugar->getCost() . "\n"; echo "Ingredients: " . $coffeeWithSugar->getIngredients() . "\n";输出结果: Cost: 1.99 Ingredients: Coffee Cost: 2.29 Ingredients: Coffee, Milk Cost: 2.79 Ingredients: Coffee, Milk, Milk, Sugar
在这个示例中,我们有一个Coffee接口和两个实现了该接口的类:SimpleCoffee(被装饰的对象)和CoffeeWithMilk、CoffeeWithSugar(装饰器类)。
CoffeeWithMilk装饰器类包装了一个Coffee对象,并添加了牛奶和额外的成本。CoffeeWithSugar装饰器类进一步包装了CoffeeWithMilk对象,并添加了糖和额外的成本。
通过链式使用装饰器,我们可以动态地构建具有不同功能和成本的咖啡。
迭代器模式
-
含义描述
迭代器设计模式允许你顺序访问一个聚合对象中的各个元素,而又不需要暴露该对象的内部表示。通过使用迭代器,聚合对象与其迭代逻辑可以分离,从而使代码更加灵活和可扩展
-
应用场景
- 操作链表、树、图:用迭代器模式可以让集合类隐藏这些复杂性,只暴露“next”、“hasNext”等基本迭代操作,这样既简化了外部对集合元素的操作,也保护了集合的封装性
- for、foreach循环:通过for语句直接遍历任何实现了迭代协议的对象,极大地简化了遍历过程,并且能够利用生成器模式实现惰性计算和流式处理
-
代码示例
//首先,定义一个迭代器接口(Iterator):interface Iterator {public function current();public function key();public function next();public function rewind();public function valid(); }//然后,定义一个具体的迭代器类(ConcreteIterator),它实现了迭代器接口:class ConcreteIterator implements Iterator {private $data;private $position = 0;public function __construct(array $data) {$this->data = $data;}public function current() {return $this->data[$this->position];}public function key() {return $this->position;}public function next() {$this->position++;}public function rewind() {$this->position = 0;}public function valid() {return isset($this->data[$this->position]);} }//接下来,定义一个聚合对象接口(Aggregate),该接口定义了一个方法来创建迭代器:interface Aggregate {public function createIterator(); }//然后,创建一个实现了聚合对象接口的具体聚合类(ConcreteAggregate):class ConcreteAggregate implements Aggregate {private $data = [];public function add($item) {$this->data[] = $item;}public function createIterator() {return new ConcreteIterator($this->data);} }//最后,你可以使用这些类来实现迭代器的功能:// 创建一个聚合对象 $aggregate = new ConcreteAggregate(); $aggregate->add('Element 1'); $aggregate->add('Element 2'); $aggregate->add('Element 3');// 获取聚合对象的迭代器 $iterator = $aggregate->createIterator();// 使用迭代器遍历聚合对象中的元素 $iterator->rewind(); while ($iterator->valid()) {echo $iterator->current() . "\n";$iterator->next(); }
在上面的示例中,ConcreteAggregate 类存储了一个元素数组,并提供了 createIterator() 方法来创建一个新的 ConcreteIterator 实例。ConcreteIterator 类实现了 Iterator 接口,用于遍历 ConcreteAggregate 中的元素。
相关文章:
php常用设计模式应用场景及示例
单例模式 含义描述 应用程序中最多只有该类的一个实例存在 应用场景 常应用于数据库类设计,采用单例模式,只连接一次数据库,防止打开多个数据库连接。 代码示例 class Singleton {private static $instance; // 定义一个私有的静态变量保存…...

浏览器与服务器通信过程(HTTP协议)
目录 1 概念 2 常见的 web 服务器有 3 浏览器与服务器通信过程 3.1 DNS 3.2 URL 4 HTTP请求方法和应答状态码 4.1 HTTP请求报文段实例 4.2 HTTP请求方法 5 HTTP应答报头和应答状态 5.1 HTTP的应答报头结构 5.2 HTTP的应答状态 1 概念 浏览器与 web 服务器在应用层通…...

Pytorch搭建AlexNet 预测实现
1.导包 import torch import matplotlib.pyplot as plt import json from model import AlexNet from PIL import Image from torchvision import transforms 2.数据预处理 data_transform transforms.Compose([transforms.Resize((224, 224)), # 将图片重新裁剪transform…...
笔记:使用parfile进行的数据导入导出
expdp ‘username/password’ parfileE:\dmp_tmp\par.txt DIRECTORYdmptmp LOGFILESYS_SEND_LOG.log DUMPFILESYS_SEND_LOG.dmp tablesSYS_SEND_LOG_BAK query“where send_dt>TO_DATE(‘2024-03-13’,‘yyyy-mm-dd’)” impdp ‘username/password’ directorydmptmp dum…...

基于YOLOv8/YOLOv7/YOLOv6/YOLOv5的行人跌倒检测系统(深度学习+UI界面+完整训练数据集)
摘要:开发行人跌倒检测系统在确保老年人安全方面扮演着至关重要的角色。本篇文章详尽地阐述了如何利用深度学习技术构建一个行人跌倒检测系统,并附上了完整的代码实现。该系统采用了先进的YOLOv8算法,并对YOLOv7、YOLOv6、YOLOv5等先前版本进…...

Ubuntu 14.04:PaddleOCR基于PaddleServing的在线服务化部署(失败)
一、 二、安装 注: 安装 PaddleOCR 2.3 。 因为 PaddleOCR 2.4 的 推荐环境 PaddlePaddle > 2.1.2。 https://github.com/PaddlePaddle/PaddleOCR/blob/release/2.4/doc/doc_ch/environment.md 安装前的环境准备 在使用Paddle Serving之前,需要完…...

Java JUC 笔记(2)
Java JUC 笔记(2) 锁框架 JDK5以后增加了Lock接口用来实现锁功能,其提供了与synchronized类似的同步功能,但是在使用时手动的获取和释放锁 Lock和Condition锁 这里的锁与synchronized锁不太一样,我们可以认为是Loc…...
webpack5高级--02_提升打包构建速度
提升打包构建速度 一、HotModuleReplacement 为什么 开发时我们修改了其中一个模块代码,Webpack 默认会将所有模块全部重新打包编译,速度很慢。 所以我们需要做到修改某个模块代码,就只有这个模块代码需要重新打包编译,其他模…...

MAC M芯片 Anaconda安装
Anaconda安装 1.M芯片下载AnaConda 1.M芯片下载AnaConda https://www.anaconda.com/download 安装完成 conda的版本是24.1.2...
【JS】自动下拉网页刷新,当出现指定关键字,就打印出来
批量检查域名是否可以注册 1、有的网站数据是通过下拉发生请求,间隔x毫秒自动下拉 2、查找某个关键字,找到就打印出来 3、打印数据自动去重 4、当连续n次下拉,没有新div元素出来,就停止该循环 var map {}; var count 0; var l…...

中兴通讯联手新疆移动,开通全疆首个乡农场景700M+900M双频双模基站
日前,在新疆博尔塔拉蒙古自治州,中兴通讯携手新疆移动共同完成了全疆首个乡农场景的700M900M双频双模基站建设,其通过采用“700M与900M共天馈共RRU设备”,成功实现乡农4/5G网络的同站址快速部署,为新疆的农牧业发展注入…...

爬虫案例4: parsel 模块的运用
目标页面: https://www.shanghairanking.cn/rankings/bcur/2023 打印在终端import requests import json from urllib.parse import urljoin from parsel import Selectorurl https://www.shanghairanking.cn/rankings/bcur/2023headers {User-Agent: Mozilla/5.0 (Macintosh…...

数据结构·复杂度
目录 1 时间复杂度 2 大O渐进表示法 举例子(计算时间复杂度为多少) 3 空间复杂度 前言:复杂度分为时间复杂度和空间复杂度,两者是不同维度的,所以比较不会放在一起比较,但是时间复杂度和空间复杂度是用…...

数学建模理论与实践国防科大版
目录 1.数学建模概论 2.生活中的数学建模 2.1.行走步长问题 2.2.雨中行走问题 2.3.抽奖策略 2.4.《非诚勿扰》女生的“最优选择” 3.集体决策模型 3.1.简单多数规则 3.2.Borda数规则 3.3.群体决策模型公理和阿罗定理 1.数学建模概论 1.数学模型的概念 2.数学建模的概…...

Yakit爆破模块应用
yakit介绍 一款集成了各种渗透测试功能的集成软件。(类似于burp,但我感觉他功能挺强大) 爆破模块位置 按照下面图标点击 界面就是如下。 左侧可以选择爆破的类型,各种数据库http,ssh等都支持。 爆破参数 可以选择…...

【3GPP】【核心网】【5G】NAS连接管理和UE注册管理状态(超详细)
1. NAS连接管理 NAS连接管理包括通过N1接口在UE和AMF之间建立和释放NAS信令连接的功能。NAS信令连接用于实现UE与核心网络之间的NAS信令交换。当UE接入5G网络时,首先与基站建立RRC连接,当RRC连接建立完成后,UE与基站的空口连接成功建立。随后…...

细粒度IP定位参文2(Corr-SLG):A street-level IP geolocation method (2021年)
[2]S. Ding, F. Zhao, and X. Luo, “A street-level IP geolocation method based on delay-distance correlation and multilayered common routers,” Secur. Commun. Netw., vol. 2021, no. 1, pp. 1–10, 2021. 智能设备的地理位置可以帮助提供多媒体内容提供商和5G网络中…...

Mac上使用M1或M2芯片的设备安装Node.js时遇到一些问题,比如卡顿或性能问题
对于Mac上使用M1或M2芯片的设备可能会遇到在安装Node.js时遇到一些问题,比如卡顿或性能问题。这可能是因为某些软件包或工具在M1或M2芯片上的兼容性不佳。为了解决这个问题,您可以尝试以下方法: 1. 使用Rosetta模式 对于一些尚未适配M1或M2…...

学习vue3第四节(ref以及ref相关api)
主要记录以下api:ref()、isRef()、unref()、 shallowRef()、triggerRef()、customRef() 1、ref() 定义 接受一个内部值,返回一个响应式的、可更改的 ref 对象,此对象只有一个指向其内部值的属性 .value,.value属性用于追踪并且存…...

关于电脑无法开启5G频段热点的解决方案
tips:本文是本着解决校园网开热点后限速的问题的目的,具体情况具体对待。 1.找到设备管理器 右键该选项 2.在新弹出窗口选择首选频带 3.选择首选5GHz频带 确定之后重新连接wifi,重新开启热点,大功告成。 后记:在使用2.4ghz开热点…...

AI-调查研究-01-正念冥想有用吗?对健康的影响及科学指南
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...

多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度
一、引言:多云环境的技术复杂性本质 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时,基础设施的技术债呈现指数级积累。网络连接、身份认证、成本管理这三大核心挑战相互嵌套:跨云网络构建数据…...
进程地址空间(比特课总结)
一、进程地址空间 1. 环境变量 1 )⽤户级环境变量与系统级环境变量 全局属性:环境变量具有全局属性,会被⼦进程继承。例如当bash启动⼦进程时,环 境变量会⾃动传递给⼦进程。 本地变量限制:本地变量只在当前进程(ba…...

简易版抽奖活动的设计技术方案
1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...

解决Ubuntu22.04 VMware失败的问题 ubuntu入门之二十八
现象1 打开VMware失败 Ubuntu升级之后打开VMware上报需要安装vmmon和vmnet,点击确认后如下提示 最终上报fail 解决方法 内核升级导致,需要在新内核下重新下载编译安装 查看版本 $ vmware -v VMware Workstation 17.5.1 build-23298084$ lsb_release…...

2.Vue编写一个app
1.src中重要的组成 1.1main.ts // 引入createApp用于创建应用 import { createApp } from "vue"; // 引用App根组件 import App from ./App.vue;createApp(App).mount(#app)1.2 App.vue 其中要写三种标签 <template> <!--html--> </template>…...
Java 加密常用的各种算法及其选择
在数字化时代,数据安全至关重要,Java 作为广泛应用的编程语言,提供了丰富的加密算法来保障数据的保密性、完整性和真实性。了解这些常用加密算法及其适用场景,有助于开发者在不同的业务需求中做出正确的选择。 一、对称加密算法…...
MySQL用户和授权
开放MySQL白名单 可以通过iptables-save命令确认对应客户端ip是否可以访问MySQL服务: test: # iptables-save | grep 3306 -A mp_srv_whitelist -s 172.16.14.102/32 -p tcp -m tcp --dport 3306 -j ACCEPT -A mp_srv_whitelist -s 172.16.4.16/32 -p tcp -m tcp -…...

html css js网页制作成品——HTML+CSS榴莲商城网页设计(4页)附源码
目录 一、👨🎓网站题目 二、✍️网站描述 三、📚网站介绍 四、🌐网站效果 五、🪓 代码实现 🧱HTML 六、🥇 如何让学习不再盲目 七、🎁更多干货 一、👨…...
JAVA后端开发——多租户
数据隔离是多租户系统中的核心概念,确保一个租户(在这个系统中可能是一个公司或一个独立的客户)的数据对其他租户是不可见的。在 RuoYi 框架(您当前项目所使用的基础框架)中,这通常是通过在数据表中增加一个…...