场景:咱不知道其他人是什么场景用它的,咱也不知道当初为啥要用这个,但是既然这个用到这个了,那咱就说道说道吧。项目中用到的场景是客户招揽中有多个任务类型,分为首保、定保、保修、保险、召回、主题等,一共这么多种类型,然后它在查询的时候会有这样一种场景,它可能会查既是首保,又是保险的任务类型,也有可能查询既是首保、保修,同时又是主题的任务类型。也就是说他查询的任务类型不只是这一种,他可能出现同时查很多种的情况。那么这个时候怎么做呢?位图就为这个提供了一种解决问题的思路。
算法:
假如有几种类型,分别是首保、定保、保修、保险、维修、主题
定义一个常量,将上面的六种类型分别用二进制位表示出来,
如:首保 = 1<<0(00000001),定保= 1<<1(00000010),保修 = 1<<2(00000100),
保险 = 1<<3(0001000),维修 = 1<<4(00010000),主题 = 1<<5(00010000)
假如前端插入的时候选择了 首保、定保两种类型的数组,那么存的时候不能存 首保和定保,这时候需要将它们做转化,根据上面的每种类型的二进制数字,转化成一个数字存到数据库中。
如果要查包含某种类型的数据,遵照相与原则还等于这个数来判断。
计算数组,将数组值转为存进数据库的值:
public static synchronized Integer orArray(List<Integer>list) {
flag=0;
for(int index=0; index<list.size(); index++) {
flag = (1 << (list.get(index).intValue()-1)) | flag;
}
return flag;
}
上面算出的值是存到数据库的结果.
下面就是如何通过查找来查出来了,根据上面的相与原则,首先也是要将前端传来的类型进行处理,首先左移成二进制,变成我们上面的 00000001 这种形式,再转为十进制与数据库中存的数据作对比:
public static synchronized Integer getDataByCardEnum(CardTypeEnum cardTypeEnum){
return 1 << (cardTypeEnum.getNum() - 1);
}
上面就将数据转换好了,最后根据相与原则与数据库中的作对比:
程序中用MP的方式, 为了方便我只展示了作比较的那一行:
wrapper.eq("last_solicit_task_code_num&"+taskTypeValue+"",taskTypeValue);
其中last_solicit_task_code_num数据库中的值就是开始插入时候存入的值,taskTypeValue就是我们查询时前端传入并经我们转换之后的值,相与后等于taskTypeValue,则数据库中的这条数据就是包含我们查询条件的数据。
PS: 写的可能不太清楚,后面是二进制转换后比较的举例, 希望可以协助大佬们理解:
首保 = 1<<0(00000001,1),定保= 1<<1(00000010,2),保修 = 1<<2(00000100,3),保险= 1<<3(00010000,4),维修 = 1<<4(00010000,5),主题= 1<<5(00010000,6)
包含 首保、定保,存到数据库中是3,用二进制表示为:
00000011
查询包含 首保 的,首保是1,用二进制表示为:
00000001
那么根据相与原则,同位为1,异位为0可得
00000011
00000001
——————
00000001
由上最后得出的结果还是为首保,所以该数据包含首保;
假如我查询包含 保险 的,保险是4,用二进制表示为:
00010000
那么
00000011
00010000
——————
00000000
得到的值为0,说明该数据不包含保险。