千家信息网

mysql分库分表和数据初始化迁移的方法

发表于:2024-12-12 作者:千家信息网编辑
千家信息网最后更新 2024年12月12日,这篇文章主要介绍"mysql分库分表和数据初始化迁移的方法",在日常操作中,相信很多人在mysql分库分表和数据初始化迁移的方法问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家
千家信息网最后更新 2024年12月12日mysql分库分表和数据初始化迁移的方法

这篇文章主要介绍"mysql分库分表和数据初始化迁移的方法",在日常操作中,相信很多人在mysql分库分表和数据初始化迁移的方法问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答"mysql分库分表和数据初始化迁移的方法"的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

  • 前言

分库分表,必不可少的步骤就是数据迁移。数据迁移又分两种,一种是初始化迁移,另一种是上线期间的数据迁移。这里先考虑的是初始化迁移。

何为初始化迁移?其实就是将老库的绝大部分数据转移到新库中,一般这种迁移都是针对的是固定的数据。

  • 场景

      1.停机迁移(不推荐)  2.数据双写迁移  3.采用canal中间件迁移


以上三种一般是数据迁移的方案。第一种和第三种场景中都有迁移固定量的数据的步骤。这里暂不说迁移的方案的优劣、选择和实现,后续再记录这些,我今天先记录一下我在初始化数据的时候碰到的问题以及解决的方案。

  • 问题

由于我想通过sql而非程序的方式来实现数据的初始化,因此这里碰到一个问题。

我需要通过hash来决定分到哪个库或者表,然而java的String类型有hashCode方法,那mysql呢?

经过一番查找之后,发现mysql并不支持hash方法,那咋办呢,只能通过存储过程来写一个自定义函数了。那就直接开始操作了!

  • 操作

由上图可知,java中String的hashCode这么实现的,关键点就是这行代码

h = 31 * h + val[i];

简单介绍下,他其实就是对字符串转成Char数组,然后进行循环。每次循环都对hash值 * 31,然后加上char的ASCII值。最后循环完成得到的值就是这个字符串最后的hashCode值。

那我们在mysql的自定义函数里面也按这个逻辑这么写就好了,如下:

DELIMITER $$CREATE FUNCTION hash_code (user_id VARCHAR(50)) RETURNS INTBEGINDECLARE result INT DEFAULT 0 ;DECLARE num INT DEFAULT 1 ;WHILE (num <= LENGTH(user_id)) DOSET result = result * 31 + ASCII(SUBSTRING(user_id, num, 1)) ;SET num = num + 1 ;ENDWHILE ;IF result < 0 THENSET result = result * - 1 ;ENDIF ; RETURN result ; END$$

但是经过测试了之后发现,超过了INT的范围了,尴尬。看来只能再优化下了。

然后发现java中超过INT范围之后,他会自己进行补码。举个易懂的例子,看如下代码:

    int num = 0;    for (int i = 0; ; i++) {        num++;        System.out.println(num);    }

上面的代码无限相加,打印出来的Num会是什么,有兴趣的大家可以试一下。

我这边先直接说结果,如下:

0 --> 1 --> 2 .... --> Integer.MAX_VALUE(2147483647) --> -2147483648 --> -2147483647 --> -2147483646 .... --> 2 --> 1 --> 0

是不是找到规律了?那就直接操作了!一步一步来,先来一个相同数相加的程序

DELIMITER $$CREATE FUNCTION int_add (num BIGINT) RETURNS BIGINTBEGINDECLARE result BIGINT ;SET result = num ;IF result >= 0 THENIF 2147483647 - result >= result THENSET result = result + result ;ELSESET result = (2147483648 - result) * - 2 ;ENDIF ;ELSEIF result >= - 1073741824 THENSET result = result + result ;ELSESET result = (- 2147483648 - result) * - 2 ;ENDIF ;ENDIF ; RETURN result ; END$$DELIMITER ;

写完发现自己有点蠢了,为了数字不超过INT的最大范围做了很多操作和判断,那我为啥不利用下BIGINT呢?超过INT也没事,超过之后再将他的数值更正回来即可。那就直接换个更简单的方法吧!

DELIMITER $$CREATE FUNCTION int_add_new (num BIGINT, addNum BIGINT) RETURNS BIGINTBEGINDECLARE result BIGINT ;SET result = num + addNum ;IF result > 2147483647 THENSET result = - 2147483648 + (result - 2147483648) ;ELSEIF result < - 2147483648 THENSET result = 2147483647 - (- 2147483649 - result) ;ENDIF ; RETURN result ; END$$DELIMITER ;

或者直接乘呢

DELIMITER $$CREATE FUNCTION int_multiply (num BIGINT, multiplyNum BIGINT) RETURNS BIGINTBEGINDECLARE result BIGINT ;SET result = (num * addNum) % (2147483648 * 2) ;IF result > 2147483647 THENSET result = - 2147483648 + (result - 2147483648) ;ELSEIF result < - 2147483648 THENSET result = 2147483647 - (- 2147483649 - result) ;ENDIF ; RETURN result ; END$$DELIMITER ;

嗯,确实看起来容易太多了。这一步ok了之后,接下去通过调用这个方法再去写HashCode方法就简单多啦,如下:

DELIMITER $$CREATE FUNCTION hash_code (user_id VARCHAR(50), hashNum INT) RETURNS INTBEGINDECLARE result BIGINT DEFAULT 0 ;DECLARE num INT DEFAULT 1 ;DECLARE tempNum INT;DECLARE tempResult BIGINT;WHILE (num <= LENGTH(user_id)) DOSET tempNum = 1 ;SET tempResult = result ;WHILE (tempNum <= 30) DOSET result = int_add_new (result, tempResult) ;SET tempNum = tempNum + 1 ;ENDWHILE ;SET result = int_add_new (    result,    ASCII(SUBSTRING(user_id, num, 1))) ;SET num = num + 1 ;ENDWHILE ;IF result < 0 THENSET result = result * - 1 ;ENDIF ; RETURN result % hashNum ; END$$DELIMITER ;

大功告成,直接试一下!

接下去和java程序对比一下,结果也对上啦,nice!

啊,突然想到如果大家碰到了这个问题的话

这个是因为没允许自定义函数,运行下下面的指令就ok拉!

set global log_bin_trust_function_creators=TRUE;

到此,关于"mysql分库分表和数据初始化迁移的方法"的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注网站,小编会继续努力为大家带来更多实用的文章!

0