1. 程式人生 > 其它 >資料庫中介軟體MyCat之主鍵值生成方式詳解

資料庫中介軟體MyCat之主鍵值生成方式詳解


開啟新的專題【資料庫中介軟體】第7節,一起開啟資料庫中介軟體的學習,上節回顧:本機windows系統啟動mycat,訪問3臺虛擬機器,演示mycat的11種分片策略演示,防止入坑。本節就演示上節提到的主鍵6種生成方式。 

(一)主鍵值生成方式

  1. ① 介紹
   在實現分庫分表的情況下,原來是一張表就分到多個庫上面和多個表上面,各個表都有自增,無法保證資料庫自增主鍵自增主鍵的全域性唯一。為此,MyCat 提供了全域性sequence,並且提供了包含本地配置和資料庫配置等多種實現方式。 
   CREATETABLE t_customer(      idBIGINT PRIMARY KEY,       namevarchar(100) notnull,       province intnotnull       );      <tablename="t_customer"primaryKey="id"autoIncrement="true"dataNode="dn1,dn2,dn3"rule="sharding-by-province" />  
  1. ② 本地檔案方式
   原理:此方式MyCAT 將sequence 配置到檔案中,當使用到sequence 中的配置後,MyCAT 會更新 conf中的sequence_conf.properties 檔案中sequence 當前的值。 
   配置方式: 
   1.在sequence_conf.properties 檔案中做如下配置 
   HISIDS 歷史ID 
   MIXID 最小ID 
   MAXID 最大ID 
   CURID 當前ID 
   GLOBAL.HISIDS=       GLOBAL.MINID=1001GLOBAL.MAXID=1000000000GLOBAL.CURID=1000  
   其中HISIDS 表示使用過的歷史分段(一般無特殊需要可不配置),MINID 表示最小ID 值,MAXID 表示最大 ID 值,CURID 表示當前ID 值。 

