在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
MySQL的自增id都定义了初始值,然后不断加步长。虽然自然数没有上限,但定义了表示这个数的字节长度,计算机存储就有上限。比如,无符号整型(unsigned int)是4个字节,上限就是 表定义自增值id表定义的自增值达到上限后的逻辑是:再申请下一个id时,得到的值保持不变。 mysql> create table t(id int unsigned auto_increment primary key) auto_increment=4294967295; Query OK, 0 rows affected (0.01 sec) mysql> insert into t values(null); Query OK, 1 row affected (0.00 sec) mysql> show create table t; +-------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Table | Create Table | +-------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | t | CREATE TABLE `t` ( `id` int unsigned NOT NULL AUTO_INCREMENT, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=4294967295 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci | +-------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 1 row in set (0.00 sec) //成功插入一行 4294967295 mysql> insert into t values(null); ERROR 1062 (23000): Duplicate entry '4294967295' for key 't.PRIMARY' 第一个insert成功后,该表的AUTO_INCREMENT还是4294967295,导致第二个insert又拿到相同自增id值,再试图执行插入语句,主键冲突。
InnoDB系统自增row_id若你创建的InnoDB表未指定主键,则InnoDB会自动创建一个不可见的,6个字节的row_id。InnoDB维护了一个全局的
所有无主键的InnoDB表,每插入一行数据,都将当前的 代码实现时row_id是个长度为8字节的无符号长整型(bigint unsigned)。但InnoDB在设计时,给row_id留的只是6个字节的长度,这样写到数据表中时只放了最后6个字节,所以row_id能写到数据表中的值,就有两个特征:
即写入表的row_id从 验证该结论:通过gdb修改系统的自增row_id。用gdb是为了便于复现问题,只能在测试环境使用。 row_id用完的验证序列 row_id 用完的效果验证 可见,在我用gdb将dict_sys.row_id设置为2^48之后,再插入a=2会出现在表t的第一行,因为该值的row_id=0。 所以应该在InnoDB表中主动创建自增主键:当表自增id到达上限后,再插入数据时会报主键冲突错误。 Xidredo log和binlog有个共同字段Xid,用来对应事务。Xid在MySQL内部是如何生成的呢? MySQL内部维护了一个全局变量 每次执行语句时,将它赋值给 若当前语句是该事务执行的第一条语句,则MySQL还会同时把
而 但MySQL重启之后会重新生成新binlog文件,这就保证同一个binlog文件里的Xid唯一。 虽然MySQL重启不会导致同一个binlog里面出现两个相同Xid,但若 因为
Innodb trx_idXid由server层维护 但InnoDB自己的trx_id,是另外维护的事务id(transaction id)。 InnoDB内部维护了一个max_trx_id全局变量,每次需要申请一个新的trx_id时,就获得max_trx_id的当前值,然后并将max_trx_id加1。 InnoDB数据可见性的核心思想每一行数据都记录了更新它的trx_id,当一个事务读到一行数据时,判断该数据是否可见,就是通过事务的一致性视图与这行数据的trx_id做对比。 对于正在执行的事务,你可以从information_schema.innodb_trx表中看到事务的trx_id。 看如下案例:事务的trx_id
S2 的执行记录: mysql> use information_schema; Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A Database changed mysql> select trx_id, trx_mysql_thread_id from innodb_trx; +-----------------+---------------------+ | trx_id | trx_mysql_thread_id | +-----------------+---------------------+ | 421972504382792 | 70 | +-----------------+---------------------+ 1 row in set (0.00 sec) mysql> select trx_id, trx_mysql_thread_id from innodb_trx; +---------+---------------------+ | trx_id | trx_mysql_thread_id | +---------+---------------------+ | 1355623 | 70 | +---------+---------------------+ 1 row in set (0.01 sec) S2从innodb_trx表里查出的这两个字段,第二个字段 t2时显示的trx_id是一个很大的数;t4时刻显示的trx_id是1289,看上去是一个比较正常的数字。这是为啥?
除了明显的修改类语句,若在select 语句后面加上for update,也不是只读事务。
t2时查到的很大数字是怎么来的? 这样可以保证:
为什么要加248? 保证只读事务显示的trx_id值比较大,正常情况下就会区别于读写事务的id。但trx_id跟row_id的逻辑类似,定义为8个字节。 为何只读事务不分配trx_id?
由于只读事务不分配trx_id,显然trx_id的增速变慢。 达到该状态后,MySQL就会持续出现一个脏读bug: 复现脏读
因为系统的max_trx_id被设置成2^48 - 1,所以在session A启动的事务TA的低水位就是2^48 - 1。 t2时:
t3时: session A执行select的可见性判断:c=3这个数据版本的trx_id(0),小于事务TA的低水位(2^48 - 1),所以认为该数据可见。 但这是脏读。 并且MySQL重启时 这也可以加深对低水位和数据可见性的理解。 thread_id系统保存了一个全局变量
每新建一个连接,就将
但不会在
给新线程分配 总结每种自增id有各自的应用场景,在达到上限后的表现也不同:
到此这篇关于线上MySQL的自增id用尽怎么办的文章就介绍到这了,更多相关MySQL自增id用尽内容请搜索极客世界以前的文章或继续浏览下面的相关文章希望大家以后多多支持极客世界! |
请发表评论