一直会持有AUTO-INC锁直到语句结束,生成的值都是连续的,不会产生间隙。
innodb_autoinc_lock_mode=1,这时候一条语句内不会产生间隙,但是语句之间可能会产生间隙。后面会有例子说明。
innodb_autoinc_lock_mode=2,如果有并发的insert操作,那么同一条语句内都可能产生间隙。
mixed-mode inserts
这种模式下针对innodb_autoinc_lock_mode的值配置不同,结果也会不同,当然innodb_autoinc_lock_mode=0时时不会产生间隙的,而innodb_autoinc_lock_mode=1以及innodb_autoinc_lock_mode=2是会产生间隙的。后面例子说明。
另外注意的一点是,在master-slave这种架构中,复制如果采用statement-based replication这种方式,则innodb_autoinc_lock_mode=0或1才是安全的。而如果是采用row-based replication或者mixed-based replication,则innodb_autoinc_lock_mode=0,1,2都是安全的。
4.实例
测试的两个表分别为t和t1,定义分别如下:
CREATE TABLE `t` ( `a` bigint(20) unsigned NOT NULL AUTO_INCREMENT, PRIMARY KEY (`a`) ) ENGINE=InnoDB; CREATE TABLE `t1` ( `c1` int(11) NOT NULL AUTO_INCREMENT, `c2` varchar(10) DEFAULT NULL, PRIMARY KEY (`c1`) ) ENGINE=InnoDB
首先在表t插入1-10000000共1千万条数据,为了后面测试方便。开启session1,执行下面语句:
insert into t1(c2) select * from t;
然后开启session2,在t1中插入数据:
insert into t1(c2) values(400);
针对innodb_autoinc_lock_mode不同的情况,新插入的数据的c1的值也不同。
innodb_autoinc_lock_mode=0时,因为session1的语句都是加AUTO-INC锁,因此,session1先开始的话,c1列的值都是1-10000000连续的值,由于在传统机制下,auto_increment值都是一个个分配,因此session2插入的数据c1的值则是10000001。最终看到的就是有两条这样的数据(400,400),(10000001,400)。
innodb_autoinc_lock_mode=1时,同样session1也会加AUTO-INC锁,但是由于该模式下会预先分配auto_increment的值,所以可以看到在session2中插入的数据的c1值不会是10000001,但是不会是1-10000000这其中的数字,因为session1有加AUTO-INC锁。最终的数据会是这样两条:(400,400), (10026856,400)。
innodb_autoinc_lock_mode=2时,session1不会加AUTO-INC锁,因此虽然session2是后执行,但是并不影响auto_increment值分配,最终的值跟我们执行session2的时间有关,最终的值可能是这样的:(400,400),(1235603,400)这样的,会占用1-10000000之间的值。
5.另外几点
1)关于innodb_autoinc_lock_mode=1时,auto_increment预先分配策略可以参照参考资料2,假定表t中已经初始有一条记录1,然后在表t中我们用`insert into t select NULL from t执行四次,可以看到表t中最终的记录会是1,2,3,4,6,7,8,9,13,14,15,16,17,18,19,20,其中5,10,11,12都浪费掉了。参考资料1后面部分也有讲到预分配问题。
2)INSERT INTO t1…SELECT … FROM t这类语句会对表t1加record lock,如果隔离级别是read committed,或者设置了innodb_locks_unsafe_for_binlog且隔离级别不是serialize,则不会对t加锁,否则对t加shared next-key lock。