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

作者: Shawlaw | 来源:发表于2016-12-31 22:09 被阅读127次

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

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

以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基本数据类型总结

相关文章

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

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

  • 数据库存储原理特性索引优化

    说一下mysql数据库存储的原理? 事务的特性? 数据库索引 数据库怎么优化查询效率? 数据库优化方案 优化索引、...

  • iOS 备忘录模式(简单使用)

    备忘录模式设计存储中心,指定存储接口,实现存储机制。优化存储方案统一存储规范,实现灵活多变的存储机制。 FastC...

  • 【键值数据库】和【时间系列数据库】与量化投资分析

    一、键-值储存 1.1、含义 键-值数据库,或键-值存储,是设计用来存储、检索和管理关联数组的数据存储范式,关联数...

  • Android存储优化

    存储方式 序列化 Sharepreferences优化 数据库使用及优化未完待续

  • decimal精确计算

    关系型数据库mysql中,存储10.00这个值,若以float类型存储,是10.0,若以int类型存储,是1...

  • SharedPreferences

    概述 源码分析 总结 一、概述 Android系统里面大致有三种数据存储方案: 文件存储。 数据库存储。 Shar...

  • 备忘录模式

    内容大纲 如何存储记录 备忘录模式的基本原理 使用备忘录模式 优化存储方案 恢复UIView的状态 1、如何存储记...

  • 【华为网络技术大赛】储存基础原理

    广义的存储 硬件存储系统 存储软件 存储网络 存储解决方案 存储方案 DAS(直接连接存储)早期 SAN(存储区域...

  • 源铸:数值处理问题

    一、数值存储计算方案 高精度浮点数 采用双精度浮点数是最简单的存储方案,数据库支持,编程语言也支持。只要数据库和编...

网友评论

    本文标题:数据库存储二元值的优化方案,位存储

    本文链接:https://www.haomeiwen.com/subject/bjacmttx.html