首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 数据库 > Mysql >

基于mysql的分页程序完全解决方案(含普普通通分页/分段分页/原始分页/微博的since_id类分页)

2012-08-03 
基于mysql的分页程序完全解决方案(含普通分页/分段分页/原始分页/微博的since_id类分页)Author: selfimprB

基于mysql的分页程序完全解决方案(含普通分页/分段分页/原始分页/微博的since_id类分页)

Author: selfimpr

Blog: http://blog.csdn.net/lgg201

Mail: lgg860911@yahoo.com.cn

Copyright: 转载请注明出处


0. 下载:

本程序可自由修改, 自由分发, 可在http://download.csdn.net/user/lgg201下载
1. 分页的需求
信息的操纵和检索是当下互联网和企业信息系统承担的主要责任. 信息检索是从大量的数据中找到符合条件的数据以用户界面展现给用户.
符合条件的数据通常会有成千上万条, 而用户的单次信息接受量是很小的, 因此, 如果一次将所有符合用户条件的数据展现给用户, 对于多数场景, 其中大部分数据都是冗余的.
信息检索完成后, 是需要经过传输(从存储介质到应用程序)和相关计算(业务逻辑)的, 因此, 我们需要一种分段的信息检索机制来降低这种冗余.
分页应运而生.
2. 分页的发展
基本的分页程序, 将数据按照每页记录数(page_size)将数据分为ceil(total_record / page_size)页, 第一次为用户展现第一段的数据, 后续的交互过程中, 用户可以选择到某一页对数据进行审阅.
后来, 主要是在微博应用出现后, 由于其信息变化很快, 而其特性为基于时间线增加数据, 这样, 基本的分页程序不能再满足需求了: a) 当获取下一页时, 数据集可能已经发生了很多变化, 翻页随时都可能导致数据重复或跳跃; b) 此类应用采用很多采用一屏展示多段数据的用户界面, 更加加重了数据重复/跳跃对用户体验的影响. 因此, 程序员们开始使用since_id的方式, 将下一次获取数据的点记录下来, 已减轻上述弊端.
在同一个用户界面, 通过用户阅读行为自动获取下一段/上一段数据的确比点击"下一页"按钮的用户体验要好, 但同样有弊端: a) 当用户已经到第100页时, 他要回到刚才感兴趣的第5页的信息时, 并不是很容易, 这其实是一条设计应用的规则, 我们不能让用户界面的单页屏数过多, 这样会降低用户体验; b) 单从数据角度看, 我们多次读取之间的间隔时间足够让数据发生一些变化, 在一次只展示一屏时, 我们很难发现这些问题(因此不影响用户体验), 然而当一页展示100屏数据时, 这种变化会被放大, 此时, 数据重复/跳跃的问题就会再次出现; c) 从程序的角度看, 将大量的数据放置在同一个用户界面, 必然导致用户界面的程序逻辑受到影响. 基于以上考虑, 目前应用已经开始对分页进行修正, 将一页所展示的屏数进行的限制, 同时加入了页码的概念, 另外也结合since_id的方式, 以达到用户体验最优, 同时保证数据逻辑的正确性(降低误差).
3. 分页的讨论
感谢xp/jp/zq/lw四位同事的讨论, 基于多次讨论, 我们分析了分页程序的本质. 主要的结论点如下:
1) 分页的目的是为了分段读取数据
2) 能够进行分页的数据一定是有序的, 哪怕他是依赖数据库存储顺序. (这一点换一种说法更容易理解: 当数据集没有发生变化时, 同样的输入, 多次执行, 得到的输出顺序保持不变)
3) 所有的分段式数据读取, 要完全保证数据集的一致性, 必须保证数据集顺序的一致性, 即快照
4) 传统的分页, 分段式分页(每页内分为多段)归根结底是对数据集做一次切割, 映射到mysql的sql语法上, 就是根据输入求得limit子句, 适用场景为数据集变化频率低
5) since_id类分页, 其本质是假定已有数据无变化, 将数据集的某一个点的id(在数据集中可以绝对定位该数据的相关字段)提供给用户侧, 每次携带该id读取相应位置的数据, 以此模拟快照, 使用场景为数据集历史数据变化频率低, 新增数据频繁
6) 如果存在一个快照系统, 能够为每一个会话发起时的数据集产生一份快照数据, 那么一切问题都迎刃而解
7) 在没有快照系统的时候, 我们可以用since_id的方式限定数据范围, 模拟快照系统, 可以解决大多数问题
8) 要使用since_id方式模拟快照, 其数据集排序规则必须有能够唯一标识其每一个数据的字段(可能是复合的)
4. 实现思路
1) 提供SQL的转换函数
2) 支持分段式分页(page, page_ping, ping, ping_size), 传统分页(page, page_size), 原始分页(offset-count), since_id分页(prev_id, next_id)
3) 分段式分页, 传统分页, 原始分页在底层均转换为原始分页处理
5. 实现定义
ping_to_offset
输入:
page #请求页码, 范围: [1, total_page], 超过范围以边界计, 即0修正为1, total_page + 1修正为total_page
ping #请求段号, 范围: [1, page_ping], 超过范围以边界计, 即0修正为1, page_ping + 1修正为page_ping
page_ping #每页分段数, 范围: [1, 无穷]
count #要获取的记录数, 当前应用场景含义为: 每段记录数, 范围: [1, 无穷]
total_record #总记录数, 范围: [1, 无穷]
输出:
offset #偏移量
count #读取条数
offset_to_ping
输入:
offset #偏移量(必须按照count对齐, 即可以被count整除), 范围: [0, 无穷]
page_ping #每页分段数, 范围: [1, 无穷]
count #读取条数, 范围: [1, 无穷]
输出:
page #请求页码
ping #请求段号
page_ping #每页分段数
count #要获取的记录数, 当前应用场景含义为: 每段记录数
page_to_offset
输入:
page #请求页码, 范围: [1, total_page], 超过范围以边界计, 即0修正为1, total_page + 1修正为total_page
total_record #总记录数, 范围: [1, 无穷]
count #要获取的记录数, 当前应用场景含义为: 每页条数, 范围: [1, 无穷]
输出:
offset #偏移量
count #读取条数
offset_to_page
输入:
offset #偏移量(必须按照count对齐, 即可以被count整除), 范围: [0, 无穷]
count #读取条数, 范围: [1, 无穷]
输出:
page #请求页码
count #要获取的记录数, 当前应用场景含义为: 每页条数
sql_parser #将符合mysql语法规范的SQL语句解析得到各个组件
输入:
sql #要解析的sql语句
输出:
sql_components#SQL解析后的字段
sql_restore #将SQL语句组件集转换为SQL语句
输入:
sql_components#要还原的SQL语句组件集
输出:
sql #还原后的SQL语句
sql_to_count #将符合mysql语法规范的SELECT语句转换为获取计数
输入:
sql_components#要转换为查询计数的SQL语句组件集
alias #计数字段的别名
输出:
sql_components#转换后的查询计数SQL语句组件集
sql_add_offset
输入:
sql_components#要增加偏移的SQL语句组件集, 不允许存在LIMIT组件
offset #偏移量(必须按照count对齐, 即可以被count整除), 范围: [0, 无穷]
count #要获取的记录数, 范围: [1, 无穷]
输出:
sql_components#已增加LIMIT组件的SQL语句组件集
sql_add_since #增加since_id式的范围
输入:
sql_components#要增加范围限定的SQL语句组件集
prev_id #标记上一次请求得到的数据左边界
next_id #标记上一次请求得到的数据右边界
输出:
sql_components#增加since_id模拟快照的范围限定后的SQL语句组件集
datas_boundary#获取当前数据集的边界
输入:
sql_components#要读取的数据集对应的SQL语句组件集
datas #结果数据集
输出:
prev_id #当前数据集左边界
next_id #当前数据集右边界
mysql_paginate_query#执行分页支持的SQL语句
输入:
sql #要执行的业务SQL语句
offset #偏移量(必须按照count对齐, 即可以被count整除), 范围: [0, 无穷]
count #读取条数, 范围: [1, 无穷]
prev_id #标记上一次请求得到的数据左边界
next_id #标记上一次请求得到的数据右边界
输出:
datas #查询结果集
offset #偏移量
count #读取条数
prev_id #当前数据集的左边界
next_id #当前数据集的右边界
6. 实现的执行流程
分段式分页应用(page, ping, page_ping, count):
total_record = sql_to_count(sql);
(offset, count)= ping_to_offset(page, ping, page_ping, count, total_record)
(datas, offset, count)= mysql_paginate_query(sql, offset, count, NULL, NULL);
(page, ping, page_ping, total_record, count)= offset_to_ping(offset, page_ping, count, total_record);
return (datas, page, ping, page_ping, total_record, count);
传统分页应用(page, count):
total_record = sql_to_count(sql);
(offset, count)= page_to_offset(page, count, total_record)
(datas, offset, count)= mysql_paginate_query(sql, offset, count, NULL, NULL);
(page, total_record, count)= offset_to_page(offset, count, total_record);
return (datas, page, total_record, count);
since_id分页应用(count, prev_id, next_id):
total_record = sql_to_count(sql);
(datas, offset, count, prev_id, next_id)= mysql_paginate_query(sql, NULL, count, prev_id, next_id);
return (count, prev_id, next_id);
复合型分段式分页应用(page, ping, page_ping, count, prev_id, next_id):
total_record = sql_to_count(sql);
(offset, count)= ping_to_offset(page, ping, page_ping, count, total_record)
(datas, offset, count, prev_id, next_id)= mysql_paginate_query(sql, offset, count, prev_id, next_id);
(page, ping, page_ping, total_record, count)= offset_to_ping(offset, page_ping, count, total_record);
return (datas, page, ping, page_ping, total_record, count, prev_id, next_id);
复合型传统分页应用(page, count, prev_id, next_id):
total_record = sql_to_count(sql);
(offset, count)= page_to_offset(page, count, total_record)
(datas, offset, count, prev_id, next_id)= mysql_paginate_query(sql, offset, count, prev_id, next_id);
(page, total_record, count)= offset_to_page(offset, count, total_record);
return (datas, page, total_record, count, prev_id, next_id);
mysql_paginate_query(sql, offset, count, prev_id, next_id)
need_offset = is_null(offset);
need_since = is_null(prev_id) || is_null(next_id);
sql_components= sql_parser(sql);
if ( need_offset ) :
sql_components= sql_add_offset(sql_components, offset, count);
endif
if ( need_since ) :
sql_components= sql_add_since(sql_components, prev_id, next_id);
endif
sql = sql_restore(sql_components);
datas = mysql_execute(sql);
(prev_id, next_id)= datas_boundary(sql_components, datas);
ret = (datas);
if ( need_offset ) :
append(ret, offset, count);
endif
if ( need_since ) :
append(ret, prev_id, next_id);
endif
return (ret);
7. 测试点
1) 传统分页
2) 分段分页
3) 原始分页
4) since_id分页
5) 复合型传统分页
6) 复合型分段分页
7) 复合型原始分页
8. 测试数据构建
DROP DATABASE IF EXISTS `paginate_test`;
CREATE DATABASE IF NOT EXISTS `paginate_test`;
USE `paginate_test`;


