程序员还是熟悉一下数据库为好,今天就被坑了一回:
CREATE TABLE `T2` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `name` char(32) NOT NULL DEFAULT '', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=1000 DEFAULT CHARSET=utf8;
好吧,正常来说,新插入的记录id就应该从1000开始了。然而,在创建完表到正式插入第一条记录之间,你可能发现数据库有需要优化的地方,修改了一下配置,重启mysqld。这个时候,再插入:
mysql> insert into T2(name) values('es'); Query OK, 1 row affected (0.01 sec) mysql> select * from T2; +----+------+ | id | name | +----+------+ | 1 | es | +----+------+ 1 row in set (0.00 sec)
这算是一件大事吗?是的,太严重了,因为我设了一条规则,根据id来找到这个表属于哪个库,想想mysql建立链接时c api:
MYSQL *mysql_real_connect(MYSQL *mysql, const char *host, const char *user, const char *passwd, const char *db, unsigned int port, const char *unix_socket, unsigned long client_flag)
操作每个库使用的是不同的句柄,一个错误的id,别想获得正确的句柄了。
为什么重启之后auto_increment的值就不复存在了呢?简单来说就是auto_increment的值保存在内存,详细看这里:http://biancheng.dnbcw.info/mysql/248738.html
然后嘛就出事了,部分数据丢失,要靠着剩下的部分数据去恢复,这就到了考验mysql能力的时候了。然后突然发现,这方面能力实在不大行,特别碰上情况紧急,更是手忙脚乱。例如拿着一个id列表,对每个id插入几条信息到表中,我不会!我甚至不知道mysql是否有循环这回事,我只想到写个小程序来操作。幸好最后发现这样的操作并不需要,要不就死定了。但是,程序员,你还是熟悉一下数据库吧。循环插入,可以写一个存储过程,或者不关注性能,使用mysql命令写个小脚本也可以,只要你知道mysql命令有一个--execute选项,例如:
mysql test -e "insert into T2(name) values('esw');"
(test为数据库名,如需要用户名或密码,使用-p -u)
存储过程,从来没写过,看这里:http://www.blogjava.net/sxyx2008/archive/2013/02/03/303497.html,自己写一下:
delimiter // DROP PROCEDURE IF EXISTS loop_insert; CREATE PROCEDURE loop_insert( in n INT ) BEGIN DECLARE i INT DEFAULT 0; WHILE i < 10 DO INSERT INTO T2(id, name) VALUES(n, 'a'); SET i=i+1; SET n=n+1; END WHILE; END // delimiter ;
delimiter命令用于告诉mysql客户端,遇到'//'的时候才执行输入的指令。使用的时候要先选择T2所在的库,然后
mysql> set @n=20; Query OK, 0 rows affected (0.00 sec) mysql> CALL loop_insert(@n); Query OK, 1 row affected (0.52 sec)
记得要@就行了。
然后刚才又发现了存储过程中很有用的游标(cursor):http://blog.csdn.net/rdarda/article/details/7881648
也来自己写一下:
delimiter // DROP PROCEDURE IF EXISTS cursor_test; CREATE PROCEDURE cursor_test() BEGIN DECLARE done INT DEFAULT 0; DECLARE id_found INT; DECLARE loop_cursor CURSOR FOR SELECT id FROM T1; DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done = 1; OPEN loop_cursor; FETCH loop_cursor INTO id_found; REPEAT INSERT INTO T2(id, name) VALUES(id_found, 'a'); FETCH loop_cursor INTO id_found; UNTIL done END REPEAT; CLOSE loop_cursor; END // delimiter ;
T1是之前写的另一个表,这里只需要知道它有一个id字段就可以了。其中的CONTINUE HANDLER在我这边似乎没有用,调用这个存储过程之后依然会有warning。然后FETCH INTO是可以将多个字段赋值到多个变量的,这里没用到而已。
今天还用到的几个命令:
查看创建表的代码:
mysql> show create table T2; +-------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Table | Create Table | +-------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | T2 | CREATE TABLE `T2` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `name` char(32) NOT NULL DEFAULT '', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 | +-------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 1 row in set (0.00 sec)
修改auto_increment:
mysql> alter table T2 auto_increment=100; Query OK, 2 rows affected (0.05 sec) Records: 2 Duplicates: 0 Warnings: 0
查看auto_increment和其他状态:
mysql> show create table T2; +-------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Table | Create Table | +-------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | T2 | CREATE TABLE `T2` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `name` char(32) NOT NULL DEFAULT '', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=100 DEFAULT CHARSET=utf8 | +-------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 1 row in set (0.00 sec)