最近在工作中遇到很多使用MySQL自帶的autoincrement函數作為發號器,在實際使用中當並發比較小的時候還沒有問題,一旦並發增加就會出現很多問題,特此進行如下總結。
一、自增配置
通過如下建表語句就可以完成自增的配置
CREATE TABLE `test_inc` ( `id` int(11) NOT NULL AUTO_INCREMENT, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
二、修改自增大小
通過如下sql可以自動生成數字:
insert into test_inc values();
當增加3行后表中數據如下:
+----+
| id |
+----+
| 1 |
| 2 |
| 3 |
+----+
CREATE TABLE `test_inc` ( `id` int(11) NOT NULL AUTO_INCREMENT, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
使用 alter table test_inc auto_increment=10;將自增修改成10后再次插入的數據為10.
+----+
| id |
+----+
| 1 |
| 2 |
| 3 |
| 10 |
| 11 |
+----+
三、自增幅度
自增幅度通過auto_increment_offset和auto_increment_increment這2個參數進行控制
set global auto_increment_increment=2; set global auto_increment_offset=2; set session auto_increment_increment=2; set session auto_increment_offset=2;
生成偶數的自增
set global auto_increment_increment=2; set global auto_increment_offset=1; set session auto_increment_increment=2; set session auto_increment_offset=1;
生成奇數的自增
auto_increment_offset表示起始數字
auto_increment_increment表示調動幅度(即每次增加n個數字,2就代表每次+2)
四、獲得最后一個數字
通過使用last_insert_id()函數可以獲得最后一個插入的數字
select last_insert_id();
五、自增鎖
如果存在自增字段,MySQL會維護一個自增鎖,和自增鎖相關的一個參數為(5.1.22版本之后加入)
innodb_autoinc_lock_mode:可以設定3個值,0,1,2
0:traditonal (每次都會產生表鎖) 1:consecutive (會產生一個輕量鎖,simple insert會獲得批量的鎖,保證連續插入) 2:interleaved (不會鎖表,來一個處理一個,並發最高)
ps:這個參數值控制InnoDB引擎的設置,所有Myisam均為traditonal,每次均會進行表鎖。但是Innodb會視參數不通二產生不通的鎖。目前MySQL默認的配置為1。
六、自增的過程
第一種,插入空值的時候
當innodb_autoinc_lock_mode=0時
1、申請AUTO_INC鎖 2、得到當前的AUTO_INCREMENT值n,並加1 3、執行插入操作,並將n寫入新增的對應字段中。 4、釋放AUTO_INC鎖。
第二種,插入已經有值的自增
1、插入第一條數據 2、如果失敗流程結束 3、如果成功,申請AUTO_INC鎖 4、調用set_max函數,修改AUTO_INCREMENT 5、語句結束,釋放AUTO_INC鎖
七、存在的問題
1、復制的問題
在innodb_autoinc_lock_mode=2的時候,由於是來一個分配一個,故當replication模式為SBR的時候,如果發生Bulk inserts會在分配的時候向其他insert分配,就會出現主從不一致的情況,但是如果改為RBR就不會出現這種情況。
也就是說在RBR模式下,innodb_autoinc_lock_mode=2是安全的,其他情況還是建議設置為1.
2、load data的問題
當使用load data語句的時候,就算innodb_autoinc_lock_mode=1也會退化回0,這是因為為了保證數據的一致性。首先要說一下load data的執行過程,在主庫上load data為原始SQL語句,而在從庫上會先將文件傳輸過去在tmp下生成臨時問題,然后在執行load data語句。為了保證主庫和從庫的自增ID的一致性,binlog中會有set insert_ID命令,標明這個load語句的第一行的自增ID值,這樣在表鎖的情況下,就可以保證一致性了。
八、insert的補充說明
1.“INSERT-like”: INSERT, INSERT … SELECT, REPLACE, REPLACE … SELECT, and LOAD DATA, INSERT … VALUES(),VALUES() 2.“Simple inserts” 就是通過分析insert語句可以確定插入數量的insert語句, INSERT, INSERT … VALUES(),VALUES() 3.“Bulk inserts” 就是通過分析insert語句不能確定插入數量的insert語句, INSERT … SELECT, REPLACE … SELECT, LOAD DATA 4.“Mixed-mode inserts” INSERT INTO t1 (c1,c2) VALUES (1,’a'), (NULL,’b'), (5,’c'), (NULL,’d'); INSERT … ON DUPLICATE KEY UPDATE
九、官方鏈接
http://dev.mysql.com/doc/refman/5.5/en/innodb-parameters.html#sysvar_innodb_autoinc_lock_mode
