如何在SQLite中表示权限标志集合?C++数据类存储场景咨询
嘿,这个场景我之前做过类似的实现,针对你的Dialog类和Permission枚举,在SQLite里存储权限集合主要有三种靠谱的方案,我给你逐个拆解清楚:
方案1:用关联表存储(最推荐,符合数据库设计范式)
这是最标准的关系型数据库做法,完美适配多对多的场景(一个Dialog对应多个Permission,一个Permission也可以对应多个Dialog),扩展性拉满,后续加新权限或者统计权限使用情况都很方便。
首先你需要建两张表:
- 一张存Dialog的基础信息
- 另一张存Dialog和Permission的关联关系
SQL建表语句如下:
-- 存储Dialog的主表 CREATE TABLE dialogs ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL UNIQUE -- 可以加个UNIQUE约束避免重名Dialog ); -- 存储Dialog与Permission的关联表,主键是dialog_id+permission的组合,避免重复关联 CREATE TABLE dialog_permissions ( dialog_id INTEGER NOT NULL, permission INTEGER NOT NULL, PRIMARY KEY (dialog_id, permission), -- 外键关联,删除Dialog时自动删除对应的权限关联 FOREIGN KEY (dialog_id) REFERENCES dialogs(id) ON DELETE CASCADE );
举个例子,如果你有一个名为"ProjectDialog"的Dialog,拥有CAN_EDIT和CAN_RENAME权限,操作步骤是:
- 先插入Dialog到
dialogs表,拿到对应的id - 往
dialog_permissions表插入两条记录:(dialog_id, 1)和(dialog_id, 3)(对应你的枚举值)
查询的时候,用JOIN就能把Dialog和它的权限关联起来:
SELECT d.name, dp.permission FROM dialogs d JOIN dialog_permissions dp ON d.id = dp.dialog_id WHERE d.name = 'ProjectDialog';
方案2:位掩码存储(适合权限固定且数量少的场景)
如果你的权限列表确定不会频繁变动,而且数量不多(最多64个,因为SQLite的INTEGER是64位),用位掩码会非常高效,存储和查询都快。
不过这里要先调整下你的枚举值,把每个权限对应2的幂次,这样才能用位运算组合:
enum class Permission { CAN_EDIT = 1 << 0, // 对应数值1 CAN_DELETE = 1 << 1, // 对应数值2 CAN_RENAME = 1 << 2 // 对应数值4 };
然后建表的时候只需要一个permissions字段存整数:
CREATE TABLE dialogs ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, permissions INTEGER NOT NULL DEFAULT 0 -- 默认0表示无权限 );
存储时,把多个权限用位或运算组合成一个整数:比如同时有CAN_EDIT和CAN_RENAME,就是1 | 4 = 5,直接存5就行。
查询某个权限是否存在时,用位与运算判断:
-- 查询所有拥有CAN_EDIT权限的Dialog SELECT * FROM dialogs WHERE (permissions & 1) != 0;
这个方案的缺点是不够直观,权限多了之后很难直接看数值知道有哪些权限,而且新增权限时得保证是新的2的幂次,扩展性不如关联表。
方案3:JSON数组存储(SQLite 3.9.0+支持,最省心的方案)
如果你的项目数据量不大,而且不想折腾多表关联,直接用SQLite的JSON支持把权限存成数组就行,非常省心。
建表语句:
CREATE TABLE dialogs ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, permissions JSON NOT NULL -- 直接用JSON类型存储权限数组 );
插入时可以直接存数值数组或者枚举名字数组:
-- 存数值数组 INSERT INTO dialogs (name, permissions) VALUES ('ProjectDialog', json('[1,3]')); -- 存枚举名字数组(更直观) INSERT INTO dialogs (name, permissions) VALUES ('ProjectDialog', json('["CAN_EDIT","CAN_RENAME"]'));
查询时用SQLite的JSON函数过滤:
-- 查询拥有CAN_EDIT权限的Dialog(数值版) SELECT * FROM dialogs WHERE json_contains(permissions, '1'); -- 查询拥有CAN_EDIT权限的Dialog(名字版) SELECT * FROM dialogs WHERE json_contains(permissions, '"CAN_EDIT"');
这个方案的优点是实现简单,不需要额外表,但查询性能不如前两种,尤其是数据量大的时候,而且JSON没有强类型约束,容易存错格式。
最后给你个选型参考:
- 长期维护、权限可能扩展 → 选关联表
- 权限固定、追求性能 → 选位掩码
- 快速实现、数据量小 → 选JSON数组
内容的提问来源于stack exchange,提问作者Megamozg