DROP TABLE IF EXISTS `feed`;
CREATE TABLE IF NOT EXISTS `feed` (
`feed_id` INT NOT NULL PRIMARY KEY AUTO_INCREMENT COMMENT '微博ID', 
`ctime` INT NOT NULL COMMENT '微博创建时间', 
`content` CHAR(20) NOT NULL DEFAULT '' COMMENT '微博内容', 
`transpond_count` INT NOT NULL DEFAULT 0 COMMENT '微博转发数'
) COMMENT '微博表';


DROP TABLE IF EXISTS `comment`;
CREATE TABLE IF NOT EXISTS `comment` (
`comment_id` INT NOT NULL PRIMARY KEY AUTO_INCREMENT COMMENT '评论ID', 
`content` CHAR(20) NOT NULL DEFAULT '' COMMENT '评论内容', 
`feed_id` INT NOT NUL COMMENT '被评论微博ID'
) COMMENT '评论表';


DROP TABLE IF EXISTS `hot`;
CREATE TABLE IF NOT EXISTS `hot` (
`feed_id` INT NOT NULL PRIMARY KEY AUTO_INCREMENT COMMENT '微博ID', 
`hot` INT NOT NULL DEFAULT 0 COMMENT '微博热度'
) COMMENT '热点微博表';
9. 测试用例:
1) 搜索最热微博(SELECT f.feed_id, f.content, h.hot FROM feed AS f JOIN hot AS h ON f.feed_id = h.feed_id ORDER BY hhot DESC, f.feed_id DESC)
2) 搜索热评微博(SELECT f.feed_id, f.content, COUNT(c.*) AS count FROM feed AS f JOIN comment AS c ON f.feed_id = c.feed_id GROUP BY c.feed_id ORDER BY count DESC, f.feed_id DESC)
3) 搜索热转微博(SELECT feed_id, content, transpond_count FROM feed ORDER BY transpond_count DESC, feed_id DESC)
4) 上面3种场景均测试7个测试点
10. 文件列表
readme.txt 当前您正在阅读的开发文档
page.lib.php 分页程序库
test_base.php 单元测试基础函数
test_convert.php不同分页之间的转换单元测试
test_parse.phpSQL语句解析测试

