在平时的开发过程中应该会遇到这种场景,一个对象有多个属性,每一个属性只有两个状态,但是构建对表时不得不为每一个属性定义一个字段,这样会使得这张表中有很多个字段,但是每个字段其实记录的数据很小【true/false】,字段的利用率非常低。
举个例子,比如一个论坛网站要记录用户的浏览兴趣喜好,在初次注册登录会让用户选择感兴趣的新闻类型,比如有游戏、体育、汽车、军事、生活、情感、娱乐、财经、科技、历史、足球、图片、动漫、公益等, 这里我仅仅列举其中一部分而已,真实的大概还有几十个,那按照为每一个类型创建一个字段的话,那么这张用户兴趣表将会是一种超级宽的表,而且如果要新增兴趣类型的话,就得在表中新增一个字段,这种设计灰常反人类,很难维护。
聪明的你可能想到了一种方案,给每一个类型分配一个code,比如,游戏=1,体育=2,汽车=3,军事=4,生活=5。。。。。。,然后将用户选择的每一个code拼接起来,这样的话表就只需要一个字段了,把拼接起来的字符串放在这个字段上就OK了。但是存在一个问题,这个字段的长度要设置的足够大,因为要从分考虑到用户全部选择的极端情况,虽然这部分人的占比很小,但是就是为了这一小部分人的极端需求就要将这个字段的空间设置的很大 ,浪费很多空间,代价有点大,而且还得考虑新增兴趣类型可能带来的这个字段长度的变更。
这里我们可以通过 "位"来帮助我们解决这类问题。我们得给每一个属性分配一个code,如下
public class Topic {
private static long GAME = 1; //游戏
private static long GYM = 2<<1;//体育
private static long CAR = 2<<2;//汽车
private static long MILITARY = 2<<3;//军事
private static long LIFE = 2<<4;//生活
private static long EMOTION = 2<<5;//情感
private static long ENTERTAINMENT = 2<<6;//娱乐
private static long FINANCE = 2<<7;//财经
private static long SCIENCE = 2<<8;//科学
private static long HISTORY = 2<<9;//历史
private static long BALL = 2<<10;//足球
private static long PIC = 2<<11;//图片
}
如果有一个用户选得兴趣为游戏、足球、体育、图片,那么这个用户得兴趣汇合的实例为:
long topics = GAME | BALL |GYM |PIC;
其值为 1 |2 |2<<10|2<<11 = 6147, 只需要将6147这个值存在数据库创建的那个字段上就OK了,6147这个数据保存了当前用户选择的四个兴趣【游戏、足球、体育、图片】。而且表中这个字段的长度是固定的,因为 long类型是八个字节,对应到数据库应该是使用bigint就可以了。完全不用考虑增加兴趣类型的情况。灰常好用。