前几天看到有说mysql使用 limit 0,10 这种方式分页会丢失数据,有人质疑说不会,动手验证一下。
表结构如下:
create table `test`.`t_model`( `id` bigint NOT NULL AUTO_INCREMENT COMMENT '自增主键', `uid` bigint COMMENT '业务主键', `modelid` varchar(50) COMMENT '字符主键', `modelname` varchar(50) COMMENT '名称', `desc` varchar(50) COMMENT '描述', primary key (`id`), UNIQUE index `uid_unique` (`uid`), key `modelid_index` (`modelid`) USING BTREE ) ENGINE=InnoDB charset=utf8 collate=utf8_bin;构造测试数据语法如下:
drop procedure IF EXISTS u_head_and_low_pro; delimiter $$ create procedure u_head_and_low_pro() begin DECLARE n int DEFAULT 1; set @exesql = 'insert into t_model (uid,modelid,modelname,`desc`) values '; set @exedata = ''; WHILE n < 10001 DO set @exedata = concat(@exedata,"(",n,",","'id20170831",n,"','","name",n,"','","desc'",")"); if n % 1000 = 0 then set @exesql = concat(@exesql,@exedata,";"); prepare stmt from @exesql; execute stmt; DEALLOCATE prepare stmt; commit; set @exesql = 'insert into t_model (uid,modelid,modelname,`desc`) values '; set @exedata = ""; else set @exedata = concat(@exedata,','); end if; set n = n + 1; END WHILE; end;$$ delimiter ;查询语法如下:
-- 第一页 select * from t_model limit 0, 10; -- 第二页 select * from t_model limit 10, 10; -- 第三页 select * from t_model limit 20, 10; -- 第四页 select * from t_model limit 30, 10; -- 第五页 select * from t_model limit 40, 10;在查询时,第一页是1~10,第二页是11~20,第四页时,查询结果为: id uid modelid modelname desc
此时,查询第5页应该是 41~50。如果某人A在界面上查询数据,现在查询到第4页,在显示完第4页数据后,另外一个人B(或程序)将第11~20的数据删除掉了,A再翻页到第5页时,此时数据为: id uid modelid modelname desc
也就是说,A在本次操作过程中,如果一直往下翻页到最后一页的话,41~50 这页的数据就无法看到,数据丢失了。 当然,如果刷新一下界面,重新翻页就没有问题了。
如果分页查询的表的数据插入和删除等操作频繁的话,建议还是使用 limit 10 这种语法方式分页查询,可以提升性能,也更准确。
