对查询进行缓存
上个月,我们简单地了解了ADOdb中,如何进行SELECT、INSERT和UPDATE的操作。如果你在ADOdb上是个新手,我建议先读一下上个月的那篇文章。 ADOdb 还有很多更高级的特征,这个月,我们就一起来关注其中的部分内容。
数据库时常会成为应用程序效率低下的祸首。尽量减少对数据库的查询,是提高执行效率的方法之一。这,通常可以通过对整页内容进行缓存(有很多种方法来实现。比如,PEAR->Cache),或者,如果你需要做一张动态页面,并且只想让查询指令被缓存,那么,你可以使用ADOdb,简单地将查询指令缓存起来。在你视图通过缓存来提高你的应用程序的糟糕性能之前,我建议你先试图去优化你的查询指令。有时候,一些简单的索引可以改变一切——有太多的所谓的专业的解决方案,都在使用糟糕的索引。在本文中,你能找到很多这样的实例。现在,让我们来看看ADOdb是如何使你能够对数据库的查询结果进行缓存的。在这个实例中,ADOdb把我们的最后的一次查询的结果保存在/var/tmp/adodb_cache这个缓存文件中,并保留10分钟。
include("$adodb_path/db_values.inc.php");
include("$adodb_path/adodb.inc.php");
$db = NewADOConnection('$database_type');
$db->Connect("$host", "$user", "$password", "employees");
$ADODB_CACHE_DIR = "/var/tmp/adodb_cache"; //Directory to store cached files
$sql = "SELECT surname, age FROM employees";
$rs = &$db->CacheExecute(600,$sql); // Executes, and caches the results for 600 seconds
if (!$rs) {
print $db->ErrorMsg(); // Displays the error message if no results could be returned
}
else {
while (!$rs->EOF) {
print $rs->fields[0].' '.$rs->fields[1].'<BR>';
// fields[0] is surname, fields[1] is age
$rs->MoveNext(); // Moves to the next row
} // end while
} // end else
CacheExecute() 函数有两个参数: 第一个参数是缓存文件将被保留的时间,以秒计时;第二个参数是 SQL 声明。 第一个参数是可选择的 (一些开发者或许会认为它应当成为第二个参数) ,如果你没有限定时间,那么,默认值是 3600 秒,也就是1个小时。缓存文件被命名为 adodb_*.cache,你可以在文件系统中安全地将他们删除。你应该定期清楚过期的缓存文件(用UNIX的“crontab万年历”,或者WINDOWS的“计划任务”。译者注:万年历不知有没有译错,我没有UNIX。)。要注意的是,要使用缓存方法,你需要将PHP的参数magic_quotes_runtime设为off(译者注:在php.ini中,将值设为0)。你可以根据需要,在运行时修改它的值:
set_magic_quotes_runtime(0);
只需将上述代码放到你调用数据库的指令之前就可以了。你可以在任何时候,通过调用CacheFlush();来清除缓存。处于对安全的考虑,ADOdb 也建议将PHP的参数register_globals 设为0(在PHP最新版中,这是默认值) 。
更多关于查询结果的信息
开发者通常会对他们的要得到的结果产生一些质疑,最通常的问题是:有多少个记录?ADOdb能够很容易地通过RecordCount()来回答这个问题。 RowCount()是同义函数。
$sql = "SELECT surname, age FROM employees";
$rs = &$db->CacheExecute(600,$sql); // Executes, and caches the results for 600 seconds
print $rs->RecordCount() . " rows returned]"; // Display number of rows returned
或许第二个问题会产生在需量列表上:被返回字段数量是多少?不用担心,ADOdb有FieldCount()。
$sql = "SELECT surname, age FROM employees";
$rs = &$db->CacheExecute(600,$sql); // Executes, and caches the results for 600 seconds
print $rs->FieldCount() . " columns returned]"; // Display number of rows returned
限制结果
上次我们讨论了如何通过使用一个数据库库函数使你的应用程序更简洁,更易于移植。在从MySQL转移到 Informix中 , 我经历了一次痛苦的移植过程。一切都归咎于非ANSII标准的LIMIT子句( 举例来说, 在MySQL中允许下列指令:SELECT name FROM employee LIMIT 15),它是一个非常有用的功能,可在Informix中却不被支持。(在Informix中,相同功能的书写应该是:SELECT FIRST 15 name FROM employee in Informix。)它似乎对你敲响了警钟,要你停止在你的查询中使用非标准SQL的指令,而去认真地学习标准的SQL。幸运的是,ADOdb有一个处理LIMIT的方法:SelectLimit()。
$sql = "SELECT surname, age FROM employees";
$rs = &$db->SelectLimit($sql, 10, 100); // Select 10 rows, starting at row 100
if (!$rs) {
print $db->ErrorMsg(); // Displays the error message if no results could be returned
}
else {
while (!$rs->EOF) {
print $rs->fields[0].' '.$rs->fields[1].'<BR>';
// fields[0] is surname, fields[1] is age
$rs->MoveNext(); // Moves to the next row
} // end while
} // end else
SelectLimit()将SQL声明作为第一参数,第二个是返回的列的数量,最后一个参数是偏移量(返回的第一行)。注意这跟MySQL的指令中LIMIT子句的参数顺序相反。SelectLimit()对于将搜索结果部分地显示在页面上,是十分有用的,通过Previous和Next按钮,可以浏览所有的结果。
不止一次地,我看到的代码将来自数据库的所有查询结果,都用PHP作过滤处理——杀鸡用牛刀! 你完全可以使用 CacheSelectLimit()函数来贮藏这种类型的结果。
处理事务
处理事务是许多应用程序的一个重要的特征。(对于初学者来说,处理事务是你可以提交一打查询操作的过程,而这些查询是都成功了,还是有部分失败了,都需要考虑进去。
经典范例是银行处理。钱从你的帐户转出,然后转入到其他某个人的帐户中。只要其中任意一项失败,那么,这整个过程都必须被认定为失败。不然,钱被划出,而没有进对方的帐户;或者,钱没有划出,对方帐户无端多了一笔小费。)
处理事务可以在代码级上进行机警地管理控制。 常数错误检查被用来判断是否要COMMIT(事务的所有各项都正确,执行正确,结束事务)还是ROLLBACK(事务中有错误,所有改动需要恢复原来状况)。ADOdb 有一些能使处理操作正确进行的有用的函数。下例在某个职员的结余加10,并在另一个上减10,整个过程有两个查询,作为一个完整的事务。
$sql1 = "UPDATE employees SET balance=balance-10 WHERE id=15";
$sql2 = "UPDATE employees SET balance=balance+10 WHERE id=22";
$db->StartTrans();
$db->Execute($sql);
$db->Execute($sql2);
$db->CompleteTrans();
当你浏览老的代码时,可能会看到一个比较老的方法来实现这一切。使用 BeginTrans()、CommitTrans()和RollbackTrans()函数时,需要你自己来处理错误。StartTrans()和 CompleteTrans()将会自动地处理错误,并适当地进行COMMIT或ROLLBACK。当需要的时候,你可以通过FailTrans()来强制执行ROLLBACK。
当然你可能需要知道处理是失败了还是成功了。ADOdb 提供了 HasFailedTrans() 来实现这个功能。 如果出错(或者,你可以将这种情况称作FailTrans()),返回TRUE;如果成功,返回FALSE。
$sql1 = "UPDATE employees SET balance=balance-10 WHERE id=15";
$sql2 = "UPDATE employees SET balance=balance+10 WHERE id=22";
$db->StartTrans();
$db->Execute($sql);
$db->Execute($sql2);
$db->CompleteTrans();
if ($db->HasFailedTrans()) {
// Something went wrong
}
值得注意的是,你的数据库需要支持这些事务函数。 (大多数的数据库是支持的,不过,MySQL InnoDB表支持,可 MySQL MyISAM 表不支持。)
我希望我所做的一切能让你对数据库库函数能有极大的兴趣。还有大量有趣的函数可以用来从数据库表中自动生成HTML,并且同一结果有不同的方法来实现。你可以在此找到完整的手册。
祝你好运!
2003.07.31
原文地址:http://www.databasejournal.com/features/php/article.php/2234861