2.server.xml 中配置

   注:sequnceHandlerType 需要配置為0,表示使用本地檔案方式。 
   <system><propertyname="sequnceHandlerType">0</property></system>  
   使用示例 
   缺點:當MyCAT 重新發布後,配置檔案中的sequence 會恢復到初始值。 優點:本地載入,讀取速度較快。為表配置主鍵自增值的序列。如果需要重啟,需要先將這個檔案進行拷貝出來,修改後,在拷貝到這個位置。 
   insertinto table1(id,name) values(nextvaluefor MYCATSEQ_GLOBAL,‘test’);  
   為表配置主鍵自增值的序列: 
   規則:在sequence_conf.properties 中配置以表名為名的序列。 
   T_COMPANY.CURID=501       T_COMPANY.MINID=1       T_COMPANY.MAXID=1000000000  
   就可以使用了。 
   <tablename="t_company"primaryKey="id"autoIncrement="true"dataNode="dn1,dn2,dn3"rule="range-sharding-by-members-count" />      INSERTINTO t_company(name,members) VALUES('company06',200);       select * from t_company;  
  1. ③ 資料庫方式
   在資料庫中建立一張表,存放sequence 名稱(name),sequence 當前值(current_value),步長(increment int型別,每次讀取多少個sequence)等資訊。 
   Sequence 獲取步驟 
  1. 當初次使用該sequence 時,根據傳入的sequence 名稱,從資料庫這張表中讀取
  2. current_value,和 increment 到MyCat 中,並將資料庫中的current_value 設定為原
  3. current_value 值+increment 值。
  4. MyCat 將讀取到current_value+increment 作為本次要使用的sequence 值,下次使用
  5. 時,自動加1,當 使用increment 次後,執行步驟1)相同的操作。
   MyCat 負責維護這張表,用到哪些sequence,只需要在這張表中插入一條記錄即可。若某次讀取的 sequence 沒有用完,系統就停掉了,則這次讀取的sequence 剩餘值不會再使用。 
   注:sequnceHandlerType 需要配置為1,表示使用資料庫方式生成sequence。 
   <system><propertyname="sequnceHandlerType">1</property></system>  
   資料庫配置: 
  1. 建立MYCAT_SEQUENCE 表
   -- 建立存放sequence 的表 DROPTABLEIFEXISTS MYCAT_SEQUENCE;       -- name sequence 名稱 -- current_value 當前value -- increment 增長步長! 可理解為mycat 在資料庫中一次讀取多少個sequence. 當這些用完後, 下次再從數 據庫中讀取。 CREATETABLE MYCAT_SEQUENCE (       nameVARCHAR(50) NOTNULL,       current_value INTNOTNULL,       incrementINTNOTNULLDEFAULT100,       PRIMARY KEY(name)      );       -- 插入一條sequence INSERT INTO MYCAT_SEQUENCE(name,current_value,increment) VALUES ('GLOBAL', 100000, 100);  
  1. 建立相關function
   -- 獲取sequence當前值(返回當前值,增量)的函式 DROPFUNCTIONIFEXISTS mycat_seq_currval;             CREATEFUNCTION mycat_seq_currval(seq_name VARCHAR(50))       RETURNSvarchar(64)      BEGINDECLARE retval VARCHAR(64);       SET retval='-999999999,null';       SELECTconcat(CAST(current_value ASCHAR),',',CAST(incrementASCHAR)) INTO retval       FROM MYCAT_SEQUENCE       WHEREname = seq_name;       RETURN retval;       END;                   -- 設定sequence 值的函式 DROPFUNCTIONIFEXISTS mycat_seq_setval;             CREATEFUNCTION mycat_seq_setval(seq_name VARCHAR(50),valueINTEGER)       RETURNSvarchar(64)      BEGINUPDATE MYCAT_SEQUENCE       SET current_value = valueWHEREname = seq_name;       RETURN mycat_seq_currval(seq_name);       END;            -- 獲取下一個sequence 值 DROPFUNCTIONIFEXISTS mycat_seq_nextval;       CREATEFUNCTION mycat_seq_nextval(seq_name VARCHAR(50))       RETURNSvarchar(64)       BEGINUPDATE MYCAT_SEQUENCE SET current_value = current_value + incrementWHEREname = seq_name;       RETURN mycat_seq_currval(seq_name);       END;  
   注意:MYCAT_SEQUENCE 表和以上的3 個function,需要放在同一個節點上。function 請直接在具體節點的資料庫上執行,如果執行的時候報: you might want to use the less safe log_bin_trust_function_creators variable 
   需要對資料庫做如下設定: windows 下my.ini[mysqld]加上 
   log_bin_trust_function_creators=1 linux 下/etc/my.cnf 下my.ini[mysqld]加上 
   log_bin_trust_function_creators=1 修改完後,即可在mysql 資料庫中執行上面的函式。 
  1. sequence_db_conf.properties 相關配置,指定sequence 相關配置在哪個節點上:
   USER_SEQ=test_dn1  

使用示例:

   insertinto table1(id,name) values(nextvaluefor MYCATSEQ_GLOBAL,'test');  
   配置表的主鍵自增使用序列 

1 在序列定義表中增加名字為表名的序列

   INSERTINTO MYCAT_SEQUENCE(name,current_value,increment) VALUES ('T_COMPANY', 1,100);  

2 在sequence_db_conf.properties中增加表的序列配置

   T_COMPANY=dn1  

3 主鍵自增就可以使用了

   <tablename="t_company"primaryKey="id"autoIncrement="true"dataNode="dn1,dn2,dn3"rule="range-sharding-by-members-count" />      INSERTINTO t_company(name,members) VALUES('company08',200);       select * from t_company;  
  1. ④ 本地時間戳方式
   原理: 
   ID= 64 位二進位制:42(毫秒)+5(機器ID)+5(業務編碼)+12(重複累加)。 
   換算成十進位制為18 位數的long 型別,每毫秒可以併發12 位二進位制的累加。 
   使用方式: 

1.配置server.xml

   <propertyname="sequnceHandlerType">2</property>  

2.在mycat 下配置:sequence_time_conf.properties

   WORKID=0-31 任意整數 表示機器id(或mycat例項id) 
   DATAACENTERID=0-31 任意整數 業務編碼 

多個mycat 節點下每個mycat 配置的WORKID,DATAACENTERID 不同,組成唯一標識,總共支援32*32=1024 種組合。

