feat: 完善多租户md

This commit is contained in:
橙子
2024-07-28 23:40:29 +08:00
parent 8b890a9271
commit 2eaa5f5bb6
12 changed files with 106 additions and 7 deletions

View File

@@ -134,10 +134,9 @@ namespace Yi.Framework.TenantManagement.Application
var moduleContainer = service.GetRequiredService<IModuleContainer>(); var moduleContainer = service.GetRequiredService<IModuleContainer>();
//没有数据库,不能创工作单元,创建库,先关闭 //没有数据库,不能创工作单元,创建库,先关闭
ISqlSugarClient db = null;
using (var uow = UnitOfWorkManager.Begin(requiresNew: true, isTransactional: false)) using (var uow = UnitOfWorkManager.Begin(requiresNew: true, isTransactional: false))
{ {
db = await _repository.GetDbContextAsync(); ISqlSugarClient db = await _repository.GetDbContextAsync();
//尝试创建数据库 //尝试创建数据库
db.DbMaintenance.CreateDatabase(); db.DbMaintenance.CreateDatabase();

View File

@@ -16,6 +16,7 @@ import '@/assets/atom-one-dark.css';
import '@/assets/github-markdown.css'; import '@/assets/github-markdown.css';
import hljs from "highlight.js"; import hljs from "highlight.js";
const isShowTipNumber=ref(10);
const router = useRouter(); const router = useRouter();
//聊天存储 //聊天存储
const chatStore = useChatStore(); const chatStore = useChatStore();
@@ -34,6 +35,18 @@ const inputListDataStore = ref([{ key: "all", value: "" }, { key: "ai", value: "
//AI聊天临时存储 //AI聊天临时存储
const sendAiChatContext = ref([]); const sendAiChatContext = ref([]);
let timerTip=null;
//倒计时显示tip
const startCountTip = () => {
timerTip = setInterval(() => {
if (isShowTipNumber.value > 0) {
isShowTipNumber.value--;
} else {
clearInterval(timerTip); // 倒计时结束
}
}, 1000);
};
//当前聊天框显示的消息 //当前聊天框显示的消息
const currentMsgContext = computed(() => { const currentMsgContext = computed(() => {
if (selectIsAll()) { if (selectIsAll()) {
@@ -93,7 +106,7 @@ let codeCopyDic=[];
//code部分处理、高亮 //code部分处理、高亮
const codeHandler = (code, language) => { const codeHandler = (code, language) => {
const codeIndex = parseInt(Date.now() + "") + Math.floor(Math.random() * 10000000); const codeIndex = parseInt(Date.now() + "") + Math.floor(Math.random() * 10000000);
console.log(codeIndex,"codeIndex"); //console.log(codeIndex,"codeIndex");
// 格式化第一行是右侧language和 “复制” 按钮; // 格式化第一行是右侧language和 “复制” 按钮;
if (code) { if (code) {
const navCode = navHandler(code) const navCode = navHandler(code)
@@ -179,11 +192,15 @@ onMounted(async () => {
} }
chatStore.setMsgList((await getChatAccountMessageList()).data); chatStore.setMsgList((await getChatAccountMessageList()).data);
chatStore.setUserList((await getChatUserList()).data); chatStore.setUserList((await getChatUserList()).data);
startCountTip();
}) })
onUnmounted(() => { onUnmounted(() => {
if (timer != null) { if (timer != null) {
clearInterval(timer) clearInterval(timer)
} }
if (timerTip != null) {
clearInterval(timerTip)
}
}) })
@@ -370,8 +387,9 @@ const getLastMessage = ((receiveId, itemType) => {
</script> </script>
<template> <template>
<div style="position: absolute; top: 0;left: 0;">
<p>当前版本1.4.0</p> <div style="position: absolute; top: 0;left: 0;" v-show="isShowTipNumber>0">
<p>当前版本1.5.0</p>
<p>tip:官方学习交流群每次发送消息消耗 1 钱钱</p> <p>tip:官方学习交流群每次发送消息消耗 1 钱钱</p>
<p>tip:点击聊天窗口右上角X可退出</p> <p>tip:点击聊天窗口右上角X可退出</p>
<p>tip:多人同时在聊天室时左侧可显示其他成员</p> <p>tip:多人同时在聊天室时左侧可显示其他成员</p>
@@ -380,6 +398,7 @@ const getLastMessage = ((receiveId, itemType) => {
<p>tip:当前Ai为OpenAi ChatGpt4由于接口收费原因还请各位手下留情</p> <p>tip:当前Ai为OpenAi ChatGpt4由于接口收费原因还请各位手下留情</p>
<p>tip:ai对话为持续对话已优化输出速度</p> <p>tip:ai对话为持续对话已优化输出速度</p>
<p>tip:ai对话只有本地存储了记录可点击清除或刷新</p> <p>tip:ai对话只有本地存储了记录可点击清除或刷新</p>
<p>即将自动隐藏tip{{ isShowTipNumber }}</p>
</div> </div>
<div class="body"> <div class="body">
<div class="left"> <div class="left">
@@ -885,6 +904,7 @@ const getLastMessage = ((receiveId, itemType) => {
font-size: 18px; font-size: 18px;
border-radius: 5px; border-radius: 5px;
max-width: 600px; max-width: 600px;
text-align: justify;
} }
@@ -926,7 +946,7 @@ const getLastMessage = ((receiveId, itemType) => {
.content-others-msg { .content-others-msg {
background-color: #FFFFFF; background-color: #FFFFFF;
padding: 10px 15px; padding: 10px 15px;
text-align: justify;
} }
.content-others-msg:hover { .content-others-msg:hover {

View File

@@ -0,0 +1,80 @@
## 多租户
多租户的概念、模式特别多,想要狠狠的把玩好多租户,在使用多租户之前,务必了解清楚,什么是多租户?什么才是适合你的多租户选型?希望以下的内容能帮助你对多租户的理解更深入
## 什么是多租户?
不同人有很多说法,有的人说
- 能够连接多个数据库操作的就是多租户
- 通过表的一个字段进行数据过滤的就是多租户
- 能够将不同的数据存放在多个库的就是多租户
- 多租户需要主库、业务库、默认库等等要求
他们说的对吗?不能说错,但也不全对,正是因为多租户的模式比较多,实际用到的是哪种,要由业务来决定。
我们站在各各角度,给大家举个例子,自然就很好的分清楚,你当前的方式:
#### 业务方面:
- 如果你是开发的类似淘宝的软件,每个店铺是多租户的,但是里面的用户又是一起,而不需要每次进入一个店铺就要注册一个店铺淘宝账号(需要主库共享,业务库多租户)
- 如果是你开发一个类似餐饮的软件,每个线下餐馆都是一个新的客户,而一个用户的数据不需要共享在两个店铺中(业务库多租户)
- 如果你开发的是一个类似Mes工厂系统的软件你的很多设备数据甲方要求从他们的数据库中直接搂意味着你的软件需要处理自己的数据库还要连接客户的数据库需要根据操作的实体进行切换数据库
#### 安全方面:
- 通过表字段进行隔离既加一个租户id字段查询表的时候进行数据过滤操作简单成本低但是隔离程度低一个租户出问题其他都影响
- 通过数据库进行隔离既通过租户id进行切换数据库一个租户一个数据库操作复杂成本高但是隔离程度高一个租户出问题不会影响到其他租户
- 通过数据库和表字段混合进行隔离,既可以选择是表隔离还是数据库隔离(结合上面的优缺点,对软件设计要求程度高)
> 如果是多数据库还可以兼容考虑不同数据库类型A用mysqlB用sqlserver这种更加复杂。
#### 配置方式:
- 事先知道要连几个数据库代码里先new几个db根据传入的租户条件进行选择使用哪个db需改代码成本低切换租户方便
- 通过配置文件进行配置租户数量变更租户数量代码无须更改但是会根据传入的租户条件进行选择哪个配置的db需重启成本较高切换租户较困难
- 通过界面上进行动态管理租户变更租户数量代码无须更改会根据传入的租户条件进行选择哪个db无需重启成本高切换租户较困难
> 等等,什么千奇百怪的方式都有,不同的方式适合不同的需求
## YI框架支持的多租户
- [x] 表字段进行隔离
- [x] 数据库进行隔离,且支持不同租户多数据库类型
- [x] 支持配置文件租户
- [x] 支持界面配置租户(界面配置其实也是能通过接口配置,一个道理)
- [x] 支持不同实体访问不同数据库需使用sqlsugar功能
## 接入多租户教程
yi框架基本大部分多租户方式都支持以下教程是基于较困难的数据库分库的多租户模式
#### 开启
默认是不开启多租户的,需要在配置文件中开启后才生效
![alt text](image.png)
> 多租户是有默认库的概念存在当接口传入的信息中不带有任何租户信息你也不能报错框架会自动选择Url为默认租户库另外租户表也会存储在默认库中
启动后我们切换swagger到租户模块默认模板中已接入租户模块但配置文件是关闭的
![alt text](image-1.png)
![alt text](image-2.png)
这里需要注意一下
> 由于sqlsugar简化了efcore,dbcontext上下文的概念所以无法从dbcontext获取当前使用的是什么db类型另外又为了兼容`abp连接字符串`模块,只能通过`连接key`,和`连接url`中存放db类型所以db类型有个规定以租户name的尾缀 "_xxx" 来决定如果没有将保持和默认库的db类型一致
我们创建好一个db类型之后通过返回的租户id可以进行初始化既框架实现了各各租户的db创建、表结构创建、种子初始化数据
![alt text](image-4.png)
我们可以看到,数据已经初始化了
![alt text](image-3.png)
接下来,我们如何使用该租户呢?
我们选择rbac模块下的config表进行操作
根据前端head传入的租户id框架将自动切换租户我们给他刚刚创建的租户新增一个config
![alt text](image-5.png)
然后再查询他的config发现确实新增了
![alt text](image-6.png)
如果我不传租户信息,使用默认库,就没有这条信息了
![alt text](image-7.png)
当然如果你的租户不想在数据库中配置这套模式得力于abp连接字符串模块支持可以通过配置文件新增优先级更高
我们在配置文件中新增一个租户:
![alt text](image-8.png)
重复以上部分,结果是一模一样的,如果你的多租户是固定的,或者数据库很少,直接放配置文件还方便些~

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB