一种多选项的高效存取(存储、查询)办理方案 [复制链接]
发表于 2026-2-3 21:26:10 | 显示全部楼层 |阅读模式
本文重要内容

  • 对于多选项的值,怎样生存?本文提供了一种非通例的方案。
  • 对于记载在数据库中的多选项的值,怎样快速查询那些记载是包罗了某个(某些)选项?本文利用了“与位运算”办理查询标题。
  • 源码地点:https://github.com/HackyleShawe/JavaBackEndDemos/tree/master/BusinessCommonSolution/multi-options-storage-query-demo
文章前置知识:SpringBoot、JDBCTemplate、位运算(与运算)、jQuery
内容导览 
配景

在项目开发中,怎样生存多选项的值呢?比方下图中的职业发展和爱好爱好


  • 最容易想到的就是,选择了哪些选项,就把该选项值存储起来。
  • 数据库层面设置一个VARCHAR,比方选择了"收入无上线、培训与发展、职业代价感",前端就转达"收入无上线、培训与发展、职业代价感",数据库就生存为"收入无上线、培训与发展、职业代价感"。
但是如许存在一个标题,我要查询那些人选择了此中的某个、某些选项,就很难实现。比方,查询那些人的爱好爱好是"编程、篮球",查询爱好爱好是"看书、写作"的人数有多少。
为相识决这种多选项的高效查询标题,本人计划了一种方法,可以实现快速、高效地查询多选项中有某个、某些选项的全部记载。
计划头脑

焦点思绪:

  • 编码:将每个选项与特定的比特位上对应起来,选中为1,未选中为0
  • 存储:将比特位转换为Long型(64bit,最大支持64个多选项),数据库表字段为BIGINT
  • 查询:与(&)位运算
重要流程

  • 编码:将多选项举行编号

    • 比方:对职业发展的多选项举行编号为:1-收入无上限,2-培训与发展,3-职业代价感,4-行业稳固性,5-外交与人脉,6-塑造个品行牌,7-团队综合素质,8-终身学习;
    • 对爱好爱好的多选项举行编号为:1-编程,2-听音乐唱歌,3-篮球,4-玩游戏,5-看影戏,6-享美食,7-健身,8-旅游,9-看书,10-写作。

  • 存储

    • 前端:选择了哪些选项,就转达哪些选项的编号。比方:选择了"编程、篮球",则转达的编号串为:"1,3"
    • 后端:将编号串转换为二进制串,再转换为数字,落库

  • 查询:前端还是只传选项编号;后端将其转换为数字;在数据库层面利用位运算中的与运算,匹配包罗了参数选项的记载。
编码:将多选项转换为数字

现以爱好爱好为例,为其多选项界说编号:1-编程,2-听音乐唱歌,3-篮球,4-玩游戏,5-看影戏,6-享美食,7-健身,8-旅游,9-看书,10-写作
根据二进制位下标与十进制数的互转:

例1

用户A勾选的爱好爱好为:"1-编程,2-听音乐唱歌,5-看影戏,6-享美食"
前端转达的串为:1,2,5,6
转换为二进制串:0011 0011
转换规则:在有选项编号出现的位下标的位置上添补1,其他位置添补0
转换为十进制后落库:51

例2

用户B勾选的爱好爱好为:"3-篮球,4-玩游戏,6-享美食,7-健身,10-写作"
前端转达的串为:3,4,6,7,10
转换为二进制串:0010 0110 1100
转换为十进制后落库:620

查询原理

查询的焦颔首脑:与(&)位运算

  • X & Y = X,则分析X的全部值为"1"的二进制位、在Y中对应的二进制位也为"1"。
  • 也就是说,Y为"1"的二进制位包罗了X的全部为"1"的二进制位。从而实现了,查询条件X,在Y中存在(包罗)


项目启动

Step 1:在application.yml中修改数据库毗连参数
Step 2:实行resources/sql.sql下的SQL文件,初始化数据
Step 3:从启动类App.java启动
Step 4:启动乐成后进入前端页面:http://localhost:9898/person.html
新增数据演示

须要数据,多选项举行勾选:

去数据库检察刚刚新增的记载:

查询数据演示

选择查询条件,点击“Query”举行查询:

检察运行日记,表现实行的SQL:

查询示例

以多选项”爱好爱好“为例,展示查询的工作原理
构造数据

AA选择了"1-编程,2-听音乐唱歌,5-看影戏,6-享美食,7-健身,8-旅游"
前端转达的编号串:1,2,5,6,7,8
转换为二进制串:0000 1111 0011
转换为数字:243
BB选择了"3-篮球,4-玩游戏,8-旅游,9-看书,10-写作"
前端转达的编号串:3,4,8,9,10
转换为二进制串:0011 1000 1100
转换为数字:908
CC选择了"2-听音乐唱歌,3-篮球,5-看影戏,6-享美食,7-健身,9-看书,10-写作"
前端转达的编号串:2,3,5,6,7,9,10
转换为二进制串:0011 0111 0110
转换为数字:886
DD选择了"1-编程,3-篮球,4-玩游戏,6-享美食,7-健身,8-旅游,10-写作"
前端转达的编号串:1,3,4,6,7,8,10
转换为二进制串:0010 0110 1101
转换为数字:749
EE选择了"2-听音乐唱歌,4-玩游戏,5-看影戏,7-健身,8-旅游,10-写作"
前端转达的编号串:2,4,5,7,8,10
转换为二进制串:0010 1101 1010
转换为数字:730
FF选择了"1-编程,2-听音乐唱歌,3-篮球,4-玩游戏,5-看影戏,7-健身"
前端转达的编号串:1,2,3,4,5,7
转换为二进制串:0000 0101 1111
转换为数字:95
GG选择了"1-编程,3-篮球,4-玩游戏,6-享美食,8-旅游,10-写作"
前端转达的编号串:1,3,4,6,8,10
转换为二进制串:0010 1010 1101
转换为数字:685
插入到数据库
  1. DROP TABLE IF EXISTS person;
  2. CREATE TABLE person (
  3.     id BIGINT AUTO_INCREMENT,
  4.     name VARCHAR(50) DEFAULT NULL COMMENT '姓名',
  5.     gender INT DEFAULT NULL COMMENT '性别,0-女,1-男',
  6.     address VARCHAR(128) DEFAULT NULL COMMENT '地址',
  7.     careers BIGINT DEFAULT NULL COMMENT '职业发展多选项',
  8.     -- 兴趣爱好多选项。可选项:1-编程,2-听音乐唱歌,3-篮球,4-玩游戏,5-看电影,6-享美食,7-健身,8-旅游,9-看书,10-写作。
  9.     -- 例如,全选:"11 1111 1111",保存为十进制=1023,全不选:"00 0000 0000",保存为十进制=0,只选择听音乐唱歌:"0000 0010",保存为十进制=2
  10.     -- LONG最大支持64位,最多支持64个多选项的任意选择
  11.     interests BIGINT DEFAULT NULL COMMENT '兴趣爱好多选项',
  12.     create_time DATETIME DEFAULT NULL,
  13.     update_time DATETIME DEFAULT NULL,
  14.     deleted INT DEFAULT 0 COMMENT '是否删除:0-否,1-是',
  15.     PRIMARY KEY(id)
  16. );
复制代码
  1. -- 将上文中构造的数据,以SQL的形式插入到数据库中,只以多选项"兴趣爱好"为例
  2. INSERT INTO person(name, gender, address, careers, interests, create_time, update_time, deleted)
  3. VALUES ('AA', 1, 'SH CN', 1, 243, '2022-12-12','2023-12-12', 0),
  4.        ('BB', 1, 'SH CN', 1, 908, '2022-12-12','2023-12-12', 0),
  5.        ('CC', 1, 'SH CN', 1, 886, '2022-12-12','2023-12-12', 0),
  6.        ('DD', 1, 'SH CN', 1, 749, '2022-12-12','2023-12-12', 0),
  7.        ('EE', 1, 'SH CN', 1, 730, '2022-12-12','2023-12-12', 0),
  8.        ('FF', 1, 'SH CN', 1, 95, '2022-12-12','2023-12-12', 0),
  9.        ('GG', 1, 'SH CN', 1, 685, '2022-12-12','2023-12-12', 0);
复制代码
查询选择了"1-编程"这个选项的记载

目标:在多选项中查询选择了"1-编程"这个选项的记载
用户的"爱好爱好"多选项(二进制情势)
AA: 0000 1111 0011
BB: 0011 1000 1100
CC: 0011 0111 0110
DD: 0010 0110 1101
EE:  0010 1101 1010
FF:  0000 0101 1111
GG: 0010 1010 1101
将"1-编程"举行转换

  • 转换为二进制:0000 0000 0001
  • 转换为十进制:1
查询原理:将查询条件"0000 0000 0001"与AA~GG的二进制位举行与运算后,仍旧为查询条件的记载,则是选择了"1-编程"这个选项的记载
查询过程

  • 将查询条件与AA的二进制位举行与运算:
  1.    0000 0000 0001
  2. &  0000 1111 0011
  3. #--------------------------
  4.    0000 0000 0001  与运算结果仍为查询条件,说明这条记录包含了"1-编程"这个选项
复制代码

  • 将查询条件与BB的二进制位举行与运算:
  1.    0000 0000 0001
  2. &  0011 1000 1100
  3. #----------------------------
  4.    0000 0000 0000   与运算结果不为查询条件,说明这条记录不包含了"1-编程"这个选项
复制代码

  • 其他记载运算同理
  • 终极发现只有AA、DD、FF、GG的运算效果符合条件,这四个记载就是满意"选择了1-编程这个选项的全部记载"
SQL实现
  1. select * FROM person WHERE interests & 1 = 1;
复制代码

查询选择了"2-听音乐唱歌,5-看影戏"这些选项的记载

目标:在多选项中查询选择了"2-听音乐唱歌,5-看影戏"这些选项的记载
用户的"爱好爱好"多选项(二进制情势)
AA: 0000 1111 0011
BB: 0011 1000 1100
CC: 0011 0111 0110
DD: 0010 0110 1101
EE:  0010 1101 1010
FF:  0000 0101 1111
GG: 0010 1010 1101

将"2-听音乐唱歌,5-看影戏"举行转换

  • 转换为二进制:0000 0001 0010
  • 转换为十进制:18
查询原理:将查询条件"0000 0001 0010"与AA~GG的二进制位举行与运算后,仍旧为查询条件的记载,则是选择了"2-听音乐唱歌,5-看影戏"这个选项的记载
查询过程

  • 将查询条件与AA的二进制位举行与运算:
  1.   0000 0001 0010
  2. & 0000 1111 0011
  3. #--------------------------
  4.    0000 0001 0010  与运算结果仍为查询条件,说明这条记录包含了"2-听音乐唱歌,5-看电影"这些选项
复制代码

  • 将查询条件与BB的二进制位举行与运算:
  1.   0000 0001 0010
  2. & 0011 1000 1100
  3. #----------------------------
  4.   0000 0000 0000   与运算结果不为查询条件,说明这条记录不包含了"2-听音乐唱歌,5-看电影"这些选项
复制代码

  • 其他记载运算同理
  • 终极发现只有AA、CC、EE、FF的运算效果符合条件,这四个记载就是满意"选择了2-听音乐唱歌,5-看影戏这些选项的全部记载"
SQL实现
  1. select * FROM person WHERE interests & 18 = 18;
复制代码

 

免责声明:如果侵犯了您的权益,请联系站长及时删除侵权内容,谢谢合作!qidao123.com:ToB企服之家,中国第一个企服评测及软件市场,开放入驻,技术点评得现金.

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表