主鍵生成策略


 
       應用開發中,我們經常需要涉及到數據主鍵的生成。大部分情況,我們會采用數據庫主鍵自增,比如學生表,讓學生表里的id自增。但是如果我們希望主鍵里保護日期信息呢?或者我們在庫里實行了分表策略,表主鍵自增也是不行的。
      
       有人會想到uuid,uuid能做到全局唯一的,能解決分表策略的問題,當時在主鍵里加入其他信息還是不行。還有個問題uuid字符串比較長,存儲費空間,不方便建索引。
 
       我之前采用的一個策略是建立一個專門的主鍵表,里面包含兩個字段(id, tablename) .
       sql如下:
 
CREATE TABLE `id_temp` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `table_name` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `table_name` (`table_name`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

 

     生成id:
REPLACE INTO id_temp (table_name) value("tablename") ;
SELECT LAST_INSERT_ID() ;

 

 
    如果我們業務表不介意id的連續性,可以多個業務表使用一個主鍵表。如果業務表要求id的連續性,那一個業務表得使用一個主鍵表。
 
    如果需要主鍵中加入日期元素,需要使用當前日期加上上面方式生成的id就成了。
 
    但是,當業務並發很大,這種生成速度已經滿足不了需求時,怎么辦呢?
 
    以前支付寶紅包剛出來的時候,記得發紅包的人,生成紅包后,會產生一個數字,其他人通過這個數字搶紅包。假設某個關鍵時間點,大量用戶在那個時間點生成紅包,那這些數字怎么生成呢(這些數字必須得有唯一性)。
 
   記得之前在一篇博客介紹過一個方案,地址忘記了,介紹的是Fickr使用的一種主鍵生成方案。他的方案和上面的類似,不過是一個分布式版。
 
  選擇N個數據庫服務器,每台數據庫建一個主鍵表,也是兩個字段(id, tablename)。
   不同的是,第一台數據庫的建表語句是:
 
CREATE TABLE `id_temp` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `table_name` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `table_name` (`table_name`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

  

 
    第m台建表語句是:
 
CREATE TABLE `id_temp` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `table_name` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `table_name` (`table_name`)
) ENGINE=InnoDB AUTO_INCREMENT=m DEFAULT CHARSET=utf8;

  

 
   m是 1 到 N中間的一個數字,每台數據庫主鍵的初始值不同,從1到N。
 
   然后,每台數據庫設置他們的  auto_increment_increment值,
  
set @@session.auto_increment_increment=N ;

  

 
    大概意思我們應該明白了,1到N台服務器,每台服務器的自增初始值不同,分別從1到N,然后每次自增的長度是N。 應用服務器分布式調用到不同的數據庫后,都能保證id的唯一性,和單台數據庫的效果是一樣的,而且使用上數據庫集群,解決了高並發的問題。
 
 
    這里在引申一下,假如需要添加服務器,或者下線服務器,怎么辦呢?
 
方案一:
 
   我們可以假設在這個上線、下線數據庫改動期間,id能自增到的最大值M(通過平時的統計,可以有更多的富余),取一個稍微大於M的一個值,記作K。然后每台數據庫,重新設置他的 auto_increment_increment和auto_increment_offset值。第一台auto_increment_offset值設為K,第二台設為K+1,依次第m台設為K+m;每台的auto_increment_increment值設置為新的服務器數。
 
方案二:
 
     先生成足夠的id在緩存中,后面的請求不走db,全部從緩存取。然后修改每台數據庫的auto_increment_increment和auto_increment_offset值,參數修改完后,在恢復從db取。
 
 
 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM