数据库存储二元值的优化方案,位存储

在进行应用开发的时候,相信总是会有些数据的数据结构中含有一些二元属性,如该条记录是否对用户可见、是否为待办记事等等。而这些属性也是需要存到数据库中的。

那这样的属性,在内存中使用的数据结构中可能表现为一个布尔值,存到数据库中还能是布尔类型吗?

以Android开发为例,Android中使用的数据库系统是SQLite,SQLite支持的存储格式根据官网的文档[1] 有如下这些:

官网文档截图

可以看到并没有布尔类型这种存储格式,所以开发人员常常都是用一个Integer的字段来存储一个布尔值属性。既然数据库都用了Integer,许多开发人员也就把数据结构中的boolean也改成了int。

但是在Java中,一个boolean只占一个二进制位,而一个int占了32个二进制位[2] 。整整差了31倍!那这样子的使用未免也太浪费了吧!

既然一个int都能存32位,那就直接用一个int值来存32个二元属性。一般的数据结构都不会用到那么多个二元属性,哪怕是进行了多次业务升级之后。而且我觉得吧,如果真的用到了那么多二元属性,建议重新考虑数据结构设计的合理性。

实现的方式很简明易懂,位运算。先上工具类代码。

/**
 * 用于帮助开发者在数据结构中使用Int值存储二元属性的工具类
 * Created by Shawlaw on 2016/12/4.
 */

public class BitHelper {
    /**
     * 给指定的int数值的特定位置0或置1
     * @param src 用于存储二元值的int数
     * @param bitMask 指定位的掩码,可通过{@link #getDeterminedBitMask(int)}取得指定位的对应掩码
     * @param bitValue 要给指定位设定的值
     * @return 置值完毕后的int数
     */
    public static int setDeterminedBit(int src, int bitMask, boolean bitValue){
        if (bitValue) {
            src |= bitMask;
        } else {
            src &= (~bitMask);
        }
        return src;
    }

    /**
     * 取得指定的int数值中的特定位上的值
     * @param src 用于存储二元值的int数
     * @param bitMask 指定位的掩码,可通过{@link #getDeterminedBitMask(int)}取得指定位的对应掩码
     * @return 指定位的值是否为1,为1则返回true,为0则返回false
     */
    public static boolean getDeterminedBit(int src, int bitMask){
        return (src & bitMask ) != 0;
    }

    /**
     * 获取int数的指定位的位运算掩码,一般配合{@link #getDeterminedBit(int, int)}或{@link #setDeterminedBit(int, int, boolean)}方法一起使用
     * @param reverseIndex 从最右即最低位为1数起的位数,最大为32,因为int数为4字节最大32位。
     * @return 位运算掩码
     */
    public static int getDeterminedBitMask(int reverseIndex){
        if (reverseIndex > 32 || reverseIndex < 1) {
            throw new RuntimeException("Index must between 1 to 32. The current index is "+reverseIndex);
        }
        return 1 << (reverseIndex - 1);
    }
}

工具类里面一共就三个方法,分别用于设置特定位的值、取特定位的值以及取特定位的运算掩码。
使用样例代码,如下:

public class MyModel{
    private boolean mIsNewUser;
    private boolean mIsRedDotShowed;

    private int mBitStatus;

    private final static int IS_NEW_USER_BIT_MASK = BitHelper.getDeterminedBitMask(1);
    private final static int IS_RED_DOT_SHOWED_BIT_MASK = BitHelper.getDeterminedBitMask(2);

    /**
     * 从数据库或网络请求取到数据**之后**,执行这个方法,从数值中解析各个位的状态到内存中的boolean值中。
     */
    public void restoreStatusFromInt(){
        mIsNewUser = BitHelper.getDeterminedBit(mBitStatus, IS_NEW_USER_BIT_MASK);
        mIsRedDotShowed = BitHelper.getDeterminedBit(mBitStatus, IS_RED_DOT_SHOWED_BIT_MASK);
    }

    /**
     * 要写入数据库或发网络请求**之前**,执行这个方法,把内存中的boolean值写入到数值中。
     */
    public void storeStatusToInt(){
        mBitStatus = BitHelper.setDeterminedBit(mBitStatus, IS_NEW_USER_BIT_MASK, mIsNewUser);
        mBitStatus = BitHelper.setDeterminedBit(mBitStatus, IS_RED_DOT_SHOWED_BIT_MASK, mIsRedDotShowed);
    }
   ....省略了通用的Setter和Getter方法....
}

讲完了源代码和样例代码,再来说说这样实现的优点和缺点。
优点:

  1. 节省空间耗费。
  2. 业务弹性强,尤其是当内存数据结构发生多次变化时,数据库表头不用同样地多次更改。

缺点: 对代码调用次序有硬性要求。

所以使用的时候还是得根据开发需求来确定要不要这样实现。


参考文献:
[1] Datatypes In SQLite Version 3
[2] Java基本数据类型总结

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,053评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,527评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,779评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,685评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,699评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,609评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,989评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,654评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,890评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,634评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,716评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,394评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,976评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,950评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,191评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,849评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,458评论 2 342

推荐阅读更多精彩内容