php+mysql缓存技术的实现
本教程适合于那些对缓存SQL查询以减少数据库连接与执行的负载、提高脚本性能感兴趣的PHP程序员。
概述
许多站点使用数据库作为站点数据存储的容器。数据库包含了产器信息、目录结构、文章或者留言本,有些数据很可能是完全静态的,这些将会从一个缓存系统中得到的极大好处。
这样一个系统通过把SQL查询的结果缓存到系统的一个文件中存储,从而阻止连接数据库,构造查询与取得返回结果而提高了响应时间。
有些系统数据库并不是放在WEB服务器上的,这样需要一个远程连接(TCP或者其它类似的),或者从数据库中获取大量的数据,这样你得忍受更多时间,这决定于系统响应时间与资源利用。
前提
本教程使用MySQL作为数据库。你需要安装MySQL(www.mysql.com下载是有效的)和激活PHP MYSQL扩展(默认情况是激活的)。
由于要查询数据库,你需要知识一些SQL(结构化查询语言)的基本常识。
缓存SQL查询结果
为什么要缓存查询结果?
缓存查询结果能极大地改进脚本执行时间和资源需求。
缓存SQL查询结果也允许你通过后期处理数据。如果你用文件缓存去存储全部脚本的输出结果(HTML输出),这样可能是行不通的。
当你执行一个SQL查询时,点典的处理过程是:
<!--[if !supportLists]-->l <!--[endif]-->连接数据库
<!--[if !supportLists]-->l <!--[endif]-->准备SQL查询
<!--[if !supportLists]-->l <!--[endif]-->发送查询到数据库
<!--[if !supportLists]-->l <!--[endif]-->取得返回结果
<!--[if !supportLists]-->l <!--[endif]-->关闭数据库连接
以上方法非常占用资源并且相反的影响了脚本的性能。只能通过取得的大量返回数据和数据库服务器的位置这二个要素来相互协调。尽管持续连接可以改进连接数据库时的负载,但非常耗费内存资源,如果获取的是大量的数据,那么存储的全部时间会非常短暂。
创建一条SQL查询:
SQL(结构化查询语言)查询被用作操作数据库及它内容的接口。SQL可用于定义和编辑表的结构,插入数据到表,更新或删除表中的信息。
SQL是用于与数据通讯的语言,在大多数PHP数据库扩展(MySQL,ODBC,Oracle等)通过传递SQL查询到数据库中来管理整个过程。
本教程中,仅仅用select语言来获取数据库中的数据。这些数据将被缓存,之后将用作数据源。
决定什么时候更新缓存:
根据程序的需要,缓存可以采取多种形式。最常见的3种方式是:
<!--[if !supportLists]-->l <!--[endif]-->时间触发缓存(过期的时间戳)
<!--[if !supportLists]-->l <!--[endif]-->内容改变触发缓存(发现数据改变后,相应地更新缓存)
<!--[if !supportLists]-->l <!--[endif]-->人工触发缓存(人工的方式告知系统信息超期并且强制产生新的缓存)
你的缓存需求可能是以上原理的一个或多个的综合。本教程将讨论时间触发方式。然而,在一个全面的缓存机制中,3种方式的综合将被使用。
缓存结果:
基本的缓存是用PHP的两个函数serialize()和unserialize()(译注:这二个函数分别代表序列化与反序列化)。
函数serialize()用于存储PHP的值,它能保证不失去这些值的类型和结构。
事实上,PHP的session扩展是用序列化过的变量,把session变量($_SESSION)存储在系统的一个文件中。
函数unserialize()与以上操作相反并且使序列化过的字符串返回到它原来的结构和数据内容。
在本例中,以一个电子商务商店为例。商店有2个基本表,categories和products(此处为原始数据库表名).product表可能每天都在变化,categories仍然是不变静止的。
要显示产品,你可以用一个输出缓存脚本来存储输出的HTML结果到一个文件中。然而categories表可能需要后期处理。例如,所有的目录通过变量 category_id(通过$_REQUEST['category_id']来取得)被显示,你可能希望高亮当前被选择的目录。
表categories结构
Field Type Key Extra
category_id int(10) unsigned PRI auto_incremen
category_name varchar(255)
category_description text
在本例中,通过时间触发缓存技术被运用,设定一段时间后让其缓存SQL输出过期。在此特殊的例子中,定一段时间为24小时。
序列化例子:
<!--[if !supportLists]-->l <!--[endif]-->连接数据库
<!--[if !supportLists]-->l <!--[endif]-->执行查询
<!--[if !supportLists]-->l <!--[endif]-->取得所有结果构成一个数组以便后面你可以访问
<!--[if !supportLists]-->l <!--[endif]-->序列化数组
<!--[if !supportLists]-->l <!--[endif]-->保存序列化过的数组到文件中*/
$file = 'sql_cache.txt';
$link = mysql_connect('localhost','username','password') or die (mysql_error());
mysql_select_db('shop') or die (mysql_error());
/* 构造SQL查询 */
$query = "SELECT * FROM categories";
$result = mysql_query($query) or die (mysql_error());
while ($record = mysql_fetch_array($result) ){
$records[] = $record;
}
$OUTPUT = serialize($records);
$fp = fopen($file,"w"); // 以写权限的方式打开文件
fputs($fp, $OUTPUT);
//fwrite($fp,$OUTPUT);
fclose($fp);
/*查看sql_cache.txt文件,里面的内容可能类似这样的:
a:1:{i:0;a:6:{i:0;s:1:"1";s:11:"category_id";s:1:"1";i:1;s:9:"Computers";s:13:"category_name";s:9:"Computers" ;i:2;s:25:"Description for computers";s:20:"category_description";s:25:"Description for computers";}}
这个输出是它的变量和类型的内部表现形式。假若你用mysql_fetch_array()函数返回数字索引的数组和一个关联的数组(这就是为什么数据看起来像是发生了两次),一个是数字索引,另一个是字符串索引。
使用缓存:
要用缓存,你需要用函数unserialize()来使数据还原成原始格式与类型。
你可以用file_get_contents()这个函数来读取sql_cache.txt文件的内容,把它赋给一个变量。
请注意:这个函数在PHP4.3.0及以上版本有效。若你使用的是一个老版本的PHP,一个简单的方法是用file()函数(读整个文件到一个数组,每行变成一个数组)。implode()函数用于把数组的各元素连接成一个字符串然后使用unserialize()反序列化。*/
// file_get_contents() 适合于for PHP < 4.3.0
$file = 'sql_cache.txt';
$records = unserialize(implode('',file($file)));
//现在你可以通过$records数组并且取得原始查询的数据:
foreach ($records as $id=>$row) {
print $row['category_name']."<br>";
}
/* 注意$records是数组(一个包含了查询结果的数字索引列——每行是一个数字和一个字符串...真是混乱)的一排。
把它们放在一块:
基于本例子中的时间来决定是否缓存。如果文件修改的时间戳比当前时间戳减去过期时间戳大,那么就用缓存,否则更新缓存。
<!--[if !supportLists]-->l <!--[endif]-->检查文件是否存在并且时间戳小于设置的过期时间
<!--[if !supportLists]-->l <!--[endif]-->获取存储在缓存文件中的记录或者更新缓存文件
$file = 'sql_cache.txt';*/
$expire = 86400; // 24 小时 (单位:秒)
if (file_exists($file)&&filemtime($file) > (time() - $expire)){
// 取得缓存中的记录
$records = unserialize(file_get_contents($file));
} else {
// 通过 serialize() 函数创建缓存
}
/*附加其它可能的:
<!--[if !supportLists]-->l <!--[endif]-->把缓存结果存储在共享内存中以获取更快的速度
<!--[if !supportLists]-->l <!--[endif]-->增加一个功能随机地运行SQL查询并且检查是否输出与缓存输出一致。如果不一致,则更新缓存(本函数运行次数的概率可以定为1/100)。通过哈希算法(如MD5())可以协助判断字符串或者文件是否改变。
<!--[if !supportLists]-->l <!--[endif]-->增加一个管理员的功能,人工的删除这个缓存文件,以强制更新缓存(如file_exists()函数返回 false时)。你可以用函数unlink()删除文件。
脚本:*/
$file = 'sql_cache.txt';
$expire = 86400; // 24 小时
if (file_exists($file)&&filemtime($file) > (time() - $expire)) {
$records = unserialize(file_get_contents($file));
//$records=unserialize(fread($file,filesize($file)));
} else {
$link = mysql_connect('localhost','username','password') or die (mysql_error());
mysql_select_db('shop') or die (mysql_error());
/* 构造SQL查询 */
$query = "SELECT * FROM categories";
$result = mysql_query($query) or die (mysql_error());
while ($record = mysql_fetch_array($result) ) {
$records[] = $record;
}
$OUTPUT = serialize($records);
$fp = fopen($file,"w");
//fputs($fp, $OUTPUT);
fwrite($fp,$OUTPUT);
fclose($fp);
} // end else
// 查询结果在数组 $records 中
foreach ($records as $id=>$row) {
if ($row['category_id'] == $_REQUEST['category_id']) {
// 被选择的目录显示粗体字
print '<B>'.$row['category_name'].'</B><BR>';
} else {
// 其它目录显示用常规字体
print $row['category_name'].'<br>';
}
} // end foreach
php+mysql缓存技术的实现的更多相关文章
- php缓存技术总结
缓存是指临时文件交换区,电脑把最常用的文件从存储器里提出来临时放在缓存里,就像把工具和材料搬上工作台一样,这样会比用时现去仓库取更方便.因为缓存往往使用的是RAM(断电即掉的非永久储存), ...
- 网站缓存技术总结( ehcache、memcache、redis对比)
网站技术高速发展的今天,缓存技术已经成为大型网站的一个关键技术,缓存设计好坏直接关系的一个网站访问的速度,以及购置服务器的数量,甚至影响到用户的体验. 网站缓存按照存放的地点不同,可以分为客户端缓存. ...
- PHP网页缓存技术
http://blog.sina.com.cn/s/blog_646e51c40100weu9.html 前台静态化:把动态页面解析后保存为静态页面 文件缓存:把查询结果保存为文件,XML 内存缓存: ...
- ThinkPHP的缓存技术
原文:ThinkPHP的缓存技术 如果没有缓存的网站是百万级或者千万级的访问量,会给数据库或者服务器造成很大的压力,通过缓存,大幅减少服务器和数据库的负荷.假如我们 把读取数据的过程分为三个层,第一个 ...
- 详细讲解PHP中缓存技术的应用
PHP,一门最近几年兴起的web设计脚本语言,由于它的强大和可伸缩性,近几年来得到长足的发展,php相比传统的asp网站,在速度上有绝对的优势,想mssql转6万条数据php如需要40秒,asp不下2 ...
- PHP缓存技术的多种方法小结
这里所说的数据缓存是指数据库查询PHP缓存机制,每次访问页面的时候,都会先检测相应的缓存数据是否存在,如果不存在,就连接数据库,得到数据,并把查询结果序列化后保存到文件中,以后同样的查询结果就直接从缓 ...
- ThinkPHP 缓存技术详解 使用大S方法
如果没有缓存的网站是百万级或者千万级的访问量,会给数据库或者服务器造成很大的压力,通过缓存,大幅减少服务器和数据库的负荷,假如我们把读取数据的过程分为三个层,第一个是访问层,第一个是缓存层,第三个是数 ...
- MySQL缓存参数优化(转)
MySQL 数据库性能优化之缓存参数优化 数据库属于 IO 密集型的应用程序,其主要职责就是数据的管理及存储工作.而我们知道,从内存中读取一个数据库的时间是微秒级别,而从一块普通硬盘上读取一个IO是在 ...
- java缓存技术的介绍
一.什么是缓存1.Cache是高速缓冲存储器 一种特殊的存储器子系统,其中复制了频繁使用的数据以利于快速访问2.凡是位于速度相差较大的两种硬件/软件之间的,用于协调两者数据传输速度差异的结构,均可称之 ...
随机推荐
- Qt消息机制和事件
Qt消息机制和事件 1 事件 事件(event)是由系统或者 Qt 本身在不同的时刻发出的.当用户按下鼠标.敲下键盘,或者是窗口需要重新绘制的时候,都会发出一个相应的事件.一些事件在对用户操作做出响应 ...
- 代码收藏系列--javascript--移动端技巧
JS判断是否是手机端访问: var is_mobi = navigator.userAgent.toLowerCase().match(/(ipod|iphone|android|coolpad|mm ...
- [JOI 2014 Final] IOI 馒头
link 试题分析 我们发现若是要选馒头的话则应该从馒头售价高的先装. 并且若要选择包装盒时应该选择装x个最小的时候.所以只需要贪心$+$背包即可. #include<iostream> ...
- 手脱EZIP v1.0
一.单步 1.载入PEID查壳 EZIP v1.0 2.载入OD,一上来就是一个大跳转,F8单步一直走 0040D0BE > $ /E9 jmp Notepad.004102DC ; //入口点 ...
- Linux常用网络工具:批量主机服务扫描之nmap
Linux下有很多强大网络扫描工具,网络扫描工具可以分为:主机扫描.主机服务扫描.路由扫描等. 之前已经写过常用的主机扫描和路由扫描工具,nmap支持批量主机扫描和主机服务扫描. nmap的安装直接使 ...
- 「Python」35个知识点
No.1 一切皆对象 众所周知,Java中强调“一切皆对象”,但是Python中的面向对象比Java更加彻底,因为Python中的类(class)也是对象,函数(function)也是对象,而且Pyt ...
- Python入门记录
最近看到Python3.7版本已经发布了,安装了Aconda最新的版本.安装完成后测试: 在Python程序里有两种办法查看Python版本信息: import sys # 查看版本 print(sy ...
- Java设计模式の模版方法模式
概述 模板方法模式是类的行为模式.准备一个抽象类,将部分逻辑以具体方法以及具体构造函数的形式实现,然后声明一些抽象方法来迫使子类实现剩余的逻辑.不同的子类可以以不同的方式实现这些抽象方法,从而对剩余的 ...
- IDEA调试服务器上部署的程序
提出问题: 一个程序,部署在自己的电脑上,debug调试,相信大家都会,但是,如果我想debug调试非本地部署的程序怎么办呢.比如测试服务器上部署的程序. 其实这样的需求也是经常有的,比如一个大型的项 ...
- 关于java 获取 html select标签 下拉框 option 文本内容 隐藏域
在HTML中从多选下拉框中提取已选中选项的文本内容到后台,被这个问题难倒了. demo.jsp文件 <select id="selecttype" name"typ ...