你现在的位置:首页 > PHP网站建设知识库 > ecmall > 正文

ecmall缓存问题研究

在从事ecmall二次开发过程中,经常会遇到写程序对数据库进行一些操作,这项工作赖以说是最基础的,其中查询的方法写成这样:

01    function get_order_data($goods_id)
02    {
03        include_once("gonndb/nmdb.php");
04        include_once("gonndb/dbinfo.php");
05         
06        $connector = new nmdb($host, $username, $password);
07        $connector -> select_db($database);
08     
09        $sql = "select a.buyer_name, a.add_time, a.status, b.phone_tel, b.phone_mob, c.price, c.quantity
10                from shop_order a, shop_order_extm b, shop_order_goods c
11                where a.order_id = b.order_id and b.order_id = c.order_id
12                and c.goods_id = '".$goods_id."'
13                order by a.add_time desc
14                limit 3 ";
15                 
16        $result = $connector -> query($sql);
17         
18        //$r = array();
19        while($myrow = $connector -> fetch_array($result))
20        {
21            $r[] = $myrow;
22        }
23         
24        return $r;
25    }

发现第一次查询的数据是对的,然后经过模板解析后的数据怎么都不正确。后来发现,Ecmall有这么一个机制。先是经过app进行数据库操作,操作完毕后会在 temp/compileed/ 下留下模板缓存,而且第一次数据库查询后会产生数据库缓存。这压根就说明,二次开发最好还是用Ecmall自带函数的比较好。上面的函数改成了这样:

01    function get_order_data($goods_id)
02    {
03        $db = &db();
04         
05        $sql = "select a.buyer_name, a.add_time, a.status, b.phone_tel, b.phone_mob, c.price, c.quantity
06                from shop_order a, shop_order_extm b, shop_order_goods c
07                where a.order_id = b.order_id and b.order_id = c.order_id
08                and c.goods_id = '".$goods_id."'
09                order by a.add_time desc
10                limit 3 ";
11     
12        $result = $db -> query($sql);
13         
14        $r = array();
15        while($myrow = $db -> fetch_array($result))
16        {
17            $r[] = $myrow;
18        }
19         
20        return $r;
21    }

这个函数只是使用了Ecmall自带的数据库函数,还是没有产生数据库缓存。看一下别人写的,如何才能产生数据库缓存呢?

下面是一个公告挂件的程序,我们来详细分析一下:

01    <?php
02     
03    
10    class NotWidget extends BaseWidget
11    {
12        var $_name = 'not';
13        var $_ttl  = 86400;
14        var $_num  = 3;
15     
16        function _get_data()
17        {
18            // 创建一个缓存对象
19            $cache_server =& cache_server();
20            // 获取该缓存对象数据的id
21            $key = $this->_get_cache_id();
22            // 凭证领取对象书记
23            $data = $cache_server->get($key);
24            $data1 = $cache_server->get($key);
25            if($data === false)
26            {
27                $acategory_mod =& m('acategory');
28                $article_mod =& m('article');
29                $data = $article_mod->find(array(
30                    'conditions'    => 'cate_id=' . $acategory_mod->get_ACC(ACC_NOTICE) . ' AND if_show = 1',
31                    'order'         => 'sort_order ASC, add_time DESC',
32                    'fields'        => 'article_id, title, add_time',
33                    'limit'         => $this->_num,
34                ));
35                $cache_server->set($key, $data, $this->_ttl);
36            }
37            if($data1 === false)
38            {
39                $acategory_mod1 =& m('acategory');
40                $article_mod1 =& m('article');
41                $data1 = $article_mod1->find(array(
42                    'conditions'    => 'cate_id=' . $acategory_mod1->get_ACC(ACC_HELP) . ' AND if_show = 1',
43                    'order'         => 'sort_order ASC, add_time DESC',
44                    'fields'        => 'article_id, title, add_time',
45                    'limit'         => $this->_num,
46                ));
47                $cache_server->set($key, $data1, $this->_ttl);
48            }
49     
50            return array(
51                'notices'       => $data,
52                'systems'       => $data1,
53            );
54        }
55    }
56     
57    ?>

看了程序,我发现ECMALL的文章调用是这样的。定义一个data,一堆调用最后通过 ACC_NOTICE 来确定调用的分类的。最后通过

1    return array(
2        'notices'       => $data,
3    );

来对应一下。

谈谈写入数据查询缓存的步骤:

1    // 1. 创建缓存对象
2    $cache_server =& cache_server();
3    // 2. 获取缓存数据的 id
4    $key = $this->_get_cache_id();
5    // 自定义也可以
6    $key = 'page_of_goods_' . $id;
7    // 将key,数据,缓存时间设置好
8    $cache_server->set($key, $data, 1800);

