ECMall的数据库查询缓存机制

对数据库进行一些操作上的缓存影响
服务器君一共花费了166.974 ms进行了4次数据库查询,努力地为您提供了这个页面。
试试阅读模式?希望听取您的建议

刚接触Ecmall的二次开发不久,接到一个任务。很常见的任务,主要是对数据库进行一些操作,其中查询的方法我写成这样:

	function get_order_data($goods_id)
	{
		include_once("gonndb/nmdb.php");
		include_once("gonndb/dbinfo.php");
		
		$connector = new nmdb($host, $username, $password);
		$connector -> select_db($database);
		$sql = "select a.buyer_name, a.add_time, a.status, b.phone_tel, b.phone_mob, c.price, c.quantity
				from shop_order a, shop_order_extm b, shop_order_goods c
				where a.order_id = b.order_id and b.order_id = c.order_id
				and c.goods_id = '".$goods_id."'
				order by a.add_time desc
				limit 3 ";
				
		$result = $connector -> query($sql);
		
		//$r = array();
		while($myrow = $connector -> fetch_array($result))
		{
			$r[] = $myrow;
		}
		
		return $r;
	}

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

	function get_order_data($goods_id)
	{
		$db = &db();
		
		$sql = "select a.buyer_name, a.add_time, a.status, b.phone_tel, b.phone_mob, c.price, c.quantity
				from shop_order a, shop_order_extm b, shop_order_goods c
				where a.order_id = b.order_id and b.order_id = c.order_id
				and c.goods_id = '".$goods_id."'
				order by a.add_time desc
				limit 3 ";
		$result = $db -> query($sql);
		
		$r = array();
		while($myrow = $db -> fetch_array($result))
		{
			$r[] = $myrow;
		}
		
		return $r;
	}

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

下面是一个公告挂件的程序:

<?php
/**
* 公告栏挂件
*
* @param   string  $ad_image_url   广告图片地址
* @param   string  $ad_link_url    广告链接地址
* @return  array
*/
class NotWidget extends BaseWidget
{
    var $_name = 'not';
    var $_ttl  = 86400;
    var $_num  = 3;
    function _get_data()
    {
        // 创建一个缓存对象
		$cache_server =& cache_server();
		// 获取该缓存对象数据的id
        $key = $this->_get_cache_id();
		// 凭证领取对象书记
        $data = $cache_server->get($key);
 		$data1 = $cache_server->get($key);
        if($data === false)
        {
            $acategory_mod =& m('acategory');
            $article_mod =& m('article');
            $data = $article_mod->find(array(
                'conditions'    => 'cate_id=' . $acategory_mod->get_ACC(ACC_NOTICE) . ' AND if_show = 1',
                'order'         => 'sort_order ASC, add_time DESC',
                'fields'        => 'article_id, title, add_time',
                'limit'         => $this->_num,
            ));
            $cache_server->set($key, $data, $this->_ttl);
        }
        if($data1 === false)
        {
            $acategory_mod1 =& m('acategory');
            $article_mod1 =& m('article');
            $data1 = $article_mod1->find(array(
                'conditions'    => 'cate_id=' . $acategory_mod1->get_ACC(ACC_HELP) . ' AND if_show = 1',
                'order'         => 'sort_order ASC, add_time DESC',
                'fields'        => 'article_id, title, add_time',
                'limit'         => $this->_num,
            ));
            $cache_server->set($key, $data1, $this->_ttl);
        }
        return array(
            'notices'       => $data,
            'systems'       => $data1,
        );
    }
}
?>

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

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

来对应一下。

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

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

如果是缓存模板文件的话,那就算不使用内存来缓存从数据库读取的数据也没关系,因为最后会把模板文件连同数据一起缓存进一个文件,那后面读取时就只读取这个文件而不用再去缓存数据库,但与静态化有点不同,这个文件里面还有一点php信息,并不能用来直接输出,模板引擎会在去掉这点php信息后输出。

在使用ecmall2时也觉得有时反应不过来,相比来讲ecshop还快,经过观察,其实ecshop在display时是加了一个id的,就是用来缓存这次输出的。而我们现在要做的就是在ecmall2里面实现缓存模板输出,通俗点讲就是在$this->display()时给一个id这个id要唯一。

其实所有的东西ecmall2已经准备好了,只是不知道为什么没有使用,详细的原理不再介绍修改完后就可以使你的商城在运行方面的速度上一层楼,但是网络方面可不包哦。

我们以商品详细页为例:

  1. 修改app/goods.app.php的index方法的最后一行成这样{$this->display('goods.index.html','goods_detail_'.$id);}(不包括大括号,以下不再提示)。
  2. app/frontend.base.php文件里面的class StorebaseApp extends FrontendApp类的function _config_view()方法里的最后添加如下代码{$this->_view->cache_dir = ROOT_PATH . "/temp/html_cache/store/{$template_name}";}这里设置缓存的目录。
  3. 再找到app/frontend.base.php的class FrontendApp extends ECBaseApp类的function display($tpl)方法的方法名改成这样{function display($tpl,$cache_id="")}接着把方法里面的parent::display($tpl);改成{parent::display($tpl,$cache_id);}。
  4. 找到includes/ecapp.base.php里的function display($f)方法的方法名改成{function display($f,$cache_id="")},以及里面的parent::display($f);改成{parent::display($f,$cache_id);}。
  5. eccore/controller/app.base.php里面的function display($n)方法改成{function display($n,$cache_id='')},以及里面的$this->_view->display($n);改{$this->_view->display($n,$cache_id);}。

