ECMall的数据库查询缓存机制

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

view source

print?

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     $sql = "select a.buyer_name, a.add_time, a.status, b.phone_tel, b.phone_mob, c.price, c.quantity
09             from shop_order a, shop_order_extm b, shop_order_goods c
10             where a.order_id = b.order_id and b.order_id = c.order_id
11             and c.goods_id = ‘".$goods_id."‘
12             order by a.add_time desc
13             limit 3 ";
14            
15     $result = $connector -> query($sql);
16    
17     //$r = array();
18     while($myrow = $connector -> fetch_array($result))
19     {
20         $r[] = $myrow;
21     }
22    
23     return $r;
24 }

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

view source

print?

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     $result = $db -> query($sql);
12    
13     $r = array();
14     while($myrow = $db -> fetch_array($result))
15     {
16         $r[] = $myrow;
17     }
18    
19     return $r;
20 }

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

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

view source

print?

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

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

view source

print?

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

来对应一下。

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

view source

print?

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

view source

print?

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

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

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

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

时间: 2024-07-28 14:10:28

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, $usern

MySql存储引擎+表解压缩机制+索引+查询缓存机制+慢查询日志

一.大型网站优化之MySql优化 1.优化和不优化的对比的 在业界当中我们有一个叫大数据(big data)的概念,所谓的大数据指代千万级别以上的数据作为起步的数据.所以我们现在需要对两张都具有50331650条记录的表进行查询对比,其中表名为tbl_no的表是没有做过任何优化手段的表,表名为tbl_yes的表是做过优化手段的表.这个实验的目的是观察具有优化手段和不具有优化手段的查询中速度的差别. 实验条件: 1)两张表的数据记录总数是相同的 2)两张表的数据字段结构也是一样的 3)查询的记录的

CAS 实现单点登录(SSO)数据库查询认证机制-xml方式(三)

继前面介绍过基于CAS实现单点登录(SSO)的实例演示,演示过程中服务端认证机制采用的是默认配置即CAS Servier默认用户名和密码一致即可登录成功,那么本文将侧重于应用方面,真正通过查询用户名密码来进程验证用户是否可以登录. CAS Server添加相关的jar包 需要在web项目的lib下添加两个包:cas-server-support-jdbc-x.x.x.jar和 mysql-connector-java-x.x.x-bin.jar(具体版本号根据情况而定) 修改CAS Server

CAS 实现单点登录(SSO)数据库查询认证机制-自定义编码方式(四)

通过xml配置方式实现数据库查询认证,的确简单但是不够灵活.但是如果登录验证逻辑稍微复杂些,可能通过这种配置方式就不能满足需求了,比如:当用户登录时,需要判断该用户是否绑定了邮箱,如果未绑定,拒绝登录并给出提示信息. 遇到类似的情况,就需要使用自定义登录来完成,并且给出的提示信息也需要是自定义的.  自定义登录验证(默认实现QueryDatabaseAuthenticationHandler) CAS内置了一些AuthenticationHandler实现类,如下图所示,在cas-server-

CI框架学习之六 ( 数据库查询缓存优化 )

CI框架中有个比较好的查询优化,就是数据库缓存优化 1.开启缓存 //在application/config.php中开启 $db['default']['cache_on'] = TRUE; //在application/config.php中开启 $db['default']['cachedir'] = './cache'; //并在对应的目录中加一个可写缓存目录cache 2. 在对应的查询中开启缓存语句 // 打开缓存开关 $this->db->cache_on(); $query =

MySQL数据库的查询缓冲机制

MySQL数据库的查询缓冲机制 2011-08-10 11:07 佚名 火魔网 字号:T | T 使用查询缓冲机制,可以极大地提高MySQL数据库查询的效率,节省查询所用的时间.那么查询缓冲机制是怎样设置的呢?本文我们就来介绍这部分内容,希望能够对您有所帮助. AD: MySQL数据库提供了查询缓冲机制.使用该查询缓冲机 制,MySQL将SELECT语句和查询结果存放在缓冲区中,以后对于同样的SELECT语句(区分大小写),将直接从缓冲区中读取结果.以节省查询时 间,提高了SQL查询的效率.本文

Spring AOP + Redis缓存数据库查询

应用场景 我们希望能够将数据库查询结果缓存到Redis中,这样在第二次做同样的查询时便可以直接从redis取结果,从而减少数据库读写次数. 需要解决的问题 操作缓存的代码写在哪?必须要做到与业务逻辑代码完全分离. 如何避免脏读? 从缓存中读出的数据必须与数据库中的数据一致. 如何为一个数据库查询结果生成一个唯一的标识?即通过该标识(Redis中为Key),能唯一确定一个查询结果,同一个查询结果,一定能映射到同一个key.只有这样才能保证缓存内容的正确性 如何序列化查询结果?查询结果可能是单个实体

12.查询缓存

查询缓存的使用,主要是为了提高查询访问速度.将用户对同一数据的重复查询过程简化, 不再每次均从数据库查询获取结果数据,从而提高访问速度. MyBatis 的查询缓存机制,根据缓存区的作用域(生命周期)可划分为两种:一级查询 缓存与二级查询缓存. 一级查询缓存 MyBatis 一级查询缓存是基于 org.apache.ibatis.cache.impl.PerpetualCache 类的 HashMap 本地缓存,其作用域是 SqlSession. 在同一个 SqlSession 中两次执行相同的

Hibernate缓存机制剖析

Hibernate是基于缓存机制实现的.Hibernate的缓存包括:一级缓存.二级缓存和查询缓存. Hibernate中支持懒加载load,也支持及时加载get.Hibernate采用CGlib的动态代理实现延迟加载.延迟加载采用CGlib的Enhancer类动态生成类. 比较 下面对Hibernate中一级缓存.二级缓存.查询缓存机制做一个横向比较: 相同点: 1.均为缓存,均可在一定的条件下缓存数据: 2.Hibernate的查询实现,是基于缓存机制: 3.三种缓存方式的内部实现方式类似,