如果是缓存模板文件的话,那就算不使用内存来缓存从数据库读取的数据也没关系,因为最后会把模板文件连同数据一起缓存进一个文件,那后面读取 时就只读取这个文件而不用再去缓存数据库,但与静态化有点不同,这个文件里面还有一点php信息,并不能用来直接输出,模板引擎会在去掉这点php信息后 输出。
在使用ecmall2时也觉得有时反应不过来,相比来讲ecshop还快,经过观察,其实ecshop在display时是加了一个id 的,就是用来缓存这次输出的。而我们现在要做的就是在ecmall2里面实现缓存模板输出,通俗点讲就是在$this->display()时给一 个id这个id要唯一。
其实所有的东西ecmall2已经准备好了,只是不知道为什么没有使用,详细的原理不再介绍修改完后就可以使你的商城在运行方面的速度上一层楼,但是网络方面可不包哦。
我们以商品详细页为例:
修改app/goods.app.php的index方法的最后一行成这样{$this->display('goods.index.html','goods_detail_'.$id);}(不包括大括号,以下不再提示)。
app/frontend.base.php文件里面的class StorebaseApp extends FrontendApp类的function _config_view()方法里的最后添加如下代码{$this->_view->cache_dir = ROOT_PATH . "/temp/html_cache/store/{$template_name}";}这里设置缓存的目录。
再找到app/frontend.base.php的class FrontendApp extends ECBaseApp类的function display($tpl)方法的方法名改成这样{function display($tpl,$cache_id="")}接着把方法里面的parent::display($tpl);改成 {parent::display($tpl,$cache_id);}。
找到includes/ecapp.base.php里的function display($f)方法的方法名改成{function display($f,$cache_id="")},以及里面的parent::display($f);改成 {parent::display($f,$cache_id);}。
eccore/controller/app.base.php里面的function display($n)方法改成{function display($n,$cache_id='')},以及里面的$this->_view->display($n);改{$this-& gt;_view->display($n,$cache_id);}。
再修改eccore/view/template.php的function fetch($filename, $cache_id = '')方法如下。

01    function fetch($filename, $cache_id = '')
02     {
03         if (!$this->_seterror)
04         {
05             error_reporting(E_ALL ^ E_NOTICE);
06         }
07         $this->_seterror++;
08     
09         if (strncmp($filename,'str:', 4) == 0)
10         {
11             $out = $this->_eval_r($this->fetch_str(substr($filename, 4)));
12         }
13         else
14         {
15             if ($this->_checkfile)
16             {
17                 if (!is_file($filename))
18                 {
19                     $filename = $this->template_dir . '/' . $filename;
20                 }
21             }
22             else
23             {
24                 $filename = $this->template_dir . '/' . $filename;
25             }
26     
27             if ($this->direct_output)
28             {
29                 $this->_current_file = $filename;
30                 $out = $this->_eval_r($this->fetch_str(file_get_contents($filename)));
31             }
32             else
33             {
34     
35                 if ($this->is_cached($filename,$cache_id)&&$cache_id && $this->caching)
36                 {
37                     $out = $this->template_out;
38                 }
39                 else
40                 {
41                     if (!in_array($filename, $this->template))
42                     {
43                         $this->template[] = $filename;
44                     }
45     
46                     $out = $this->make_compiled($filename);
47     
48                     if ($cache_id)
49                     {
50                         if ($this->appoint_cache_id)
51                         {
52                             $cachename = $cache_id;
53                         }
54                         else
55                         {
56                             $cachename = basename($filename, strrchr($filename, '.')) . '_' . $cache_id;
57                         }
58                         $data = serialize(array('template' => $this->template, 'expires' => $this->_nowtime + $this->cache_lifetime, 'maketime' => $this->_nowtime));
59                         $out = str_replace("\r", '', $out);
60     
61                         while (strpos($out, "\n\n") !== false)
62                         {
63                             $out = str_replace("\n\n", "\n", $out);
64                         }
65     
66                             if (!file_exists($this->cache_dir))
67                                     {
68                                         ecm_mkdir($this->cache_dir);
69                                     }
70     
71                         if (file_put_contents($this->cache_dir . '/' . $cachename . '.php', '<?php exit;?>' . $data . $out, LOCK_EX) === false)
72                         {
73                             trigger_error('can\'t write:' . $this->cache_dir . '/' . $cachename . '.php');
74                         }
75                         $this->template = array();
76                     }
77                 }
78             }
79         }
80     
81         $this->_seterror--;
82         if (!$this->_seterror)
83         {
84             error_reporting($this->_errorlevel);
85         }
86     
87         return $out; // 返回html数据
88     }

怎么样确定成功没有呢?你打开一个商品详细页面,多刷新几次,如果下面的执行时间不变就表示成功。其实用这个方法,你甚至可以给商城的商品分类、店铺的商品分类都缓存起来,条件是你要给$this->display()方法一个能确定唯一的id。
现在的问题:这些修改后好像是不会在固定时间后自动更新的缓存的,你可以去temp/html_cache/下面删除所有的东西,就会重新生成缓存了。

最后附上一张比较典型的PHP缓存技术的流程图:

\