ID 示例:56763083475511 。

   主鍵自增配置 
   <tablename="t_company"primaryKey="id"autoIncrement="true"dataNode="dn1,dn2,dn3"rule="range-sharding-by-members-count" />      INSERTINTO t_company(name,members) VALUES('company09',200);       select * from t_company;  
  1. ⑤ 分散式ZK ID生成器
   server.xml 
   # system 中新增      <propertyname="sequnceHandlerType">3</property>  
   配置 
   1.Zk 的連線資訊統一在myid.properties 的zkURL 屬性中配置。此只需關注zkURL。 
   loadZk=false       zkURL=127.0.0.1:2181       clusterId=mycat-cluster-1       myid=mycat_fz_01       clusterSize=3       clusterNodes=mycat_fz_01,mycat_fz_02,mycat_fz_04       #server booster ; booster install on db same server,will reset all       minCon to 2 type=server       boosterDataHosts=dataHost1  
   基於ZK 與本地配置的分散式ID 生成器,ID 結構:long 64 位,ID 最大可佔63 位: 
  1. |current time millis(微秒時間戳38 位,可以使用17 年)|clusterId(機房或者ZKid,通過配置檔案配置5 位)|instanceId(例項ID,可以通過ZK 或者配置檔案獲取,5
  2. 位)|threadId(執行緒ID,9 位) |increment(自增,6 位)
  3. 一共63 位,可以承受單機房單機器單執行緒1000*(2^6)=640000 的併發。
  4. 無悲觀鎖,無強競爭,吞吐量更高
  5. 配置檔案:sequence_distributed_conf.properties,只要配置裡面:INSTANCEID=ZK 就是從ZK 上獲取 InstanceID。(可以通過ZK 獲取叢集(機房)唯一InstanceID,也可以通過配置檔案配置InstanceID)
   測試 
   <tablename="t_company"primaryKey="id"autoIncrement="true"dataNode="dn1,dn2,dn3"rule="range-sharding-by-members-count" />      INSERTINTO t_company(name,members) VALUES('company10',200);       select * from t_company;  
  1. ⑥ ZK 遞增的方式
   server.xml 
   # system 中新增      <propertyname="sequnceHandlerType">4</property>  
   Zk 的連線資訊統一在myid.properties 的zkURL 屬性中配置。 

配置:

配置檔案:sequence_conf.properties 只要配置好ZK 地址和表名的如下屬性

  1. TABLE.MINID 某執行緒當前區間內最小值
  2. TABLE.MAXID 某執行緒當前區間內最大值
  3. TABLE.CURID 某執行緒當前區間內當前值
   檔案配置的MAXID 以及MINID 決定每次取得區間,這個對於每個執行緒或者程序都有效。檔案中的這三個屬性配置只對第一個程序的第一個執行緒有效,其他執行緒和程序會動態讀取ZK。 
   測試 
   <tablename="t_company"primaryKey="id"autoIncrement="true"dataNode="dn1,dn2,dn3"rule="range-sharding-by-members-count" />      INSERTINTO t_company(name,members) VALUES('company12',200);       select * from t_company;  
  1. ⑦ last_insert_id() 問題
   我們配置分片表主鍵自增。 
   <tablename="t_company"primaryKey="id"autoIncrement="true"dataNode="dn1,dn2,dn3"rule="range-sharding-by-members-count" />  
   如需通過 select last_insert_id() 來獲得自增主鍵值,則表定義中主鍵列需是自增的 
   AUTO_INCREMENT 
   CREATETABLE t_company(       idBIGINT PRIMARY KEY AUTO_INCREMENT,       namevarchar(100) notnull,       members intnotnull       );  
   如果沒有指定 AUTO_INCREMENT,則select last_insert_id() 獲取不到剛插入資料的主鍵值。 
   CREATETABLE t_company(       idBIGINT PRIMARY KEY,       namevarchar(100) notnull,       members intnotnull       );  
   Mybatis 中新增記錄後獲取last_insert_id 的示例 
   <insertid="insert"parameterType="com.study.mike.user.model.User">       insert into t_user (user_name,login_name,login_pwd,role_id) values(#{userName},#{loginName},#{loginPwd},#{roleId})       <selectKeyresultType="java.lang.Long"order="AFTER"keyProperty="id">       select last_insert_id() as id       </selectKey></insert>  

PS:這就是myCat相關分庫分表先關的內容,建議不選擇檔案的方式,選擇資料庫的方式或者是zk的方式來確定主鍵的生成,保證唯一性