项目要求能够重复利用编号值,编号值得范围是 1~65535。也就是,当自动分配的上限超过65535的时候,能够回过头来找那些已经不使用的编号值。有4张表需要重复利用编号值。
思路是每张表都做一个 trigger before insert。每次取该表的最大编号+1。如果该编号已经超过65535。那么随机分配一个1~65535的编号,检查是否使用,如果已经有人使用,那么继续随机。尝试次数超过65535时,也就是不太可能再找到合适的编号时,随便插入一个最大编号。编号列有唯一索引,所以此时会出错退出事务。
缺陷有几个:
1、随机寻找的编号可能分布不均匀,有可能还是有少数几个可以使用的编号,但是找不到。也就是查找编号的算法需要改进。
(比如遍历?比如分配的时候采用二分法分配,二分法查找?这样可以均匀分配编号,又可以快速查找)
2、出错的方式不优雅。当编号用满时,是通过唯一索引检查失败之后产生错误。MySQL不能从trigger 中抛出自定义的错误。
PS:写完才发现二分法更好,看来算法基础不行。
这次任务加深了对 MySQL trigger & procedure的了解。拷贝代码做一个记录~~~
其中一张表的触发器代码:
create trigger SetPiUnderId BEFORE INSERT on t_play_item
for each ROW
begin
DECLARE uid int;
declare usedNum int;
declare retry int;
declare maxRetry int;
SELECT max(pi_under_id)+1 into uid from t_play_item;
IF uid = 0
then
set uid = 1;
end if;
IF uid < 65535 THEN
-- UPDATE t_play_item set pi_under_id = pi_id where pi_id = new.pi_id;
set NEW.pi_under_id = uid;
else
begin
-- 否则开始生成随机数查询
set maxRetry = 65530;
set retry = 0;
REPEAT
set uid = RAND() * 65530;
set usedNum = 0;
-- 有几条记录使用这个编号
select count(*) into usedNum from t_play_item where pi_under_id = uid;
set retry = retry + 1;
until usedNum = 0 or retry >= maxRetry
end repeat;
IF usedNum = 0
then
-- UPDATE t_play_item set pi_under_id = uid where pi_id = new.pi_id;
set NEW.pi_under_id = uid;
else
-- 强制设置成id, 没有找到抛出错误的办法,
set NEW.pi_under_id = uid;
-- UPDATE t_play_item set pi_under_id = pi_id where pi_id = new.pi_id;
-- UPDATE t_play_item set pi_under_id = 65535 where pi_id = new.pi_id;
end if;
end;
end if;
end
用来测试的存储过程:
CREATE PROCEDURE TestSetPiUnderId(in times int, in showMsg bool)
MODIFIES SQL DATA
begin
declare t int;
set t = 0;
REPEAT
set t = t + 1;
insert into t_play_item(pi_style, pi_rect_no, pi_sent, pi_des) values(t, 1, 0, '');
IF showMsg then
select CONCAT('插入成功第', CAST(t as char));
end if;
until t> times
end repeat;
end;
posted on 2008-04-23 17:04
windone 阅读(2463)
评论(0) 编辑 收藏 引用 所属分类:
数据库