<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                # 緩存對象關系映射(Caching in the ORM) # 緩存對象關系映射(Caching in the ORM) 現實中的每個應用都不同,一些應用的模型數據經常改變而另一些模型的數據幾乎不同。訪問數據庫在很多時候對我們應用的來說是個瓶頸。這是由于我們每次訪問應用時都會和數據庫數據通信,和數據庫進行通信的代價是很大的。因此在必要時我們可以通過增加緩存層來獲取更高的性能。本章內容的重點即是探討實施緩存來提高性能的可行性。Phalcon框架給我們提供了靈活的緩存技術來實現我們的應用緩存。 ### 緩存結果集(Caching Resultsets) 一個非常可行的方案是我們可以為那些不經常改變且經常訪問的數據庫數據進行緩存,比如把他們放入內存,這樣可以加快程序的執行速度。 當:doc:Phalcon\\Mvc\\Model <../api/Phalcon\_Mvc\_Model> 需要使用緩存數據的服務時Model可以直接從DI中取得此緩存服務modelsCache(慣例名). Phalcon提供了一個組件(服務)可以用來:doc:\[`](#)緩存 <cache>`任何種類的數據,下面我們會解釋如何在model使用它。第一步我們要在啟動文件注冊這個服務: ``` <pre class="calibre14">``` <?php use Phalcon\Cache\Frontend\Data as FrontendData; use Phalcon\Cache\Backend\Memcache as BackendMemcache; // 設置模型緩存服務 $di->set('modelsCache', function () { // 默認緩存時間為一天 $frontCache = new FrontendData( array( "lifetime" => 86400 ) ); // Memcached連接配置 這里使用的是Memcache適配器 $cache = new BackendMemcache( $frontCache, array( "host" => "localhost", "port" => "11211" ) ); return $cache; }); ``` ``` 在注冊緩存服務時我們可以按照我們的所需進行配置。一旦完成正確的緩存設置之后,我們可以按如下的方式緩存查詢的結果了: ``` <pre class="calibre14">``` <?php // 直接取Products模型里的數據(未緩存) $products = Products::find(); // 緩存查詢結果.緩存時間為默認1天。 $products = Products::find( array( "cache" => array( "key" => "my-cache" ) ) ); // 緩存查詢結果時間為300秒 $products = Products::find( array( "cache" => array( "key" => "my-cache", "lifetime" => 300 ) ) ); // 使用自定義緩存 $products = Products::find( array( "cache" => $myCache ) ); 這里我們也可以緩存關聯表的數據: ``` ``` ``` <pre class="calibre14">``` <?php // Query some post $post = Post::findFirst(); // Get comments related to a post, also cache it $comments = $post->getComments( array( "cache" => array( "key" => "my-key" ) ) ); // Get comments related to a post, setting lifetime $comments = $post->getComments( array( "cache" => array( "key" => "my-key", "lifetime" => 3600 ) ) ); ``` ``` 如果想刪除已經緩存的結果,則只需要使用前面指定的緩存的鍵值進行刪除即可。 注意并不是所有的結果都必須緩存下來。那些經常改變的數據就不應該被緩存,這樣做只會影響應用的性能。另外對于那些特別大的不易變的數據集,開發者應用根據實際情況進行選擇是否進行緩存。 ### 重寫 find 與 findFirst 方法(Overriding find/findFirst) 從上面的我們可以看到這兩個方法是從:doc:Phalcon\\Mvc\\Model繼承而來 <../api/Phalcon\_Mvc\_Model>: ``` <pre class="calibre14">``` <?php use Phalcon\Mvc\Model; class Robots extends Model { public static function find($parameters = null) { return parent::find($parameters); } public static function findFirst($parameters = null) { return parent::findFirst($parameters); } } ``` ``` 這樣做會影響到所有此類的對象對這兩個函數的調用,我們可以在其中添加一個緩存層,如果未有其它緩存的話(比如modelsCache)。例如,一個基本的緩存實現是我們在此類中添加一個靜態的變量以避免在同一請求中多次查詢數據庫: ``` <pre class="calibre14">``` <?php use Phalcon\Mvc\Model; class Robots extends Model { protected static $_cache = array(); /** * Implement a method that returns a string key based * on the query parameters */ protected static function _createKey($parameters) { $uniqueKey = array(); foreach ($parameters as $key => $value) { if (is_scalar($value)) { $uniqueKey[] = $key . ':' . $value; } else { if (is_array($value)) { $uniqueKey[] = $key . ':[' . self::_createKey($value) .']'; } } } return join(',', $uniqueKey); } public static function find($parameters = null) { // Create an unique key based on the parameters $key = self::_createKey($parameters); if (!isset(self::$_cache[$key])) { // Store the result in the memory cache self::$_cache[$key] = parent::find($parameters); } // Return the result in the cache return self::$_cache[$key]; } public static function findFirst($parameters = null) { // ... } } ``` ``` 訪問數據要遠比計算key值慢的多,我們在這里定義自己需要的key生成方式。注意好的鍵可以避免沖突,這樣就可以依據不同的key值取得不同的緩存結果。 上面的例子中我們把緩存放在了內存中,這做為第一級的緩存。當然我們也可以在第一層緩存的基本上實現第二層的緩存比如使用APC/XCache或是使用NoSQL數據庫(如MongoDB等): ``` <pre class="calibre14">``` <?php public static function find($parameters = null) { // Create an unique key based on the parameters $key = self::_createKey($parameters); if (!isset(self::$_cache[$key])) { // We're using APC as second cache if (apc_exists($key)) { $data = apc_fetch($key); // Store the result in the memory cache self::$_cache[$key] = $data; return $data; } // There are no memory or apc cache $data = parent::find($parameters); // Store the result in the memory cache self::$_cache[$key] = $data; // Store the result in APC apc_store($key, $data); return $data; } // Return the result in the cache return self::$_cache[$key]; } ``` ``` 這樣我們可以對可模型的緩存進行完全的控制,如果多個模型需要進行如此緩存可以建立一個基礎類: ``` <pre class="calibre14">``` <?php use Phalcon\Mvc\Model; class CacheableModel extends Model { protected static function _createKey($parameters) { // ... Create a cache key based on the parameters } public static function find($parameters = null) { // ... Custom caching strategy } public static function findFirst($parameters = null) { // ... Custom caching strategy } } ``` ``` 然后把這個類作為其它緩存類的基類: ``` <pre class="calibre14">``` <?php class Robots extends CacheableModel { } ``` ``` ### 強制緩存(Forcing Cache) 前面的例子中我們在Phalcon\\Mvc\\Model中使用框架內建的緩存組件。為實現強制緩存我們傳遞了cache作為參數: ``` <pre class="calibre14">``` <?php // 緩存查詢結果5分鐘 $products = Products::find( array( "cache" => array( "key" => "my-cache", "lifetime" => 300 ) ) ); ``` ``` 為了自由的對特定的查詢結果進行緩存我們,比如我們想對模型中的所有查詢結果進行緩存我們可以重寫find/findFirst方法: ``` <pre class="calibre14">``` <?php use Phalcon\Mvc\Model; class Robots extends Model { protected static function _createKey($parameters) { // ... Create a cache key based on the parameters } public static function find($parameters = null) { // Convert the parameters to an array if (!is_array($parameters)) { $parameters = array($parameters); } // Check if a cache key wasn't passed // and create the cache parameters if (!isset($parameters['cache'])) { $parameters['cache'] = array( "key" => self::_createKey($parameters), "lifetime" => 300 ); } return parent::find($parameters); } public static function findFirst($parameters = null) { // ... } } ``` ``` ### 緩存 PHQL 查詢(Caching PHQL Queries) ORM中的所有查詢,不管多么高級的查詢方法內部使用使用PHQL進行實現的。這個語言可以讓我們非常自由的創建各種查詢,當然這些查詢也可以被緩存: ``` <pre class="calibre14">``` <?php $phql = "SELECT * FROM Cars WHERE name = :name:"; $query = $this->modelsManager->createQuery($phql); $query->cache( array( "key" => "cars-by-name", "lifetime" => 300 ) ); $cars = $query->execute( array( 'name' => 'Audi' ) ); ``` ``` 如果不想使用隱式的緩存盡管使用你想用的緩存方式: ``` <pre class="calibre14">``` <?php $phql = "SELECT * FROM Cars WHERE name = :name:"; $cars = $this->modelsManager->executeQuery( $phql, array( 'name' => 'Audi' ) ); apc_store('my-cars', $cars); ``` ``` ### 可重用的相關記錄(Reusable Related Records) 一些模型有關聯的數據表我們直接使用關聯的數據: ``` <pre class="calibre14">``` <?php // Get some invoice $invoice = Invoices::findFirst(); // Get the customer related to the invoice $customer = $invoice->customer; // Print his/her name echo $customer->name, "\n"; ``` ``` 這個例子非常簡單,依據查詢到的訂單信息取得用戶信息之后再取得用戶名。下面的情景也是如何:我們查詢了一些訂單的信息,然后取得這些訂單相關聯用戶的信息,之后取得用戶名: ``` <pre class="calibre14">``` <?php // Get a set of invoices // SELECT * FROM invoices; foreach (Invoices::find() as $invoice) { // Get the customer related to the invoice // SELECT * FROM customers WHERE id = ?; $customer = $invoice->customer; // Print his/her name echo $customer->name, "\n"; } ``` ``` 每個客戶可能會有一個或多個帳單,這就意味著客戶對象沒必須取多次。為了避免一次次的重復取客戶信息,我們這里設置關系為reusable為true,這樣ORM即知可以重復使用客戶信息: ``` <pre class="calibre14">``` <?php use Phalcon\Mvc\Model; class Invoices extends Model { public function initialize() { $this->belongsTo( "customers_id", "Customer", "id", array( 'reusable' => true ) ); } } ``` ``` 此Cache存在于內存中,這意味著當請示結束時緩存數據即被釋放。我們也可以通過重寫模型管理器的方式實現更加復雜的緩存: ``` <pre class="calibre14">``` <?php use Phalcon\Mvc\Model\Manager as ModelManager; class CustomModelsManager extends ModelManager { /** * Returns a reusable object from the cache * * @param string $modelName * @param string $key * @return object */ public function getReusableRecords($modelName, $key) { // If the model is Products use the APC cache if ($modelName == 'Products') { return apc_fetch($key); } // For the rest, use the memory cache return parent::getReusableRecords($modelName, $key); } /** * Stores a reusable record in the cache * * @param string $modelName * @param string $key * @param mixed $records */ public function setReusableRecords($modelName, $key, $records) { // If the model is Products use the APC cache if ($modelName == 'Products') { apc_store($key, $records); return; } // For the rest, use the memory cache parent::setReusableRecords($modelName, $key, $records); } } ``` ``` 別忘記注冊模型管理器到DI中: ``` <pre class="calibre14">``` <?php $di->setShared('modelsManager', function () { return new CustomModelsManager(); }); ``` ``` ### 緩存相關記錄(Caching Related Records) 當使用find或findFirst查詢關聯數據時,ORM內部會自動的依據以下規則創建查詢條件于: 這意味著當我們取得關聯記錄時,我們需要解析如何如何取得數據的方法: ``` <pre class="calibre14">``` <?php // Get some invoice $invoice = Invoices::findFirst(); // Get the customer related to the invoice $customer = $invoice->customer; // Invoices::findFirst('...'); // Same as above $customer = $invoice->getCustomer(); // Invoices::findFirst('...'); ``` ``` 因此,我們可以替換掉Invoices模型中的findFirst方法然后實現我們使用適合的方法 ``` <pre class="calibre14">``` <?php use Phalcon\Mvc\Model; class Invoices extends Model { public static function findFirst($parameters = null) { // .. custom caching strategy } } ``` ``` ### 遞歸緩存相關記錄(Caching Related Records Recursively) 在這種場景下我們假定我們每次取主記錄時都會取模型的關聯記錄,如果我們此時保存這些記錄可能會為為我們的系統帶來一些性能上的提升: ``` <pre class="calibre14">``` <?php use Phalcon\Mvc\Model; class Invoices extends Model { protected static function _createKey($parameters) { // ... Create a cache key based on the parameters } protected static function _getCache($key) { // Returns data from a cache } protected static function _setCache($key) { // Stores data in the cache } public static function find($parameters = null) { // Create a unique key $key = self::_createKey($parameters); // Check if there are data in the cache $results = self::_getCache($key); // Valid data is an object if (is_object($results)) { return $results; } $results = array(); $invoices = parent::find($parameters); foreach ($invoices as $invoice) { // Query the related customer $customer = $invoice->customer; // Assign it to the record $invoice->customer = $customer; $results[] = $invoice; } // Store the invoices in the cache + their customers self::_setCache($key, $results); return $results; } public function initialize() { // Add relations and initialize other stuff } } ``` ``` 從已經緩存的訂單中取得用戶信息,可以減少系統的負載。注意我們也可以使用PHQL來實現這個,下面使用了PHQL來實現: ``` <pre class="calibre14">``` <?php use Phalcon\Mvc\Model; class Invoices extends Model { public function initialize() { // Add relations and initialize other stuff } protected static function _createKey($conditions, $params) { // ... Create a cache key based on the parameters } public function getInvoicesCustomers($conditions, $params = null) { $phql = "SELECT Invoices.*, Customers.* FROM Invoices JOIN Customers WHERE " . $conditions; $query = $this->getModelsManager()->executeQuery($phql); $query->cache( array( "key" => self::_createKey($conditions, $params), "lifetime" => 300 ) ); return $query->execute($params); } } ``` ``` ### 基于條件的緩存(Caching based on Conditions) 此例中,我依據當的條件實施緩存: 類型緩存1 - 10000mongo110000 - 20000mongo2> 20000mongo3最簡單的方式即是為模型類添加一個靜態的方法,此方法中我們指定要使用的緩存: ``` <pre class="calibre14">``` <?php use Phalcon\Mvc\Model; class Robots extends Model { public static function queryCache($initial, $final) { if ($initial >= 1 && $final < 10000) { return self::find( array( 'id >= ' . $initial . ' AND id <= '.$final, 'cache' => array( 'service' => 'mongo1' ) ) ); } if ($initial >= 10000 && $final <= 20000) { return self::find( array( 'id >= ' . $initial . ' AND id <= '.$final, 'cache' => array( 'service' => 'mongo2' ) ) ); } if ($initial > 20000) { return self::find( array( 'id >= ' . $initial, 'cache' => array( 'service' => 'mongo3' ) ) ); } } } ``` ``` 這個方法是可以解決問題,不過如果我們需要添加其它的參數比如排序或條件等我們還要創建更復雜的方法。另外當我們使用find/findFirst來查詢關聯數據時此方法亦會失效: ``` <pre class="calibre14">``` <?php $robots = Robots::find('id < 1000'); $robots = Robots::find('id > 100 AND type = "A"'); $robots = Robots::find('(id > 100 AND type = "A") AND id < 2000'); $robots = Robots::find( array( '(id > ?0 AND type = "A") AND id < ?1', 'bind' => array(100, 2000), 'order' => 'type' ) ); ``` ``` 為了實現這個我們需要攔截中間語言解析,然后書寫相關的代碼以定制緩存:首先我們需要創建自定義的創建器,然后我們可以使用它來創建守全自己定義的查詢: ``` <pre class="calibre14">``` <?php use Phalcon\Mvc\Model\Query\Builder as QueryBuilder; class CustomQueryBuilder extends QueryBuilder { public function getQuery() { $query = new CustomQuery($this->getPhql()); $query->setDI($this->getDI()); return $query; } } ``` ``` 這里我們返回的是CustomQuery而不是不直接的返回Phalcon\\Mvc\\Model\\Query, 類定義如下所示: ``` <pre class="calibre14">``` <?php use Phalcon\Mvc\Model\Query as ModelQuery; class CustomQuery extends ModelQuery { /** * The execute method is overridden */ public function execute($params = null, $types = null) { // Parse the intermediate representation for the SELECT $ir = $this->parse(); // Check if the query has conditions if (isset($ir['where'])) { // The fields in the conditions can have any order // We need to recursively check the conditions tree // to find the info we're looking for $visitor = new CustomNodeVisitor(); // Recursively visits the nodes $visitor->visit($ir['where']); $initial = $visitor->getInitial(); $final = $visitor->getFinal(); // Select the cache according to the range // ... // Check if the cache has data // ... } // Execute the query $result = $this->_executeSelect($ir, $params, $types); // Cache the result // ... return $result; } } ``` ``` 這里我們實現了一個幫助類用以遞歸的的檢查條件以查詢字段用以識我們知了需要使用緩存的范圍(即檢查條件以確認實施查詢緩存的范圍): ``` <pre class="calibre14">``` <?php class CustomNodeVisitor { protected $_initial = 0; protected $_final = 25000; public function visit($node) { switch ($node['type']) { case 'binary-op': $left = $this->visit($node['left']); $right = $this->visit($node['right']); if (!$left || !$right) { return false; } if ($left=='id') { if ($node['op'] == '>') { $this->_initial = $right; } if ($node['op'] == '=') { $this->_initial = $right; } if ($node['op'] == '>=') { $this->_initial = $right; } if ($node['op'] == '<') { $this->_final = $right; } if ($node['op'] == '<=') { $this->_final = $right; } } break; case 'qualified': if ($node['name'] == 'id') { return 'id'; } break; case 'literal': return $node['value']; default: return false; } } public function getInitial() { return $this->_initial; } public function getFinal() { return $this->_final; } } ``` ``` 最后,我們替換Robots模型中的查詢方法以使用我們創建的自定義類: ``` <pre class="calibre14">``` <?php use Phalcon\Mvc\Model; class Robots extends Model { public static function find($parameters = null) { if (!is_array($parameters)) { $parameters = array($parameters); } $builder = new CustomQueryBuilder($parameters); $builder->from(get_called_class()); if (isset($parameters['bind'])) { return $builder->getQuery()->execute($parameters['bind']); } else { return $builder->getQuery()->execute(); } } } ``` ``` ### 緩存 PHQL 查詢計劃(Caching of PHQL planning) 像大多數現代的操作系統一樣PHQL內部會緩存執行計劃,如果同樣的語句多次執行,PHQL會使用之前生成的查詢計劃以提升系統的性能,對開發者來說只采用綁定參數的形式傳遞參數即可實現: ``` <pre class="calibre14">``` <?php for ($i = 1; $i <= 10; $i++) { $phql = "SELECT * FROM Store\Robots WHERE id = " . $i; $robots = $this->modelsManager->executeQuery($phql); // ... } ``` ``` 上面的例子中,Phalcon產生了10個查詢計劃,這導致了應用的內存使用量增加。重寫以上代碼,我們使用綁定參數的這個優點可以減少系統和數據庫的過多操作: ``` <pre class="calibre14">``` <?php $phql = "SELECT * FROM Store\Robots WHERE id = ?0"; for ($i = 1; $i <= 10; $i++) { $robots = $this->modelsManager->executeQuery($phql, array($i)); // ... } ``` ``` 得用PHQL查詢亦可以提供查詢性能: ``` <pre class="calibre14">``` <?php $phql = "SELECT * FROM Store\Robots WHERE id = ?0"; $query = $this->modelsManager->createQuery($phql); for ($i = 1; $i <= 10; $i++) { $robots = $query->execute($phql, array($i)); // ... } ``` ``` \[`](#)預先準備的查詢語句`\_的查詢計劃亦可以被大多數的數據庫所緩存,這樣可以減少執行的時間,也可以使用我們的系統免受'SQL注入'\_的影響。 | - [索引](# "總目錄") - [下一頁](# "對象文檔映射 ODM (Object-Document Mapper)") | - [上一頁](# "Phalcon 查詢語言(Phalcon Query Language (PHQL))") |
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看