在實現分庫分表的情況下,數據庫自增主鍵已無法保證自增主鍵的全局唯一。為此,MyCat 提供了全局sequence,並且提供了包含本地配置和數據庫配置等多種實現方式。
本地文件方式
原理:此方式MyCAT將sequence配置到文件中,當使用到sequence中的配置後,MyCAT會更下conf中的sequence_conf.properties文件中sequence當前的值。
譬如:
#default global sequence GLOBAL.HISIDS= GLOBAL.MINID=10001 GLOBAL.MAXID=20000 GLOBAL.CURID=10000
其中HISIDS表示使用過的歷史分段(一般無特殊需要可不配置),MINID表示最小ID值,MAXID表示最大ID值,CURID表示當前ID值。
使用方式:
在server.xml中配置如下:
<system><property name="sequnceHandlerType">0</property></system>
其中0,表示使用本地文件方式。
測試如下:
mysql> create table test(id int,name varchar(20)); Query OK, 0 rows affected (0.13 sec) mysql> insert into test(id,name) values(next value for MYCATSEQ_GLOBAL,@@hostname); Query OK, 1 row affected, 1 warning (0.03 sec) mysql> select * from test; +-------+--------------+ | id | name | +-------+--------------+ | 10001 | mysql-slave2 | +-------+--------------+ 1 row in set (0.02 sec)
此時,sequence_conf.properties中GLOBAL.CURID值為10001。當然,可以使用sequence_conf.properties中定義的任何規則,譬如:
# self define sequence COMPANY.HISIDS= COMPANY.MINID=1001 COMPANY.MAXID=2000 COMPANY.CURID=1000
mysql> insert into test(id,name) values(next value for MYCATSEQ_COMPANY,@@hostname); Query OK, 1 row affected, 1 warning (0.02 sec) mysql> select * from test; +-------+--------------+ | id | name | +-------+--------------+ | 10001 | mysql-slave1 | | 1001 | mysql-slave1 | +-------+--------------+ 2 rows in set (0.10 sec)
這個可自定義。
數據庫方式
原理
在數據庫中建立一張表,存放sequence名稱(name),sequence當前值(current_value),步長(increment int類型每次讀取多少個sequence,假設為K)等信息;
Sequence獲取步驟:
1).第一次使用該sequence時,根據傳入的sequence名稱,從數據庫這張表中讀取current_value,和increment到MyCat中,並將數據庫中的current_value設置為原current_value值+increment值(實現方式是基於後續的存儲函數)
2).MyCat將讀取到current_value+increment作為本次要使用的sequence值,下次使用時,自動加1,當使用increment次後,執行步驟1)相同的操作.
MyCat負責維護這張表,用到哪些sequence,只需要在這張表中插入一條記錄即可。若某次讀取的sequence沒有用完,系統就停掉了,則這次讀取的sequence剩余值不會再使用。
使用方式:
1. 配置server.xml文件
<system><property name="sequnceHandlerType">1</property></system>
1代表使用數據庫方式生成sequence
2. 配置數據庫
在其中一個分片點對應的數據庫中創建表和存儲過程
因我在schem.xml中datanode的配置信息如下:
<dataNode name="dn$1-3" dataHost="localhost1" database="db$1-3" />
譬如我在dn2中創建,對應的數據庫名為db2(為什麼這裡會涉及到datanode,因為後續的sequence_db_conf.properties文件會使用到),注意,是登錄到數據庫中創建,而不是在mycat中創建
1> 創建MYCAT_SEQUENCE表
mysql> DROP TABLE IF EXISTS MYCAT_SEQUENCE; Query OK, 0 rows affected, 1 warning (0.00 sec) mysql> CREATE TABLE MYCAT_SEQUENCE (name VARCHAR(50) NOT NULL,current_value INT NOT NULL,increment INT NOT NULL DEFAULT 100, PRIMARY KEY(name)) ENGINE=InnoDB; Query OK, 0 rows affected (0.07 sec)
其中: – name sequence名稱
–
current_value 當前value
– increment
增長步長! 可理解為mycat在數據庫中一次讀取多少個sequence. 當這些用完後, 下次再從數據庫中讀取.
注意:MYCAT_SEQUENCE必須大寫。
2> 插入sequence記錄
mysql> INSERT INTO MYCAT_SEQUENCE(name,current_value,increment) VALUES ('mycat', 1, 100); Query OK, 1 row affected (0.01 sec)
代表插入了一個名為mycat的sequence,當前值為1,步長為100。
3> 創建存儲函數。
注意:必須在同一個數據庫中創建,在本例中,是db2。一共要創建三個。
– 獲取當前sequence的值(返回當前值,增量)
DROP FUNCTION IF EXISTS mycat_seq_currval; DELIMITER $ CREATE FUNCTION mycat_seq_currval(seq_name VARCHAR(50)) RETURNS varchar(64) CHARSET utf8 DETERMINISTIC BEGIN DECLARE retval VARCHAR(64); SET retval="-999999999,null"; SELECT concat(CAST(current_value AS CHAR),",",CAST(increment AS CHAR)) INTO retval FROM MYCAT_SEQUENCE WHERE name = seq_name; RETURN retval; END $ DELIMITER ;
– 設置sequence值
DROP FUNCTION IF EXISTS mycat_seq_setval; DELIMITER $ CREATE FUNCTION mycat_seq_setval(seq_name VARCHAR(50),value INTEGER) RETURNS varchar(64) CHARSET utf8 DETERMINISTIC BEGIN UPDATE MYCAT_SEQUENCE SET current_value = value WHERE name = seq_name; RETURN mycat_seq_currval(seq_name); END $ DELIMITER ;
– 獲取下一個sequence值
DROP FUNCTION IF EXISTS mycat_seq_nextval; DELIMITER $ CREATE FUNCTION mycat_seq_nextval(seq_name VARCHAR(50)) RETURNS varchar(64) CHARSET utf8 DETERMINISTIC BEGIN UPDATE MYCAT_SEQUENCE SET current_value = current_value + increment WHERE name = seq_name; RETURN mycat_seq_currval(seq_name); END $ DELIMITER ;
至此,數據庫方面的准備工作已結束完畢。
3. 在mycat conf目錄下的sequence_db_conf.properties文件中添加如下內容:
MYCAT=dn2
其中,dn2對應的是數據庫db2的datanode
注意:MYCAT必須為大寫,這個與表的數據是否大寫無關,事實上,MYCAT_SEQUENCE中name是否大小寫對結果沒有影響。
開始測試:
登錄mycat客戶端
# mysql -h127.0.0.1 -utest -ptest -P8066 -DTESTDB
創建測試表
mysql> create table test(id int,name varchar(10)); Query OK, 0 rows affected (0.22 sec)
插入數據
插入的格式如下:
insert into table1(id,name) values(next value for MYCATSEQ_GLOBAL,'test');
mysql> mysql> insert into test(id,name) values(next value for MYCATSEQ_MYCAT,'test1'); ERROR 1003 (HY000): mycat sequnce err.org.opencloudb.config.util.ConfigException: can't find definition for sequence :MYCAT mysql> insert into test(id,name) values(next value for MYCATSEQ_MYCAT,'test1'); Query OK, 1 row affected (0.11 sec) mysql> select * from test; +------+-------+ | id | name | +------+-------+ | 101 | test1 | +------+-------+ 1 row in set (0.09 sec)
第一次會報如下錯誤:
ERROR 1003 (HY000): mycat sequnce err.org.opencloudb.config.util.ConfigException: can't find definition for sequence :MYCAT
因為對於sequence_db_conf.properties的修改當前的mycat並不知曉,這時候,可重啟mycat或者登錄9066管理端口進行 reload @@config;
至此,測試完畢,關鍵還是兩點:MYCAT_SEQUENCE必須大寫,sequence_db_conf.properties文件中MYCAT=dn2必須大寫。
宋德福