您好,登錄后才能下訂單哦!
這篇文章主要介紹“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 INT BEGIN DECLARE result INT DEFAULT 0 ; DECLARE num INT DEFAULT 1 ; WHILE (num <= LENGTH(user_id)) DO SET result = result * 31 + ASCII(SUBSTRING(user_id, num, 1)) ; SET num = num + 1 ; END WHILE ; IF result < 0 THEN SET result = result * - 1 ; END IF ; 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 BIGINT BEGIN DECLARE result BIGINT ; SET result = num ; IF result >= 0 THEN IF 2147483647 - result >= result THEN SET result = result + result ; ELSE SET result = (2147483648 - result) * - 2 ; END IF ; ELSE IF result >= - 1073741824 THEN SET result = result + result ; ELSE SET result = (- 2147483648 - result) * - 2 ; END IF ; END IF ; RETURN result ; END$$ DELIMITER ;
寫完發現自己有點蠢了,為了數字不超過INT的最大范圍做了很多操作和判斷,那我為啥不利用下BIGINT呢?超過INT也沒事,超過之后再將他的數值更正回來即可。那就直接換個更簡單的方法吧!
DELIMITER $$ CREATE FUNCTION int_add_new (num BIGINT, addNum BIGINT) RETURNS BIGINT BEGIN DECLARE result BIGINT ; SET result = num + addNum ; IF result > 2147483647 THEN SET result = - 2147483648 + (result - 2147483648) ; ELSEIF result < - 2147483648 THEN SET result = 2147483647 - (- 2147483649 - result) ; END IF ; RETURN result ; END$$ DELIMITER ;
或者直接乘呢
DELIMITER $$ CREATE FUNCTION int_multiply (num BIGINT, multiplyNum BIGINT) RETURNS BIGINT BEGIN DECLARE result BIGINT ; SET result = (num * addNum) % (2147483648 * 2) ; IF result > 2147483647 THEN SET result = - 2147483648 + (result - 2147483648) ; ELSEIF result < - 2147483648 THEN SET result = 2147483647 - (- 2147483649 - result) ; END IF ; RETURN result ; END$$ DELIMITER ;
嗯,確實看起來容易太多了。這一步ok了之后,接下去通過調用這個方法再去寫HashCode方法就簡單多啦,如下:
DELIMITER $$ CREATE FUNCTION hash_code (user_id VARCHAR(50), hashNum INT) RETURNS INT BEGIN DECLARE result BIGINT DEFAULT 0 ; DECLARE num INT DEFAULT 1 ; DECLARE tempNum INT; DECLARE tempResult BIGINT; WHILE (num <= LENGTH(user_id)) DO SET tempNum = 1 ; SET tempResult = result ; WHILE (tempNum <= 30) DO SET result = int_add_new (result, tempResult) ; SET tempNum = tempNum + 1 ; END WHILE ; SET result = int_add_new ( result, ASCII(SUBSTRING(user_id, num, 1)) ) ; SET num = num + 1 ; END WHILE ; IF result < 0 THEN SET result = result * - 1 ; END IF ; RETURN result % hashNum ; END$$ DELIMITER ;
大功告成,直接試一下!
接下去和java程序對比一下,結果也對上啦,nice!
啊,突然想到如果大家碰到了這個問題的話
這個是因為沒允許自定義函數,運行下下面的指令就ok拉!
set global log_bin_trust_function_creators=TRUE;
到此,關于“mysql分庫分表和數據初始化遷移的方法”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。