MySQL自增锁
最近在工作中遇到很多使用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