Chinaunix首页 | 论坛 | 博客
  • 博客访问: 73961
  • 博文数量: 24
  • 博客积分: 1410
  • 博客等级: 上尉
  • 技术积分: 280
  • 用 户 组: 普通用户
  • 注册时间: 2008-04-23 14:19
文章分类
文章存档

2008年(24)

我的朋友

分类: Mysql/postgreSQL

2008-04-24 11:23:45

这个贴子中,myisam类型表 指定表选项auto_increment=36832,id为int
最大值为126的情况下,插入127报重复键,重启后仍报错,插入150正常
mysqlcheck修复后正常,估计是表的index(key)与表数据不一致了,在没有损坏情况下无法重现这个错误;
应该是程序曾经异常终止,导致表损坏了(表与索引不一致);当指定127插入时,虽然表中无127这条记录,但索引中已经存在key
 
出问题的时候我用了check 列出了类似这样的错误:
error | Found xxxx keys of yyyy
error | corrupt

其中xxxx != yyyy
select max(id) from Syslog;
返回的值也不等于 最后一条记录的ID
 
 
下面的测试有利于清楚解释表中auto_increment列与auto_increment计数器对像(其实是一个变量)
的关系,及重新gap中数据的问题.
 
没有指定表选项的情况
mysql> CREATE TABLE `sys_log` (
    ->   `log_id` int(11) NOT NULL AUTO_INCREMENT,
    ->    name varchar(30),
    ->   PRIMARY KEY (`log_id`)
    -> ) ENGINE=innodb  DEFAULT CHARSET=latin1;
Query OK, 0 rows affected (0.00 sec)
 
mysql> insert into sys_log values(126,'aaa');
Query OK, 1 row affected (0.00 sec)
 
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> insert into sys_log values(127,'aaa');
Query OK, 1 row affected (0.00 sec)
mysql> insert into sys_log values(128,'aaa'); ==>指定值128给列及计数器
Query OK, 1 row affected (0.00 sec)
mysql> rollback;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from sys_log;
+--------+------+
| log_id | name |
+--------+------+
|    126 | aaa  |
+--------+------+
1 row in set (0.00 sec)
mysql> insert into sys_log values(127,'aaa');
Query OK, 1 row affected (0.00 sec)
mysql>  select * from sys_log;
+--------+------+
| log_id | name |
+--------+------+
|    126 | aaa  |
|    127 | aaa  | ==>回滚后,如果insert给gap范围内指定值,则赋值给列指定值,而auto increment计数器的值不变仍为128
+--------+------+
2 rows in set (0.00 sec)
mysql> insert into sys_log values(null,'aaa'); ==>随后,insert给null/0时,则会从计数器取值并+1后重新赋值给计数器及列值
Query OK, 1 row affected (0.00 sec)
mysql> select * from sys_log;
+--------+------+
| log_id | name |
+--------+------+
|    126 | aaa  |
|    127 | aaa  |
|    129 | aaa  | ==>
+--------+------+
3 rows in set (0.00 sec)
 
 
指定表选项为 AUTO_INCREMENT = 1000
 
mysql> drop table sys_log;
Query OK, 0 rows affected (0.01 sec)
mysql> CREATE TABLE `sys_log` (
    ->   `log_id` int(11) NOT NULL AUTO_INCREMENT,
    ->    name varchar(30),
    ->   PRIMARY KEY (`log_id`)
    -> ) ENGINE=innodb  AUTO_INCREMENT = 1000 DEFAULT CHARSET=latin1;
Query OK, 0 rows affected (0.01 sec)
mysql> insert into sys_log values(126,'aaa');
Query OK, 1 row affected (0.00 sec)
mysql>
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> insert into sys_log values(127,'aaa');
Query OK, 1 row affected (0.00 sec)
mysql> insert into sys_log values(128,'aaa');
Query OK, 1 row affected (0.00 sec)
mysql> rollback;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from sys_log;
+--------+------+
| log_id | name |
+--------+------+
|    126 | aaa  |
+--------+------+
1 row in set (0.00 sec)
mysql> insert into sys_log values(127,'aaa');
Query OK, 1 row affected (0.00 sec)
mysql> select * from sys_log;
+--------+------+
| log_id | name |
+--------+------+
|    126 | aaa  |
|    127 | aaa  |
+--------+------+
2 rows in set (0.00 sec)
mysql> insert into sys_log values(null,'aaa');
Query OK, 1 row affected (0.00 sec)
mysql> select * from sys_log;
+--------+------+
| log_id | name |
+--------+------+
|    126 | aaa  |
|    127 | aaa  |
|   1000 | aaa  | ==>取值为1000
+--------+------+
3 rows in set (0.00 sec)
 
 
因为rollback造成序列间隙(gap),随后的insert语句可以指定gap中的值,这时mysql会正确赋值给列值,而序列计数器的值仍是rollback掉最后一条insert语句获得的序列值,所以,如果随后的insert语句是这三种情况:不指定/指定为null/指定为0 时,insert是从计数器获得值后+1再赋值给计数器及列值!
 
当建表时指定了auto_increment表选项时,则受这个option制约,计数器的起始值是选项的指定值;
 
总之,间隙中的序列值是可以重用的!
阅读(910) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~