项目里有几个多对多关系,需要表达到关系数据库。
比如:用户 角色 权限; 用户与角色是多对多关系;角色与权限是多对多关系;
一般人会分别创建 [用户角色表]、[角色权限表],来存储多对多关系,这个没啥好说的。
现在队伍里一个小伙子嫌麻烦,就创建了一张 [数据关系表],大致字段有:[第一个 id],[第二个 id],[表名]。
大家分析下,这种做法,要如何评价
1
ScotGu 2021-08-27 11:41:04 +08:00
如果一张表就能搞定这个项目,那岂不是应该献上膝盖?
|
2
securityCoding 2021-08-27 11:43:31 +08:00
瞎搞
|
3
heyjei 2021-08-27 11:43:42 +08:00
多对多的多态关系,如果他能够在 ORM 里面把这种关系配出来,就这样呗。配不出来就老老实实的多建几张表
|
4
zjj19950716 2021-08-27 11:44:49 +08:00
让他弄呗 看能玩出什么花样
|
5
buliugu 2021-08-27 11:47:25 +08:00
可以命名成数据爆炸表(逃
|
6
sy20030260 2021-08-27 11:51:13 +08:00
这种是典型的反规范建模设计,本身是没错的,得看具体的业务场景。
但是 [用户 角色 权限] 这种系统设计,本来就是典型的规范建模,具体到数据库设计又变成反规范的,就有点奇怪了~ |
7
levelworm 2021-08-27 11:53:44 +08:00 via Android 2
我擦表中表啊!
|
8
ctrlaltdeletel 2021-08-27 11:56:45 +08:00 1
最终这个模块变成了个图数据系统 XD
|
9
bk201 2021-08-27 12:33:10 +08:00
就是将关系类的数据统一放在一个表里了,数据量不大的情况下感觉也没什么问题
|
10
yeeli 2021-08-27 12:43:46 +08:00
数据不大都无所谓, 如果你以后是要搽屁股的负责人就提早改,很多时候项目和员工都撑不到爆的那一天
|
11
shanghai1943 2021-08-27 12:48:12 +08:00
一表多用了。不合理的设计。
|
12
rabbbit 2021-08-27 12:53:49 +08:00 2
没太看懂,是指他存了这么个表吗?
id1 | id2 | 表名 角色 id1| 权限 id1 | 用户权限表名 角色 id1| 权限 id2 | 用户权限表名 角色 id2| 权限 id1 | 用户权限表名 权限 id1| 角色 id1 | 用户角色表名 |
13
k9982874 2021-08-27 13:03:42 +08:00
直接甩他直属领导脸上,问就你招的这么个玩愣?
|
14
l00t 2021-08-27 13:05:16 +08:00
不知道你在说什么东西,什么第一个 ID 第二个 ID 表名,人家的字段没实际业务含义的吗?
|
15
wolfie 2021-08-27 13:12:41 +08:00
又是当时没怼过,越想越气。
user_role 、role_operation 这类设计较通用的表强行复杂化。 增加他人理解成本,并没有降低什么工作量,大数据量速度还差。 |
17
cocong 2021-08-27 13:17:08 +08:00
不是你负责的就不用管,你也管不了,瞎操心。
如果出问题了你要跟着背锅的,那就把问题反映给上级,把锅甩出去。 总的来说,如果数据量小,版本迭代慢,那怎么搞都问题。如果数据量大,或者需求经常变动,那后面加班只会越来越多。 |
18
fgwmlhdkkkw 2021-08-27 13:18:37 +08:00 1
我觉得可以优化一下,表名改为数字,挺好的吧……
|
20
comoyi 2021-08-27 13:20:38 +08:00
5 张表,用户,角色,用户-角色关系,权限,角色-权限关系
|
21
qping 2021-08-27 13:30:28 +08:00
貌似用着也没有什么问题,数据量一般也不会大
就是感觉怪怪的,能用但是不够漂亮。 |
22
young1lin 2021-08-27 13:33:38 +08:00 via Android
反范式设计,开发一时爽,维护火葬场。除非这个项目一定是他维护,不然让他改
|
23
young1lin 2021-08-27 13:36:56 +08:00 via Android 1
这个就是典型的 RBAC0 设计思路的表,你可以把更详细的 RBAC1, RBACA2, RBAC3 讲给他,还有 ACL,ABAC, PBAC 讲给他,让他去查。还有 Shiro/Spring Security 怎么实现的,最好是 Shiro 比较简单。再对比下他的设计,再让他说说你懂不懂。
|
24
EPr2hh6LADQWqRVH 2021-08-27 13:37:22 +08:00 1
你不了解,就别瞎说
邻接表,这是图查询的基石,只要数据库稍微支持一下图查询,这个结构能提供的比你那个捉鸡所谓关系模型多得多 |
25
soulzz 2021-08-27 13:40:57 +08:00
那还不如全用 mongodb 用户权限也和用户基本资料放一起,直接定义各个接口的权限
|
26
R18 2021-08-27 14:01:41 +08:00
你让他严格按照 BCNF 来就行了。
|
27
falcon05 2021-08-27 14:04:12 +08:00 via iPhone 17
楼主这表达能力让我想了半天,什么 id1,id2 的,说服力估计也不行❌
|
28
jtwor 2021-08-27 14:05:20 +08:00 1
数据库三范式。。。 那这样关联岂不是要带上 表名 条件。。
|
29
YUyu101 2021-08-27 14:07:47 +08:00
小伙子这样做就代表他把这些关系当成一个实体了,如果这些表的关系真的只有关系那没什么好说的,万一以后要给每种关系加各自属性,那他是准备搞父子表还是让多出来的字段空着,其实怎么设计都行,只要能评估好未来的工作量。
|
30
johnsonqrr 2021-08-27 14:21:25 +08:00 2
还能怎么办,上网发个贴呗
|
31
mosakashaka 2021-08-27 15:06:11 +08:00
索引搞好效率不会有问题。
|
32
Frauhling 2021-08-27 15:11:54 +08:00 1
@fgwmlhdkkkw 这个表名改为数字的主意听着就很好 XD 就是不知道是楼主先跑路还是这个小伙子先跑路
|
33
zxcslove 2021-08-27 15:15:37 +08:00
这样最大的问题是,不同的关联关系如果有不同的数据就悲剧了,只是做关联用你是杠不过他的。
|
34
5sheep OP @rabbbit 是这样存的
真实建表语句如下: CREATE TABLE [dbo].[DataConnect]( --数据关系表,可存一切多对多关系 [Id] [uniqueidentifier] NOT NULL, [SourceCode] [nvarchar](100) NULL, --存表名 [FirstId] [uniqueidentifier] NULL, --第一个 id [SecondId] [uniqueidentifier] NULL, --第二个 id [ThirdId] [uniqueidentifier] NULL, --预留字段 ... 其它预留字段 |
37
5sheep OP 12 楼的最后一行不准确,我修改下
@DavidDee id1 | id2 | 表名 角色 id1| 权限 id1 | 用户权限表名 角色 id1| 权限 id2 | 用户权限表名 角色 id2| 权限 id1 | 用户权限表名 用户 id1| 角色 id1 | 用户角色表名 用户 id1| 角色 id2 | 用户角色表名 |
38
code4you 2021-08-27 15:35:02 +08:00
只要小伙子 能搞定 能跑就行
|
39
baoshijiagong 2021-08-27 15:38:11 +08:00
sql 里面,表名如果写错,不会报错,还会以为没有数据。不好排查原因。
|
40
DavidDee 2021-08-27 15:42:53 +08:00
@5sheep
所以就是他将本来该分为两个多对多的关系表,直接使用了一个表设计,所以 id1,id2 是字段是无法确定存放的是什么内容。 如果表名 == 用户角色表名,那么 id1 就是用户 id,id2 就是角色 id ; 如果表名 == 用户权限表名,那么 id1 就是角色 id,id2 就是权限 id 。 |
41
pws22 2021-08-27 15:44:42 +08:00
说实话,如果没有一些关联特殊要求,其实设计一个大表做关联没什么毛病,就是直观看上去不好理解,但是程序逻辑能弄清就行,但是如果关联上有一些额外的字段,说不定过了一段时间再看,都会忘记了当初的设计条件了,看代码也会一脸懵,咋回事,都是反复调用这个大关联表来做操作..不能图一时轻松,还有考虑后期的维护成本和其他后来人的接受程度,选择一个大家都能比较好理解的做法. ps 如果是我组成员做出这样的,限期修改吧.
|
42
murmur 2021-08-27 15:47:00 +08:00
好家伙,表名直接写到数据里么
|
43
c6h6benzene 2021-08-27 15:52:42 +08:00 via iPhone 2
人和程序有一个能跑就行 /doge
|
44
baoshijiagong 2021-08-27 15:53:54 +08:00
|
45
baoshijiagong 2021-08-27 15:57:34 +08:00
有这种表的存在,连数据库表的模型图都不能直观画出来。
|
46
kingfalse 2021-08-27 16:07:35 +08:00
这哥们把 mysql 当 mongo 用了吗这是
|
47
vone 2021-08-27 16:10:06 +08:00
笑死,那可以把所有表都合并成一个,极为方便。
|
48
way2create 2021-08-27 16:28:52 +08:00
感觉这样更复杂啊其实
|
49
way2create 2021-08-27 16:30:01 +08:00
感觉你脸皮没他厚 怼不过他
|
50
rationa1cuzz 2021-08-27 16:32:09 +08:00
我接受这个项目,小伙是这么建表的:[角色权限 1 表]、[角色权限 2 表]、[角色权限 3 表]、[角色权限 4 表]。。。。
|
51
cnrting 2021-08-27 16:35:35 +08:00 via iPhone
这不是你该操心的事
|
52
ttyn 2021-08-27 16:37:23 +08:00
公司流程问题,这样的设计也并非不可以,要结合具体的项目来看,
稍微正规点的应该有个“设计 -> 评审 ”流程 评审通过,出问题大家一起背锅, 评审不通过,打回去修改 |
53
fml87 2021-08-27 16:39:46 +08:00
典型的眼高手低,场景又不复杂,这样搞只是白白增加维护成本
|
54
intmax2147483647 2021-08-27 16:40:08 +08:00
你不了解,就别瞎说。🤣
|
55
11232as 2021-08-27 16:40:35 +08:00
A 多对多 B,B 多对多 C
| B_id | A/C id | A/C 表名| | --- | --- | --- | | ... | ... | ... | 虽然有点怪但也没啥问题... |
56
cszchen 2021-08-27 16:40:46 +08:00 via iPhone
没看出来哪儿方便了,工作量不仅不会变小,可能还会变大,如果有可能就让他做简单的 curd,或者直接开掉
|
57
redford42 2021-08-27 16:40:56 +08:00
表设计还是评审一下吧
|
58
JoeBreeze 2021-08-27 16:47:51 +08:00
团队合作还是需要一些规范的, 他喜欢这样做, 然后其他人也大部分都认同, 打不过就加入吧, 后面有锅给他背就好了
|
59
egfegdfr 2021-08-27 16:50:49 +08:00
这么搞,在做删除、新增操作的时候,不容易产生死锁吗? 虽能说 可以通过加索引、或者是分布式锁控制,但是这个设计好几个业务逻辑,感觉这么设计的优点是小于缺点的
|
60
Carlgao 2021-08-27 16:54:58 +08:00
在多对多中间表里面加表名类型区分,可以减少中间表的数量,这属于常规操作吧。
|
61
drinke9 2021-08-27 16:55:10 +08:00
这种设计模式,laravel 框架中的一个权限包就是这种结构,`laravel-permission`
|
62
timethinker 2021-08-27 17:01:13 +08:00
看场景吧,一般角色对权限的是配置数据,数据量不大可以做缓存,更新的情况也比较少。甚至可以把角色对权限的这个关系直接通过配置文件存储起来,都不用存数据库。
而用户对角色的这部分数据是动态数据表,适合放到数据库中。话说回来,量变导致质变,不同的量级有不同的做法,条条大路通罗马。有规范的按照规范执行,没有的话按照简单的来做就行了,在没有规范的前提下就不要苛求太多。 |
63
0o0o0o0 2021-08-27 17:02:57 +08:00
关键是这逻辑是怎么想出来的,正常人第一次设计都会去网上搜索一下经验或者规范吧,所以说这是自己发明的神奇设计方法吗哈哈哈
|
64
charseer 2021-08-27 17:09:52 +08:00
一些参数表这样设计没啥问题,很好用的
|
65
Muyiafan 2021-08-27 17:13:19 +08:00
表中表中表中表中表中表
|
66
superrichman 2021-08-27 17:14:18 +08:00
@baoshijiagong 怕模型图最后画出来是个刺猬 /doge
|
67
Guidoo 2021-08-27 17:24:37 +08:00
好家伙 套娃 表中表中表中表中表中表中表中表中
|
68
aliveyang 2021-08-27 17:26:07 +08:00
他以为动态了,其实是乱搞
|
69
Leviathann 2021-08-27 17:47:48 +08:00 via iPhone
元编程是吧
|
70
conanforever22 2021-08-27 17:55:53 +08:00
他可能是觉得项目中有很多这种“类似”的关系, 不想建那么多表
感觉像我们平时分析某个业务场景, 经过思考,抽象出了一个精炼“通用”的结构;可能真的通用,能应对未来各种变化;也可能忽视了这些变化,然后各种 if...else...特殊处理 看表结构里他还建了很多预留字段,可能是考虑到某些关系可能会附加一些属性,如果能解决问题也没有性能问题,其他同事也能看懂没意见,管他呢... |
71
guisheng 2021-08-27 17:58:45 +08:00 via iPhone
个人觉得,这种做法在解决问题上是没有什么好说的。但是在可维护性上和可扩展性上 直接一巴掌拍死。
|
72
guanhui07 2021-08-27 18:01:41 +08:00 via Android
不合理
|
73
pepesii 2021-08-27 18:23:16 +08:00
这有点像 CASBIN 的 RBAC 模型呢
|
74
twing37 2021-08-27 18:41:31 +08:00
第一感觉是 casbin 的模型
|
75
konakona 2021-08-27 18:43:06 +08:00
这个表中表的设计必须是 1:1 的关系就是合理可用且没有诟病的,我指的是:
Aid | Bid | model | remark 1 | 2 | string | ... 比如 Aid 的 field name 可以是 permission_id,Bid 的 field name 可以是 model_id 或者 role_id,model 的 field name 可以是某种 type (比如 model_type 或者任何能够代表操作类的 field name 去说明它) 这个表不能复杂,最多就这么 3-4 个主要子段,因为它的定位应该是一个“中间表”。但……这也只是中间表,如果要在一个表里完成复杂的蛛网一般的交织,后续维护和理解成本(主要体现在陈长的代码里)会比较麻烦,不易维护和改造。 |
76
konakona 2021-08-27 18:45:07 +08:00
我看了看楼主的 append,这个小伙的做法好像没什么问题啊- - 很常规,很 ok 。建议看下 casbin 。。。
|
77
ericls 2021-08-27 19:22:03 +08:00 via iPhone
GenericForeignKey
|
78
mejee 2021-08-27 19:25:58 +08:00 via iPhone
感觉是建立了一个表达通用关系的表,如果是的话,可能也是很合适的
|
79
Casbin 2021-08-27 21:23:38 +08:00
这是 Casbin
|
81
mmdsun 2021-08-27 22:04:57 +08:00
还有表名称? 关系数据库 Mysql 这种要怎么查询 ?
|
82
seakingii 2021-08-27 22:14:56 +08:00
反直觉
不过就这个场景来说,是能满足要求的,也能扩展应用到所有这种简单多对多的其它表.数据量不大的话性能也不是问题 |
83
akira 2021-08-27 23:25:52 +08:00
这样的优点是 少创建一个表,嗯。 应该就这个了吧
|
84
l4ever 2021-08-28 10:06:55 +08:00
还行啊, 没啥毛病. 我更倾向于把所有配置全写一个表里面去.
``` CREATE TABLE `system_config` ( `id` mediumint UNSIGNED NOT NULL AUTO_INCREMENT, `userid` char(30) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', `module` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, `section` char(30) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', `key` char(30) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', `value` text CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, PRIMARY KEY (`id`) USING BTREE, UNIQUE INDEX `unique`(`userid`, `module`, `section`, `key`) USING BTREE ) ENGINE = MyISAM AUTO_INCREMENT = 2680 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; ``` |
85
cp19890714 2021-08-28 10:07:55 +08:00 via Android
谁最终为该系统负责,那就听谁的。当然,还是要以理服人,举例说明该方式在未来的隐患。
|
86
WilliamYang 2021-08-28 10:54:40 +08:00
从业 6 年了,某些人总能找到说服你和他自己的理由。你不是他上级,能听就听,不听就算了
|
87
chih758 2021-08-28 11:24:14 +08:00
不是本科毕业的?数据库的范式没学?
|
88
entro 2021-08-28 14:10:51 +08:00
真实,本公司项目某模块的表就是老板亲自用这种方式设计的#(笑)
|
89
hst001 2021-08-28 15:20:32 +08:00 via Android
数据量稍微多点,更新的时候就知道厉害了,后面让他再去拆表,长长教训
|
90
2i2Re2PLMaDnghL 2021-08-28 22:33:39 +08:00
重新发明图数据库
把不同表(实际上就是不同的命名空间)的 id 放在一起,需要保证表间 id 仍然唯一(实质达成命名空间合并)。 这种情况下 MySQL 性能可能捉鸡 |
91
TimPeake 2021-08-28 23:01:16 +08:00
套娃?
|
92
wqtacc 2021-08-28 23:23:06 +08:00
看起来是把角色权限和用户角色写到了一个表里?那描述应该是下面这样子?
id1 | id2 | 表名 角色 id1| 权限 id1 | 用户权限表名 角色权限? 角色 id1| 权限 id2 | 用户权限表名 角色权限? 角色 id2| 权限 id1 | 用户权限表名 用户 id1| 角色 id1 | 用户角色表名 用户 id1| 角色 id2 | 用户角色表名 |
93
Biwood 2021-08-28 23:31:18 +08:00
乍一看,还以为是什么数据库层面的高度抽象,专门存储表与表之间的关系?太高级了吧
看到“第一个 id”、“第二个 id”这里,有点懵逼了,这是用一个表解决整个系统的对应关系?有种用 0 和 1 写程序的感觉,按照这种写法,那数据库要“主键”、“外键”干嘛用 |
94
Biwood 2021-08-28 23:47:28 +08:00
@avastms
我一开始也以为像是你说的邻接表,把数据之间的关系存储起来,但是你在细读一下楼主的描述跟他的回复,根本没那么高大上,他是反向操作,纯粹是把三张表之间两两排列组合,把每一条关系都存储在一个表里面。 打个比方,就像你本来可以用 for 循环打印 10 次数据,他偏偏不用 for 循环,而是硬写了 10 次打印数据的代码。 |
95
changdy 2021-08-29 09:42:09 +08:00
|
96
encro 2021-08-29 20:21:57 +08:00
没有问题,
其实 yii 框架的默认 rbac 差不多也是这么建立的。基于 NIST RBAC model,性能没有问题,且可以多级用户角色和权限继承。 DbManager 使用 4 个数据库表存放它的数据: itemTable: 该表存放授权条目(译者注:即角色和权限)。默认表名为 "auth_item" 。 itemChildTable: 该表存放授权条目的层次关系。默认表名为 "auth_item_child"。 assignmentTable: 该表存放授权条目对用户的指派情况。默认表名为 "auth_assignment"。 ruleTable: 该表存放规则。默认表名为 "auth_rule"。 有个要求就是需要封装很好。 |
97
encro 2021-08-29 20:29:43 +08:00
下面是表结构,可以不考虑 rule 表
create table `auth_rule` ( `name` varchar(64) not null, `data` blob, `created_at` integer, `updated_at` integer, primary key (`name`) ) engine InnoDB; create table `auth_item` ( `name` varchar(64) not null, `type` smallint not null, `description` text, `rule_name` varchar(64), `data` blob, `created_at` integer, `updated_at` integer, primary key (`name`), foreign key (`rule_name`) references `auth_rule` (`name`) on delete set null on update cascade, key `type` (`type`) ) engine InnoDB; create table `auth_item_child` ( `parent` varchar(64) not null, `child` varchar(64) not null, primary key (`parent`, `child`), foreign key (`parent`) references `auth_item` (`name`) on delete cascade on update cascade, foreign key (`child`) references `auth_item` (`name`) on delete cascade on update cascade ) engine InnoDB; create table `auth_assignment` ( `item_name` varchar(64) not null, `user_id` varchar(64) not null, `created_at` integer, primary key (`item_name`, `user_id`), foreign key (`item_name`) references `auth_item` (`name`) on delete cascade on update cascade, key `auth_assignment_user_id_idx` (`user_id`) ) engine InnoDB; |
98
kiracyan 2021-08-30 09:44:51 +08:00
其实就是把多个 map 表合在一起了吧
|