分库分表(3)--分库分表的策略

1.Hash扰动函数解读

1.1 计算hash扰动函数值

static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }

如上HashMap中的hash扰动函数源码,首先,通过hashcode算出key的哈希值h,然后再将算出的h右移16位(int 为32bits,因此此步骤只是将高16移至低16位,高16位补0),最后将h与右移的值进行异或计算(值相同结果为0,不同结果为1)。过程如下图3-1

图 3-1

为什么要向右移动16位,在正常情况下,我们的集合大小都不会很大。因此,我们一般只会使用到低16位((数组长度-1)&hash)。因此,右移16位保留了低16位的信息,也尽量保留了高16位的信息。最后通过(h = key.hashCode()) ^ (h >>> 16),原始的信息都尽量保存在了低16位。

1.2 计算hash在数组中的映射

  (first = tab[(n - 1) & hash]) != null) {

如上hashmap源码,最后通过hash的值与数组长度-1求出数组下标。

为什么要与上数组长度减一?1.因为hash值为32位(-2^32 - 2^31),所以值范围很大。只有与上数组长度减一才能更好的映射到数组中。

为什么源码中数组长度为2得n次幂?首先,因为0&任何值都是0,所以当某位为0时,0与上任何值不会改变结果,会导致大量碰撞(1110&1111 == 1110 &1110,15与16产生了碰撞),因此希望(数组长度-1)每一位尽量为一。

2. 项目中实际运用

     int idx = (tableSum - 1) & (dbKeyAttr.hashCode() ^ (dbKeyAttr.hashCode() >>> 16));
//        3.根据下/每个数据库的表数,求出第几个数据库
        int dbIdx = idx / dbRouterProperties.getTbCount() + 1;
//        3.根据第几个数据库,再算出第一个表
        int tbIdx = idx % dbRouterProperties.getTbCount();
//        4.通过上下文保存数据的信息
        // 设置库表信息到上下文,String.format("%02d", dbIdx),数据不为两位的话则在前面补0,这里的策略主要和设置的库表名称有关
        // 例如: 库名称为test_01 那就写%02d。表名称user_001 对应%03d
        DBContext.setDBKey(String.format("%02d", dbIdx));
        DBContext.setTBKey(String.format("%03d", tbIdx));

项目源码解读:

idx / dbRouterProperties.getTbCount() + 1;分库数据库是从1开始编号,所以要加一。

int tbIdx = idx % dbRouterProperties.getTbCount();这里应该要加一,因为表也是从1开始。DBContext.setDBKey(String.format("%02d", dbIdx));通过ThreadLocal保存,方便上下文调用。

引用:HashMap 计算 Hash 值的扰动函数_hashmap扰动函数-CSDN博客

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值