刚接触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 /**
04 * 公告栏挂件
05 *
06 * @param   string  $ad_image_url   广告图片地址
07 * @param   string  $ad_link_url    广告链接地址
08 * @return  array
09 */
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已经准备好了,只是不知道为什么没有使用,详细的原理不再介绍修改完后就可以使你的商城在运行方面的速度上一层楼,但是网络方面可不包哦。

我们以商品详细页为例:

  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 = '')方法如下。

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($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($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($filenamestrrchr($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/下面删除所有的东西,就会重新生成缓存了。

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

ECMall关于数据查询缓存的问题的更多相关文章

  1. Hibernate 性能优化之查询缓存

    查询缓存是建立在二级缓存基础之上的,所以与二级缓存特性相似,是共享的,适合修改不是很频繁的数据 查询缓存不是默认开启的,需要设置      1.在cfg文件中配置 <property name= ...

  2. thinkphp的静态缓存,数据缓存,快速缓存,查询缓存

    // 静态缓存 // 'HTML_PATH' 缓存目录,这是个常量不是配置项,在入口文件中定义 // 'HTML_CACHE_ON'     =>    true, // 开启静态缓存 'HTM ...

  3. 解决EFCore缓存机制导致的数据查询错误问题

    如题,在对同一个Context连续进行相同条件的查询时,会触发EFCore的缓存机制,如果这个过程中数据发生了变化,则会出现错误. 例如:有两个Context实例,一个负责查询,一个负责增删改, A_ ...

  4. MVC实用架构设计(三)——EF-Code First(4):数据查询

    前言 首先对大家表示抱歉,这个系列已经将近一个月没有更新了,相信大家等本篇更新都等得快失望了.实在没办法,由于本人水平有限,写篇博客基本上要大半天的时间,最近实在是抽不出这么长段的空闲时间来写.另外也 ...

  5. hibernate笔记--缓存机制之 二级缓存(sessionFactory)和查询缓存

    二级缓存(sessionFactory): Hibernate的二级缓存由SessionFactory对象管理,是应用级别的缓存.它可以缓存整个应用的持久化对象,所以又称为“SessionFactor ...

  6. mybatis入门基础(八)-----查询缓存

    一.什么是查询缓存 mybatis提供查询缓存,用于减轻数据压力,提高数据库性能. mybaits提供一级缓存,和二级缓存. 1.1. 一级缓存是sqlSession级别的缓存.在操作数据库时需要构造 ...

  7. mybatis中的查询缓存

    一: 查询缓存 Mybatis提供查询缓存,用于减轻数据压力,提高数据库压力. Mybatis提供一级缓存和二级缓存. 在操作数据库时需要构造SqlSession对象,在对象中有一个数据结构(Hash ...

  8. 11g新特性-查询缓存(1)

    众所周知,访问内存比访问硬盘快得多,除非硬盘体系发生革命性的改变.可以说缓存在Oracle里面无处不在,结果集缓存(Result Cache)是Oracle Database 11g新引入的功能,引入 ...

  9. 【Mybatis框架】查询缓存(二级缓存)

    继上一篇博客,我们讲述了mybatis的一级缓存,接下来,我们来学习一下mybatis的二级缓存 博客链接地址: http://blog.csdn.NET/liweizhong193516/artic ...

随机推荐

  1. Bootstrap与tab组合,切换菜单实例

    <html><head><meta http-equiv="Content-Type" content="text/html; charse ...

  2. c语言,strchr(),查找字符串中第一次字符出现的位置

    int main(void) { char string[15]; char *ptr, c = 's'; strcpy(string, "This is a string"); ...

  3. Java client 访问 memcached

    在测试项目中引入了memcached作为缓存层,以下是memcached的缓存配置和调用过程. linux下memcached安装过程 直接参考以前的博文linux下安装memcached过程  不再 ...

  4. 关于C语言中运算符优先级的一次错误

    好久没碰编程了,最近有点闲,又拾起来.做了个简单的网络测试程序,测试的时候发现有条语句老是获取不到结果.如下: if(portnumber=atoi(argv[1])>65535) portnu ...

  5. jquery基础-包裹 替换 删除 复制

    <!doctype html><html lang="en"><head>    <meta charset="UTF-8&qu ...

  6. ajax 特殊参数值无法传到后台问题

    用原生的ajax请求后台的登录功能,使用特殊字符作为密码的时候发现无法把参数传到后台;发现前端就报错了.可能是因为特殊符号吧. 用 encodeURIComponent() 这个方法进行编码之后就可以 ...

  7. 20160406javaweb JDBC 实例工具类

    一.建立静态的数据库配置文件: config.properties driver=com.mysql.jdbc.Driver url=jdbc:mysql://localhost:3306/datab ...

  8. 通过修改ajaxFileUpload.js实现多图片动态上传并实现预览

    参考:http://smotive.iteye.com/blog/1903606 大部分我也是根据他的方法修改的,我也要根据name实现动态的多文件上传功能,但是有个问题使我一直无法实现多文件上传. ...

  9. java 简单分页/总结

    模型(实体) dao层 dao的实现daoimpl层 service层 然后是servlet 把service层加载到servlet中就可以传值了,马上就能看见效果了 jsp页面来了 当然不能忘了在L ...

  10. Ext.Net学习笔记12:Ext.Net GridPanel Filter用法

    Ext.Net学习笔记12:Ext.Net GridPanel Filter用法 Ext.Net GridPanel的用法在上一篇中已经介绍过,这篇笔记讲介绍Filter的用法. Filter是用来过 ...