Zen cart 系统中提供了对数据库查询结果进行缓存功能。数据库查询结果缓存原理非常简单,对查询的SQL语句取散列值,然后把查询返回的结果关联这个散列值保存起来,当有同样的查询时就从保存的结果中直接返回(前提是没有过期)。
首先看缓存类的框架:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | class cache extends base { //判断缓存是否存在,$zf_cachetime用来指定缓存时间,对应过期的缓存当然不能判断为存在 function sql_cache_exists($zf_query, $zf_cachetime) { global $db; $zp_cache_name = $this->cache_generate_cache_name($zf_query); switch (SQL_CACHE_METHOD) { case 'file': //................ break; case 'database': //................ break; case 'memory': return false; break; case 'none': default: return false; break; } } //判断缓存是否过期 function sql_cache_is_expired($zf_query, $zf_cachetime) { } //马上过期 function sql_cache_expire_now($zf_query) { } //保存缓存 function sql_cache_store($zf_query, $zf_result_array) { } //读取缓存 function sql_cache_read($zf_query) { } //刷新缓存 function sql_cache_flush_cache() { } //生成缓存名 function cache_generate_cache_name($zf_query) { } } |
从以上代码可以看出,ZenCart 系统默认只支持把缓存保存到file和database中,保存到database中是比较少用的,通常在高并发的情况下,更加倾向把结果保存到memory中,不过 Zen-cart 没有提供实现(可做二次开发)。
另外,保存的方式使用常量SQL_CACHE_METHOD指定,这个值需要在配置文件中指定:
1 2 3 | #includes/configure.php define('SQL_CACHE_METHOD', 'file'); define('DIR_FS_SQL_CACHE', '/../public_html/cache'); |
如果SQL_CACHE_METHOD为none,那么根本不会进行缓存。
注:SQL_CACHE_METHOD在安装 Zen-Cart 网站时就会提示把缓存的的方法,是file还是database,默认是none。
缓存对象的生成是在环境初始化时进行的:
1 2 3 | $autoLoadConfig[30][] = array('autoType'=>'classInstantiate', 'className'=>'cache', 'objectName'=>'zc_cache'); |
这个对象的名字叫zc_cache,它是环境初始化中首先构建的对象之一(在它之前是数据库初始化)。
那么这个对象何时会用到?实际上就是在触发SELECT查询时这个对象就会被使用。
1 2 3 4 5 6 7 8 | ##includes/clssses/db/mysql/query_factory.php class queryFactory extends base { function Execute($zf_sql, $zf_limit = false, $zf_cache = false, $zf_cachetime=0) { //.... global $zc_cache; } } |
Execute方法是Zen-cart中对数据库操作封装最核心的方法,zf_sql是要执行的SQL(不仅限于查询),zf_limit限制返回的结果数量,zf_cache表示是否缓存查询结果(只对SELECT查询起作用),zf_cachetime指定缓存时间。
目前 Zen-Cart系统默认代码应用查询缓存的有如下地方:
1 2 3 4 | ##includes/classes/category_tree.php //... $categories = $db->Execute($categories_query, '', true, 150); //... |
另一个地方是读取配置文件:
1 2 3 4 | ##includes/init_includes/init_db_config_read.php $use_cache = (isset($_GET['nocache']) ? false : true ) ; $configuration = $db->Execute('select configuration_key as cfgkey, configuration_value as cfgvalue from ' . TABLE_CONFIGURATION, '', $use_cache, 150); |
这两个地方读取的数据都是经常不改变的,所以缓存起来有必要。特别是配置表,如果每次都查询数据库,并发量一大,就会耗费大量的数据库资源,而这些消耗是完全没有必要的。
另外,虽然 Zen-Cart 系统中的cache类是用来缓存数据库查询结果的,但是并不意味着你只能用它来缓存数据库查询结果,你完成可以把某个变量缓存起来,比如某个变量每次请求时都要重新构建,而已内容都是一样的,这种情况就非常合适缓存,只是你需要使用这个变量之前首先要判断缓存是否存在,这个操作控制起来非常简单。
举例:
1 2 3 4 5 | $cs = $db->Execute("select * from countries"); while(!$cs->EOF){ echo $cs->fields['country_name']."<br />"; $cs->MoveNext(); } |
使用压力测试工具对这对代码进行测试,获取结果。
然后对带数据缓存的版本进行测试:
1 2 3 4 5 | $cs = $db->Execute("select * from countries",0,true,2000); while(!$cs->EOF){ echo $cs->fields['country_name']."<br />"; $cs->MoveNext(); } |
对比结果就能得出结论。
在高并发环境中,对于频繁访问的数据,如果能对数据进行缓存,那么数据库的压力下减是非常明显的。如果并发量很小,几乎感觉不到缓存有什么作用。