test_page.php分页测试


下面是源代码:

page.lib.php

<?php/* * 分页程序 分页测试 * author: selfimpr * blog: http://blog.csdn.net/lgg201 * mail: lgg860911@yahoo.com.cn */require dirname(__FILE__) . '/test_base.php';#初始化数据量define('FEED_ID_MIN',1000);define('FEED_COUNT',972);define('COMMENT_ID_MIN',1000);define('COMMENT_MAX_COUNT',10);define('HOT_MIN',1);define('HOT_MAX',100);define('TRANSPOND_COUNT_MAX',100);#数据库信息$db_host= '127.0.0.1';$db_port= '3306';$db_user= 'paginate_test';$db_pass= 'paginate_test';$db_db= 'paginate_test';$db_charset= 'UTF-8';#全局数据变量名define('ALL_DATAS','_all_datas');#涉及到的keydefine('K_HC_FEEDS','_hc_feed');define('K_TC_FEEDS','_tc_feed');define('K_CC_FEEDS','_cc_feed');define('K_FEED_ID','feed_id');#转发比较函数function comp_transpond_count($a, $b) {$tc= $b['transpond_count'] - $a['transpond_count'];$ic= $b['feed_id'] - $a['feed_id'];return $tc != 0 ? $tc : $ic;}#评论比较函数function comp_comment_count($a, $b) {$cc= $b['comment_count'] - $a['comment_count'];$ic= $b['feed_id'] - $a['feed_id'];return $cc != 0 ? $cc : $ic;}#热点比较函数function comp_hot($a, $b) {$hc= $b['hot'] - $a['hot'];$ic= $b['feed_id'] - $a['feed_id'];return $hc != 0 ? $hc : $ic;}#数据库初始化临时文件$tmp_file= '/tmp/__paginate_test_tmp.sql';#数据库创建脚本$db_init= <<<docDROP DATABASE IF EXISTS `paginate_test`;CREATE DATABASE IF NOT EXISTS `paginate_test`;USE `paginate_test`;DROP TABLE IF EXISTS `feed`;CREATE TABLE IF NOT EXISTS `feed` (`feed_id` INT NOT NULL PRIMARY KEY AUTO_INCREMENT COMMENT '微博ID', `ctime` INT NOT NULL COMMENT '微博创建时间', `content` CHAR(100) NOT NULL DEFAULT '' COMMENT '微博内容', `transpond_count` INT NOT NULL DEFAULT 0 COMMENT '微博转发数') COMMENT '微博表';DROP TABLE IF EXISTS `comment`;CREATE TABLE IF NOT EXISTS `comment` (`comment_id` INT NOT NULL PRIMARY KEY AUTO_INCREMENT COMMENT '评论ID', `content` CHAR(100) NOT NULL DEFAULT '' COMMENT '评论内容', `feed_id` INT NOT NULL COMMENT '被评论微博ID') COMMENT '评论表';DROP TABLE IF EXISTS `hot`;CREATE TABLE IF NOT EXISTS `hot` (`feed_id` INT NOT NULL PRIMARY KEY AUTO_INCREMENT COMMENT '微博ID', `hot` INT NOT NULL DEFAULT 0 COMMENT '微博热度') COMMENT '热点微博表';doc;#初始化数据库function init_db() {global $db_host, $db_port, $db_user, $db_pass, $db_db, $db_init, $tmp_file;$datas= generate_data();file_put_contents($tmp_file, $db_init . chr(10) . data_to_sql($datas));`mysql -u$db_user -p$db_pass -h$db_host -P$db_port $db_db -e 'SOURCE $tmp_file' && rm $tmp_file`;$tc_datas= $datas;$cc_datas= $datas;$hc_datas= $datas;foreach ( $cc_datas as $k => $v ) if ( count($v['comments']) <= 0 ) unset($cc_datas[$k]);usort($tc_datas, 'comp_transpond_count');usort($cc_datas, 'comp_comment_count');usort($hc_datas, 'comp_hot');$GLOBALS[ALL_DATAS]= array(K_TC_FEEDS=> $tc_datas, K_CC_FEEDS=> $cc_datas, K_HC_FEEDS=> $hc_datas, );}#生成测试数据function generate_data() {$i= -1;$j= 0;$feeds= array();while ( ++ $i < FEED_COUNT ) {$feed_id= FEED_ID_MIN + $i;$ctime= time();$transpond_count= rand(0, TRANSPOND_COUNT_MAX);$hot= rand(HOT_MIN, HOT_MAX);$comments= array();$comment_count= rand(0, COMMENT_MAX_COUNT);$k= -1;while ( ++ $k < $comment_count ) {$comment_id= COMMENT_ID_MIN + $j ++;$comments[]= array('content'=> sprintf('cid: %d, fid: %d, ccnt: %d, tcnt: %d, hot: %d', $comment_id, $feed_id, $comment_count, $transpond_count, $hot), 'comment_id'=> $comment_id, );}$feeds[]= array('feed_id'=> $feed_id, 'content'=> sprintf('fid: %d, ccnt: %d, tcnt: %d, hot: %d', $feed_id, $comment_count, $transpond_count, $hot), 'comments'=> $comments, 'comment_count'=> $comment_count, 'transpond_count'=> $transpond_count, 'hot'=> $hot, 'ctime'=> $ctime, );}return $feeds;}#将生成的测试数据转换为sql语句function data_to_sql($feeds) {$feed_sql= 'INSERT INTO feed(feed_id, ctime, content, transpond_count) VALUES ';$comment_sql= 'INSERT INTO comment(comment_id, content, feed_id) VALUES ';$hot_sql= 'INSERT INTO hot(feed_id, hot) VALUES ';foreach ( $feeds AS $feed ) {$feed_sql.= sprintf('(%d, %d, "%s", %d), ', $feed['feed_id'], $feed['ctime'], $feed['content'], $feed['transpond_count']);if ( !empty($feed['comments']) )foreach ( $feed['comments'] as $comment ) $comment_sql.= sprintf('(%d, "%s", %d), ', $comment['comment_id'], $comment['content'], $feed['feed_id']);$hot_sql.= sprintf('(%d, %d), ', $feed['feed_id'], $feed['hot']);}return substr($feed_sql, 0, strlen($feed_sql) - 2) . ";\n" . substr($comment_sql, 0, strlen($comment_sql) - 2) .  ";\n" . substr($hot_sql, 0, strlen($hot_sql) - 2);}#格式化打印测试数据function print_feeds($feeds) {foreach ( $feeds as $feed ) {printf("\tfeed_id: %d, transpond_count: %d, hot: %d, content: '%s'\n", $feed['feed_id'], $feed['transpond_count'], $feed['hot'], $feed['content']);foreach ( $feed['comments'] as $comment ) {printf("\t\tcomment_id: %d, content: '%s'\n", $comment['comment_id'], $comment['content']);}}}#格式化打印所有测试数据function print_all_feeds($all_feeds) {foreach ( $all_feeds as $key => $feeds ) {printf("order type: %s\n", $key);print_feeds($feeds);printf("\n\n");}}#基本断言函数function assert_base($info, $datas, $offset, $count, $file, $line, $sign) {assert_info($file, $line, $sign . ':count');assert(intval($count) === count(p_datas($info)));assert_info($file, $line, $sign . ':datas');if ( is_array(p_datas($info)) )foreach ( p_datas($info) as $data ) assert(intval($data[K_FEED_ID]) == intval($datas[$offset ++][K_FEED_ID]));}#断言热门数据function assert_hot($info, $offset, $count, $file, $line) {assert_base($info, $GLOBALS[ALL_DATAS][K_HC_FEEDS], $offset, $count, $file, $line, __FUNCTION__);}#断言热转数据function assert_transpond($info, $offset, $count, $file, $line) {assert_base($info, $GLOBALS[ALL_DATAS][K_TC_FEEDS], $offset, $count, $file, $line, __FUNCTION__);}#断言热评数据function assert_comment($info, $offset, $count, $file, $line) {assert_base($info, $GLOBALS[ALL_DATAS][K_CC_FEEDS], $offset, $count, $file, $line, __FUNCTION__);}#初始化数据库连接function init_conn() {global $db_host, $db_port, $db_user, $db_pass, $db_db, $db_charset;static $conn;if ( is_null($conn) ) {$conn= mysql_connect($db_host . ':' . $db_port, $db_user, $db_pass);mysql_select_db($db_db, $conn);mysql_set_charset($db_charset, $conn);}return $conn;}#单纯传统分页测试function test_tradition($sql, $assert, $total_record) {$total_page= ceil($total_record / 10);$remain= $total_record % 10 ? $total_record % 10 : 10;$info= mysql_paginate_tradition(init_conn(), $sql, -1, 10);$assert($info, 0, 10, __FILE__, __LINE__);$info= mysql_paginate_tradition(init_conn(), $sql, 1, 10);$assert($info, 0, 10, __FILE__, __LINE__);$info= mysql_paginate_tradition(init_conn(), $sql, 2, 10);$assert($info, 10, 10, __FILE__, __LINE__);$info= mysql_paginate_tradition(init_conn(), $sql, 2, 10);$assert($info, 10, 10, __FILE__, __LINE__);$info= mysql_paginate_tradition(init_conn(), $sql, $total_page - 1, 10);$assert($info, ($total_page - 2) * 10, 10, __FILE__, __LINE__);$info= mysql_paginate_tradition(init_conn(), $sql, $total_page, 10);$assert($info, ($total_page - 1) * 10, $remain, __FILE__, __LINE__);$info= mysql_paginate_tradition(init_conn(), $sql, $total_page + rand(1, 10), 10);$assert($info, ($total_page - 1) * 10, $remain, __FILE__, __LINE__);}#单纯分段分页测试function test_ping($sql, $assert, $total_record) {$total_ping= ceil($total_record / 10);$total_page= ceil($total_ping / 3);$remain= $total_record % 10 ? $total_record % 10 : 10;$remain_ping= $total_ping % 3 ? $total_ping % 3 : 3;$info= mysql_paginate_ping(init_conn(), $sql, -1, -1, 3, 10);$assert($info, 0, 10, __FILE__, __LINE__);$info= mysql_paginate_ping(init_conn(), $sql, -1, 2, 3, 10);$assert($info, 10, 10, __FILE__, __LINE__);$info= mysql_paginate_ping(init_conn(), $sql, 1, 3, 3, 10);$assert($info, 20, 10, __FILE__, __LINE__);$info= mysql_paginate_ping(init_conn(), $sql, 1, 4, 3, 10);$assert($info, 20, 10, __FILE__, __LINE__);$info= mysql_paginate_ping(init_conn(), $sql, 5, 2, 3, 10);$assert($info, 130, 10, __FILE__, __LINE__);$info= mysql_paginate_ping(init_conn(), $sql, $total_page, $remain_ping, 3, 10);$assert($info, ($total_ping - 1) * 10, $remain, __FILE__, __LINE__);$info= mysql_paginate_ping(init_conn(), $sql, $total_page + rand(1, 10), $remain_ping, 3, 10);$assert($info, ($total_ping - 1) * 10, $remain, __FILE__, __LINE__);}#单纯原始分页测试function test_raw($sql, $assert, $total_record) {$remain= $total_record % 10 ? $total_record % 10 : 10;$info= mysql_paginate_raw(init_conn(), $sql, -1, 10);$assert($info, 0, 10, __FILE__, __LINE__);$info= mysql_paginate_raw(init_conn(), $sql, 100, 10);$assert($info, 100, 10, __FILE__, __LINE__);$info= mysql_paginate_raw(init_conn(), $sql, ($total_record - $remain), 10);$assert($info, ($total_record - $remain), $remain, __FILE__, __LINE__);}#单纯since_id分页测试function test_since_id($sql, $assert) {#第一页$info_0= mysql_paginate_since_id(init_conn(), $sql, 10);$assert($info_0, 0, 10, __FILE__, __LINE__);#无数据(第一页之前$info_1= mysql_paginate_since_id(init_conn(), $sql, 10, p_prev_id($info_0));$assert($info_1, 0, 0, __FILE__, __LINE__);#第二页$info_2= mysql_paginate_since_id(init_conn(), $sql, 10, NULL, p_next_id($info_0));$assert($info_2, 10, 10, __FILE__, __LINE__);#第三页$info_3= mysql_paginate_since_id(init_conn(), $sql, 10, NULL, p_next_id($info_2));$assert($info_3, 20, 10, __FILE__, __LINE__);#第四页$info_4= mysql_paginate_since_id(init_conn(), $sql, 10, NULL, p_next_id($info_3));$assert($info_4, 30, 10, __FILE__, __LINE__);#第三页$info_5= mysql_paginate_since_id(init_conn(), $sql, 10, p_prev_id($info_4), NULL);$assert($info_5, 20, 10, __FILE__, __LINE__);#第二页(第二页至第三页之间的前10条)$info_5= mysql_paginate_since_id(init_conn(), $sql, 10, p_next_id($info_0), p_prev_id($info_4));$assert($info_5, 10, 10, __FILE__, __LINE__);}#传统分页复合since_id分页测试function test_tradition_since_id($sql, $assert, $total_record) {$total_page= ceil($total_record / 10);$remain= $total_record % 10 ? $total_record % 10 : 10;$info= mysql_paginate_tradition_since_id(init_conn(), $sql, -1, 10);$assert($info, 0, 10, __FILE__, __LINE__);$info= mysql_paginate_tradition_since_id(init_conn(), $sql, 2, 10);$assert($info, 10, 10, __FILE__, __LINE__);$info= mysql_paginate_tradition_since_id(init_conn(), $sql, $total_page - 1, 10);$assert($info, ($total_page - 2) * 10, 10, __FILE__, __LINE__);$info= mysql_paginate_tradition_since_id(init_conn(), $sql, $total_page, 10);$assert($info, ($total_page - 1) * 10, $remain, __FILE__, __LINE__);#第一页$info_0= mysql_paginate_tradition_since_id(init_conn(), $sql, 1, 10, TRUE, TRUE);$assert($info_0, 0, 10, __FILE__, __LINE__);#无数据(第一页之前)$info_1= mysql_paginate_tradition_since_id(init_conn(), $sql, 1, 10, p_prev_id($info_0));$assert($info_1, 0, 0, __FILE__, __LINE__);#第二页$info_2= mysql_paginate_tradition_since_id(init_conn(), $sql, 1, 10, NULL, p_next_id($info_0));$assert($info_2, 10, 10, __FILE__, __LINE__);#第三页$info_3= mysql_paginate_tradition_since_id(init_conn(), $sql, 1, 10, NULL, p_next_id($info_2));$assert($info_3, 20, 10, __FILE__, __LINE__);#第二页$info_4= mysql_paginate_tradition_since_id(init_conn(), $sql, 1, 10, p_prev_id($info_3));$assert($info_4, 10, 10, __FILE__, __LINE__);#第四页$info_5= mysql_paginate_tradition_since_id(init_conn(), $sql, 1, 10, NULL, p_next_id($info_3));$assert($info_5, 30, 10, __FILE__, __LINE__);#第三页$info_6= mysql_paginate_tradition_since_id(init_conn(), $sql, 2, 10, NULL, p_next_id($info_0));$assert($info_6, 20, 10, __FILE__, __LINE__);#第八页$info_7= mysql_paginate_tradition_since_id(init_conn(), $sql, 7, 10, NULL, p_next_id($info_0));$assert($info_7, 70, 10, __FILE__, __LINE__);#最后一页$info_8= mysql_paginate_tradition_since_id(init_conn(), $sql, $total_page - 1, 10, NULL, p_next_id($info_0));$assert($info_8, ($total_page - 1) * 10, $remain, __FILE__, __LINE__);#(TODO 分段分页/传统分页/原始分页与since_id分页联合使用时, 记录数是since_id条件附加之前的记录数, 因此会导致页码数据错乱, 目前不对此进行处理)#越界访问$info_8= mysql_paginate_tradition_since_id(init_conn(), $sql, $total_page, 10, NULL, p_next_id($info_0));$assert($info_8, 0, 0, __FILE__, __LINE__);}#分段分页复合since_id分页测试function test_ping_since_id($sql, $assert, $total_record) {$total_ping= ceil($total_record / 10);$total_page= ceil($total_ping / 3);$remain= $total_record % 10 ? $total_record % 10 : 10;$remain_ping= $total_ping % 3 ? $total_ping % 3 : 3;$info= mysql_paginate_ping_since_id(init_conn(), $sql, -1, -1, 3, 10);$assert($info, 0, 10, __FILE__, __LINE__);$info= mysql_paginate_ping_since_id(init_conn(), $sql, -1, 2, 3, 10);$assert($info, 10, 10, __FILE__, __LINE__);$info= mysql_paginate_ping_since_id(init_conn(), $sql, 1, 3, 3, 10);$assert($info, 20, 10, __FILE__, __LINE__);$info= mysql_paginate_ping_since_id(init_conn(), $sql, 1, 4, 3, 10);$assert($info, 20, 10, __FILE__, __LINE__);$info= mysql_paginate_ping_since_id(init_conn(), $sql, 5, 2, 3, 10);$assert($info, 130, 10, __FILE__, __LINE__);$info= mysql_paginate_ping_since_id(init_conn(), $sql, $total_page, $remain_ping, 3, 10);$assert($info, ($total_ping - 1) * 10, $remain, __FILE__, __LINE__);$info= mysql_paginate_ping_since_id(init_conn(), $sql, $total_page + rand(1, 10), $remain_ping, 3, 10);$assert($info, ($total_ping - 1) * 10, $remain, __FILE__, __LINE__);#第一页第一段$info_0= mysql_paginate_ping_since_id(init_conn(), $sql, 1, 1, 3, 10, TRUE, TRUE);$assert($info_0, 0, 10, __FILE__, __LINE__);#无数据(第一页之前)$info_1= mysql_paginate_ping_since_id(init_conn(), $sql, 1, 1, 3, 10, p_prev_id($info_0));$assert($info_1, 0, 0, __FILE__, __LINE__);#第一页第二段$info_2= mysql_paginate_ping_since_id(init_conn(), $sql, 1, 1, 3, 10, NULL, p_next_id($info_0));$assert($info_2, 10, 10, __FILE__, __LINE__);#第一页第三段$info_3= mysql_paginate_ping_since_id(init_conn(), $sql, 1, 1, 3, 10, NULL, p_next_id($info_2));$assert($info_3, 20, 10, __FILE__, __LINE__);#第一页第二段$info_4= mysql_paginate_ping_since_id(init_conn(), $sql, 1, 1, 3, 10, p_prev_id($info_3));$assert($info_4, 10, 10, __FILE__, __LINE__);#第一页第一段$info_5= mysql_paginate_ping_since_id(init_conn(), $sql, 1, 1, 3, 10, NULL, p_next_id($info_3));$assert($info_5, 30, 10, __FILE__, __LINE__);#第一页第三段$info_6= mysql_paginate_ping_since_id(init_conn(), $sql, 1, 2, 3, 10, NULL, p_next_id($info_0));$assert($info_6, 20, 10, __FILE__, __LINE__);#第七页第三段$info_7= mysql_paginate_ping_since_id(init_conn(), $sql, 7, 2, 3, 10, NULL, p_next_id($info_0));$assert($info_7, 200, 10, __FILE__, __LINE__);#倒数第二页最后一段$info_9= mysql_paginate_ping_since_id(init_conn(), $sql, $total_page - 1, 2, 3, 10, NULL, p_next_id($info_0));$assert($info_9, ($total_ping - $remain_ping - 1) * 10, 10, __FILE__, __LINE__);#(TODO 分段分页/传统分页/原始分页与since_id分页联合使用时, 记录数是since_id条件附加之前的记录数, 因此会导致页码数据错乱, 目前不对此进行处理)#越界访问$info_10= mysql_paginate_ping_since_id(init_conn(), $sql, $total_page + rand(1, 10), 3, 3, 10, NULL, p_next_id($info_0));$assert($info_10, 0, 0, __FILE__, __LINE__);}#原始分页复合since_id分页测试function test_raw_since_id($sql, $assert, $total_record) {$remain= $total_record % 10 ? $total_record % 10 : 10;$info= mysql_paginate_raw_since_id(init_conn(), $sql, -1, 10);$assert($info, 0, 10, __FILE__, __LINE__);$info= mysql_paginate_raw_since_id(init_conn(), $sql, 100, 10);$assert($info, 100, 10, __FILE__, __LINE__);$info= mysql_paginate_raw_since_id(init_conn(), $sql, $total_record - $remain, 10);$assert($info, $total_record - $remain, $remain, __FILE__, __LINE__);#第一页$info_0= mysql_paginate_raw_since_id(init_conn(), $sql, 0, 10, TRUE, TRUE);$assert($info_0, 0, 10, __FILE__, __LINE__);#无数据(第一页之前)$info_1= mysql_paginate_raw_since_id(init_conn(), $sql, 0, 10, p_prev_id($info_0));$assert($info_1, 0, 0, __FILE__, __LINE__);#第二页$info_2= mysql_paginate_raw_since_id(init_conn(), $sql, 0, 10, NULL, p_next_id($info_0));$assert($info_2, 10, 10, __FILE__, __LINE__);#第三页$info_3= mysql_paginate_raw_since_id(init_conn(), $sql, 0, 10, NULL, p_next_id($info_2));$assert($info_3, 20, 10, __FILE__, __LINE__);#第二页$info_4= mysql_paginate_raw_since_id(init_conn(), $sql, 0, 10, p_prev_id($info_3));$assert($info_4, 10, 10, __FILE__, __LINE__);#第四页$info_5= mysql_paginate_raw_since_id(init_conn(), $sql, 0, 10, NULL, p_next_id($info_3));$assert($info_5, 30, 10, __FILE__, __LINE__);#最后一页$info_6= mysql_paginate_raw_since_id(init_conn(), $sql, $total_record - $remain - 10, 10, NULL, p_next_id($info_0));$assert($info_6, $total_record - $remain, $remain, __FILE__, __LINE__);#(TODO 分段分页/传统分页/原始分页与since_id分页联合使用时, 记录数是since_id条件附加之前的记录数, 因此会导致页码数据错乱, 目前不对此进行处理)#越界访问$info_7= mysql_paginate_raw_since_id(init_conn(), $sql, 970, 10, NULL, p_next_id($info_0));$assert($info_7, 0, 0, __FILE__, __LINE__);}#初始化数据init_db();$h_sql= 'SELECT f.feed_id, f.content, h.hot FROM feed AS f JOIN hot AS h ON f.feed_id = h.feed_id ORDER BY h.hot DESC, f.feed_id DESC';$c_sql= 'SELECT f.feed_id, f.content, COUNT(c.comment_id) AS count FROM feed AS f JOIN comment AS c ON f.feed_id = c.feed_id GROUP BY c.feed_id ORDER BY COUNT(c.comment_id) DESC, f.feed_id DESC';$t_sql= 'SELECT feed_id, content, transpond_count FROM feed ORDER BY transpond_count DESC, feed_id DESC';$data_infos= array(array($c_sql, 'assert_comment', count($GLOBALS[ALL_DATAS][K_CC_FEEDS])), array($h_sql, 'assert_hot', count($GLOBALS[ALL_DATAS][K_HC_FEEDS])), array($t_sql, 'assert_transpond', count($GLOBALS[ALL_DATAS][K_TC_FEEDS])), );$use_cases= array('test_tradition', 'test_ping', 'test_raw', 'test_since_id', 'test_tradition_since_id', 'test_ping_since_id', 'test_raw_since_id', );foreach ( $data_infos as $data_info ) {foreach ( $use_cases as $use_case )call_user_func_array($use_case, $data_info);}

热点排行