再修改eccore/view/template.php的function fetch($filename, $cache_id = '')方法如下。

   function fetch($filename, $cache_id = '')
    {
        if (!$this->_seterror)
        {
            error_reporting(E_ALL ^ E_NOTICE);
        }
        $this->_seterror++;
        if (strncmp($filename,'str:', 4) == 0)
        {
            $out = $this->_eval($this->fetch_str(substr($filename, 4)));
        }
        else
        {
            if ($this->_checkfile)
            {
                if (!is_file($filename))
                {
                    $filename = $this->template_dir . '/' . $filename;
                }
            }
            else
            {
                $filename = $this->template_dir . '/' . $filename;
            }
            if ($this->direct_output)
            {
                $this->_current_file = $filename;
                $out = $this->_eval($this->fetch_str(file_get_contents($filename)));
            }
            else
            {
                if ($this->is_cached($filename,$cache_id)&&$cache_id && $this->caching)
                {
                    $out = $this->template_out;
                }
                else
                {
                    if (!in_array($filename, $this->template))
                    {
                        $this->template[] = $filename;
                    }
                    $out = $this->make_compiled($filename);
                    if ($cache_id)
                    {
                        if ($this->appoint_cache_id)
                        {
                            $cachename = $cache_id;
                        }
                        else
                        {
                            $cachename = basename($filename, strrchr($filename, '.')) . '_' . $cache_id;
                        }
                        $data = serialize(array('template' => $this->template, 'expires' => $this->_nowtime + $this->cache_lifetime, 'maketime' => $this->_nowtime));
                        $out = str_replace("\r", '', $out);
                        while (strpos($out, "\n\n") !== false)
                        {
                            $out = str_replace("\n\n", "\n", $out);
                        }
                            if (!file_exists($this->cache_dir))
                                    {
                                        ecm_mkdir($this->cache_dir);
                                    }
                        if (file_put_contents($this->cache_dir . '/' . $cachename . '.php', '<?php exit;?>' . $data . $out, LOCK_EX) === false)
                        {
                            trigger_error('can\'t write:' . $this->cache_dir . '/' . $cachename . '.php');
                        }
                        $this->template = array();
                    }
                }
            }
        }
        $this->_seterror--;
        if (!$this->_seterror)
        {
            error_reporting($this->_errorlevel);
        }
        return $out; // 返回html数据
    }

怎么样确定成功没有呢?你打开一个商品详细页面,多刷新几次,如果下面的执行时间不变就表示成功。其实用这个方法,你甚至可以给商城的商品分类、店铺的商品分类都缓存起来,条件是你要给$this->display()方法一个能确定唯一的id。

现在的问题:这些修改后好像是不会在固定时间后自动更新的缓存的,你可以去temp/html_cache/下面删除所有的东西,就会重新生成缓存了。

另外,我会继续研究,会有一个比较完善的生成静态的方案,但是应该是收费的(如果有资源的朋友可以过来互换啊,或者能成为核心交流人员的可以免费提供),但基本都是基于这些代码了。

本文地址:http://www.nowamagic.net/librarys/veda/detail/1486,欢迎访问原出处。

不打个分吗?

转载随意,但请带上本文地址:

http://www.nowamagic.net/librarys/veda/detail/1486

如果你认为这篇文章值得更多人阅读,欢迎使用下面的分享功能。
小提示:您可以按快捷键 Ctrl + D,或点此 加入收藏

大家都在看

现代魔法研究协会欢迎你

阅读一百本计算机著作吧,少年

很多人觉得自己技术进步很慢,学习效率低,我觉得一个重要原因是看的书少了。多少是多呢?起码得看3、4、5、6米吧。给个具体的数量,那就100本书吧。很多人知识结构不好而且不系统,因为在特定领域有一个足够量的知识量+足够良好的知识结构,系统化以后就足以应对大量未曾遇到过的问题。

奉劝自学者:构建特定领域的知识结构体系的路径中再也没有比学习该专业的专业课程更好的了。如果我的知识结构体系足以囊括面试官的大部分甚至吞并他的知识结构体系的话,读到他言语中的一个词我们就已经知道他要表达什么,我们可以让他坐“上位”毕竟他是面试官,但是在知识结构体系以及心理上我们就居高临下。

所以,阅读一百本计算机著作吧,少年!

《链接器和加载器》 莱文(John R.Levine) (作者), 李勇 (译者)

《链接器和加载器》讲述构建程序的关键工具——链接器和加载器,内容包括链接和加载、体系结构、目标文件、存储分配、符号管理、库、重定位、加载和覆盖、共享库、动态链接和加载、动态链接的共享库,以及着眼于成熟的现代链接器所做的一些变化;并介绍一个持续的实践项目,即使用Perl语言开发一个可用的小链接器。《链接器和加载器》适合高校计算机相关专业的学生、实习程序员、语言设计者和开发人员阅读参考。

更多计算机宝库...