The use of cache, cache use_PHP tutorial

WBOY
Release: 2016-07-13 10:08:33
Original
1072 people have browsed it

Use of cache, use of cache

Caching is a powerful tool to improve access speed. The main ones used in the work are memcache and redis. They are B/S software, similar to Apache installed on the computer during practice. It also listens to the port and can be directly typed on the client (such as operating Memcache through telnet on cmd). Use the corresponding command to access the value. During self-study, you can familiarize yourself with the native command in this way and see the effect. They reside in the memory, write the data into the memory after getting it (it will occupy a memory area after installing the software), set the expiration time of the data, and read it directly from the memory when used. Because it is memory, the access speed is improved by orders of magnitude. . lz Zeng Jin wrote a very simple backend, which does not require caching at all. When I saw the speed, I couldn’t help but roar: How can it be called a web page if it is so slow? ! But I was young and ignorant at that time, and I didn’t know how to use caching. Of course, it’s not much better now. I hope the front-end girl didn’t secretly curse in her heart at that time>3<......

Memcache is relatively simple to use, at least from the command point of view. In memcache, the storage method is key->value, and the key-value corresponding storage method is similar to the element form of a join array. The types that can be stored can be numbers, strings, arrays, objects, etc. In projects, they are generally stored Non-string (numbers can be regarded as numeric strings) types are first json encoded or serialized and then stored in the cache. When taken out, they are decoded or deserialized. Memcache is a PHP class that specializes in handling memcache cache. The main encapsulated methods are get, set, delete, flush, connect, and close, that is, the necessary acquisition, setting, deletion, clearing, connection, and closing of a cache. (Brackets indicate transferable parameters)

add key, var, [flag], [expire] 添加一个键为key、值为var到服务端,可指定过期时间expire,0则永不过期,最长30天
get key, [flag] 从服务端获取某一或某些元素
delete key, [timeout] 在指定timeout时间内删除key对应元素,默认timeout为0立即删除
flush 清空,即删除所有元素
connect host, [port], [timeout] 连接到memcache服务器host主机的port端口,它会在脚本执行完自动关闭,也可主动关闭
close 主动关闭memcache服务端连接,但不会关闭pconnect生成的连接
set key, var, [flag], [expire] 存储键为key、值为var的元素到服务端,key存在则覆盖其值,不存在新add一个
replace key, var, [flag], [expire] 查找键为key的元素,以值var替换,查不到会报错
increment key, [value] 在键为key的元素上增加值value,value默认为1,可能改变原值
decrement key, [value] 在键为key的元素上减少值value,value默认为1,可能改变原值
addServer host, [port], [persistent], [weight], [timeout], ...... 添加一个memcache服务到连接池(保存多个memcache连接的地方)中,即建立一个到host的连接,port为端口
pconnect host, [port], [timeout] 建立到位于host主机的memcache服务器的持久连接,port为端口,脚本执行完或调用close也无法关闭这种连接

There are a few points to note:

1. The difference between the usage of set and replace: set is successful in almost any case, unless there are hard reasons such as connection failure or insufficient memory. Replace only modifies the existing key. If it does not exist, it will fail;

2. The connection established by the connect method will either be disconnected after the script is finished running, or it will be disconnected by calling the close() method;

 3. The number obtained by the increment or decrement method is always greater than or equal to 0. If the value obtained after calculation is indeed less than 0, it will be converted. For example, int type, which occupies 4 bytes in 32 bits, will be returned. The value is (232-1). If it is greater than or equal to 0 after calculation, it will be returned directly. If the type of the element is non-numeric (or numeric string), it will be converted to a number first and then calculated;

 4. When we create a new Memcache object and connect it, there are two ways. One is the connect method: $mem =new Memcache; $mem->connect('127.0.0.1', 11211); or Use the addserver method: $mem->addServer('127.0.0.1', 11211); The latter is established by adding a Memcache server connection to the existing connection pool, with the same effect.

Redis, a powerful caching tool, has been continuously improved thanks to its wide use in domestic portals. It now has a stable version (it looks like the latest 64-bit release 2.8 version on Microsoft github, in my case It can't run on the working machine...), there are many more methods than memcache. As for development, it is mainly used for data access, while other things, communication protocols, and clusters are generally developed in the background, not for speed. Even if you pursue it to the extreme, it is still basically useless. Redis is divided into the following types according to operations:

1. String: It is also a key-value pair. It mainly performs get, set, length, auto-increment and other operations on the element corresponding to its key. Redis will store all added types as strings, even pure numbers;

 

2. Hash: Hash table (hash table) is a dictionary in the data structure, using a specific hash algorithm. For example, there are hundreds of people in the mobile phone address book, and the first letter of the last name is used as the key code to sort. , so that we can quickly find contacts by linking a letter to a name through a specific mapping method. In redis, when creating a hash table, first specify the table name, which table you want to store it in, and then specify a field (field, actually a variable) and its corresponding value. The cmd operation is as follows (in The hash table hash1 stores the value Jack corresponding to a domain username, and redis will automatically establish a mapping from username to Jack). Multiple domains and corresponding variables can be stored in a hash table;

 

3. List: List is similar to a linked list equivalent to a data structure. It can also implement stacks and queues. The previous string (the name is very weird) stores a one-to-one corresponding single key-value pair, and it stores Multiple values ​​(without keys), the point is that as a list structure, it can insert and pop up variable values ​​from the left and right (head and tail), find the length, and a series of operations, which is why it is called a list, below lpush . The rpush command inserts the variables hello and world from the left and right sides of the table;

 

4. Set: Set, as the name suggests, can also store multiple variable values ​​(without keys), but it only conforms to the characteristics of mathematically defined sets. For example, the elements in the set are not repeated, so the key names of each data pair in the set are not Similarly, it can also perform operations such as union, intersection, and difference (the following command adds a value var to the set mySet);

 

5. SortedSet: An ordered set, which can be regarded as a special way of Set. In each SortedSet type set, when adding a value (without a key), a variable value called score must be assigned to them. Ordered, there must be a field to determine whether it is in order or not. This is it. The following command creates an ordered set stset, adds a value google.com, and its score is 10. In fact, you can guess that since it is called an ordered set and since the score is given, it is basically certain that this can be used to perform certain sorting operations, and this is also the case;

 

6. Key: Operate the key alone, of course it also affects the corresponding element value, such as viewing the data type of the element corresponding to the key, the survival time of the element corresponding to the key, resetting the survival time, returning all keys, regular form View related key names, delete keys (elements are also gone), etc. It is not a data type. In fact, Redis refers to Hash table names, List table names, and Set names as keys, and the entire set or table is its value. The following is the type command to see the type of value it stores. It stores a List list.

 

For the above commands, you can find a reference document and go through them, and you will be familiar with them quickly. I will only talk about them in general here. So how is cache usually used in actual projects? Let’s not talk about the big picture, such as Weibo’s cache design. This may involve things at the architectural level. Just say that as a backend with a certain amount of visits, you want to use caching to improve speed.

An important principle (which I encounter many times now) is to use the parameters passed in from to spell the key name , and use this key name to store and retrieve the value . For example, there is a method in the Model class: getUserInfoByUid($params), which passes in an array containing the uid field to query the user's information. Here, cache is used to get the cached data first. If it cannot be retrieved, check the database and then re-add it to the cache. , and finally return the result data, which is also a common process for using cache.

Taking Memcache as an example, first look at the code and define a Cache class:

    <span>/*</span><span>*
     * Memcache缓存类
     </span><span>*/</span>
    <span>define</span>('CACHE_HOST', '127.0.0.1'<span>);
    </span><span>define</span>('CACHE_PORT', 11211<span>);
    
    </span><span>class</span><span> Cache{
        </span><span>private</span> <span>static</span> <span>$instance</span> = <span>null</span><span>;  
        
        </span><span>private</span> <span>$_cache</span> = <span>null</span>;  <span>//</span><span> 缓存操作对象</span>
        
        <span>const</span> prefix = 'APP|';  <span>//</span><span> 缓存键值的前缀,为该项目名称 </span>
        
        <span>private</span> <span>function</span><span> __construct(){
            </span><span>if</span>(<span>$this</span>->_cache === <span>null</span><span>){
                </span><span>try</span><span>{
                    </span><span>$this</span>->_cache = <span>new</span><span> Memcache;
                    </span><span>if</span>(!<span>$this</span>->_cache->connect(CACHE_HOST,<span> CACHE_PORT)){
                        </span><span>exit</span>('connect failed'<span>);
                    }
                    
                }
                </span><span>catch</span>(<span>Exception</span> <span>$e</span><span>){
                    </span><span>echo</span> 'ERROR: '.<span>$e</span>-><span>getMessage();
                }
                
            }
        }
        </span><span>/*</span><span>* 
         * 返回单例
         </span><span>*/</span>
        <span>public</span> <span>static</span> <span>function</span><span> getInstance(){
            </span><span>if</span>(self::<span>$instance</span> === <span>null</span><span>){
                self</span>::<span>$instance</span> = <span>new</span><span> self();
            }
            </span><span>return</span> self::<span>$instance</span><span>;
        }
        </span><span>/*</span><span>*
         * 生成键名
         </span><span>*/</span>
        <span>private</span> <span>function</span> genKey(<span>$key</span><span>){
            </span><span>return</span> Cache::prefix.<span>$key</span><span>;
        }
        
        </span><span>public</span> <span>function</span><span> __destruct(){
            </span><span>if</span>(<span>$this</span>->_cache !== <span>null</span><span>){
                </span><span>return</span> <span>$this</span>->_cache-><span>close();
            }
        }
        </span><span>/*</span><span>*
         * 添加元素,设置过期时间
         </span><span>*/</span>
        <span>public</span> <span>function</span> add(<span>$key</span>, <span>$val</span>, <span>$expire</span> = 3600<span>){
            </span><span>return</span> <span>$this</span>->_cache->add(<span>$this</span>->genKey(<span>$key</span>), <span>$val</span>, 0, <span>$expire</span><span>);
        }
        </span><span>/*</span><span>*
         * 重置元素
         </span><span>*/</span>
        <span>public</span> <span>function</span> set(<span>$key</span>, <span>$val</span>, <span>$expire</span> = 3600<span>){
            </span><span>echo</span> 'cache key: '.<span>$this</span>->genKey(<span>$key</span>).'<br/>';  <span>//</span><span> test</span>
            <span>return</span> <span>$this</span>->_cache->set(<span>$this</span>->genKey(<span>$key</span>), <span>$val</span>, 0, <span>$expire</span><span>);
        }
        </span><span>/*</span><span>*
         * 获取元素
         </span><span>*/</span>
        <span>public</span> <span>function</span> get(<span>$key</span><span>){
            </span><span>return</span> <span>$this</span>->_cache->get(<span>$this</span>->genKey(<span>$key</span><span>));
        }
        </span><span>/*</span><span>*
         * 自增
         </span><span>*/</span>
        <span>public</span> <span>function</span> increment(<span>$key</span>, <span>$val</span> = 1<span>){
            </span><span>return</span> <span>$this</span>->_cache->increment(<span>$this</span>->genKey(<span>$key</span>), <span>$val</span><span>);
        }
        </span><span>/*</span><span>*
         * 自减
         </span><span>*/</span>
        <span>public</span> <span>function</span> decrement(<span>$key</span>, <span>$val</span> = 1<span>){
            </span><span>return</span> <span>$this</span>->_cache->decrement(<span>$this</span>->genKey(<span>$key</span>), <span>$val</span><span>);
        }
        </span><span>/*</span><span>*
         * 删除元素
         </span><span>*/</span>
        <span>public</span> <span>function</span> delete(<span>$key</span>, <span>$timeout</span> = 0<span>){
            </span><span>return</span> <span>$this</span>->_cache->delete(<span>$this</span>->genKey(<span>$key</span>), <span>$timeout</span><span>);
        }
        </span><span>/*</span><span>*
         * 删除所有元素
         </span><span>*/</span>
        <span>public</span> <span>function</span> <span>flush</span><span>(){
            </span><span>return</span> <span>$this</span>->_cache-><span>flush</span><span>();
        }    
    }</span>
Copy after login

Then define an operation database operation class:

    <span>/*</span><span>*
     * 数据库操作
     </span><span>*/</span>
    <span>define</span>('DB_NAME', 'test'<span>);
    </span><span>define</span>('DB_HOST', '127.0.0.1'<span>);
    </span><span>define</span>('DB_PORT', 3306<span>);
    </span><span>define</span>('DB_USER', 'root'<span>);
    </span><span>define</span>('DB_PASS', '1234'<span>);
    
    </span><span>class</span><span> Dal{
        </span><span>private</span> <span>static</span> <span>$instance</span> = <span>null</span><span>;
        
        </span><span>public</span> <span>$pdo</span> = <span>null</span><span>;        
        
        </span><span>private</span> <span>function</span><span> __construct(){
            </span><span>try</span><span>{
                </span><span>$dsn</span> = 'mysql:dbname='.DB_NAME.';host='.DB_HOST.':'.<span>DB_PORT;
                </span><span>$this</span>->pdo = <span>new</span> PDO(<span>$dsn</span>, DB_USER,<span> DB_PASS);
            }
            </span><span>catch</span>(PDOException <span>$e</span><span>){
                </span><span>echo</span> 'Error: '.<span>$e</span>-><span>getMessage();
                </span><span>return</span> <span>false</span><span>;
            }
        }
        </span><span>//</span><span>获取实例</span>
        <span>public</span> <span>static</span> <span>function</span><span> getInstance(){
            </span><span>if</span>(self::<span>$instance</span> === <span>null</span><span>){
                self</span>::<span>$instance</span> = <span>new</span><span> self();
            }
            </span><span>return</span> self::<span>$instance</span><span>;
        }
        </span><span>//</span><span> 获取用户信息</span>
        <span>public</span> <span>function</span> getUserInfoByUid(<span>$uid</span><span>){
            </span><span>$sql</span> = <span>sprintf</span>('select * from tab1 where uid = %s limit 1', <span>$uid</span><span>);
            </span><span>$stmt</span> = <span>$this</span>->pdo->query(<span>$sql</span><span>);
            </span><span>return</span> <span>$stmt</span>->fetch(PDO::<span>FETCH_ASSOC);
        }
    }</span>
Copy after login

Generally speaking, data is usually read and written in the Model model class, so define another UserModel class, try to be as simple as possible, and no longer write possible Model public base classes.

    <span>include</span> 'Dal.php'<span>;
    </span><span>include</span> 'Cache.php'<span>;
    
    </span><span>class</span><span> UserModel{
        </span><span>private</span> <span>static</span> <span>$instance</span> = <span>null</span><span>;
        
        </span><span>public</span> <span>$cache</span> = <span>null</span><span>;
        
        </span><span>public</span> <span>$db</span> = <span>null</span><span>;
        
        </span><span>//</span><span> 缓存键名部分,通过函数名称及参数拼接</span>
        <span>const</span> cache_get_userinfo_uid = 'GET|USER|INFO|BY|UID|%s'<span>;
        
        </span><span>private</span> <span>function</span><span> __construct(){
            </span><span>//</span><span> 获取对应类实例</span>
            <span>$this</span>->cache = Cache::<span>getInstance();
            </span><span>$this</span>->db = Dal::<span>getInstance();
        }
        
        </span><span>public</span> <span>static</span> <span>function</span><span> getInstance(){
            </span><span>if</span>(self::<span>$instance</span> === <span>null</span><span>){
                self</span>::<span>$instance</span> = <span>new</span><span> self();
            }
            </span><span>return</span> self::<span>$instance</span><span>;
        }
        
        </span><span>/*</span><span>*
         根据uid获取用户信息
         </span><span>*/</span>
        <span>public</span> <span>function</span> getUserInfoByUid(<span>$params</span>, <span>$timeout</span> = 3600<span>){
            </span><span>//</span><span> 缺少必要参数uid,返回</span>
            <span>if</span>(<span>empty</span>(<span>$params</span>['uid'<span>])){
                </span><span>return</span> <span>null</span><span>;
            }
    
            </span><span>//</span><span> 拼接缓存键名</span>
            <span>$key</span> = <span>sprintf</span>(self::cache_get_userinfo_uid, <span>$params</span>['uid'<span>]);
                    
            </span><span>//</span><span> 获取缓存数据</span>
            <span>$data</span> = json_decode(<span>$this</span>->cache->get(<span>$key</span>), <span>true</span><span>);
            
            </span><span>echo</span> 'cache=><pre class="brush:php;toolbar:false">'<span>;
            </span><span>var_dump</span>(<span>$data</span><span>);
            
            </span><span>//</span><span> 缓存为空</span>
            <span>if</span>(!<span>$data</span><span>){
                </span><span>$data</span> = <span>$this</span>->db->getUserInfoByUid(<span>$params</span>['uid'<span>]);
                </span><span>if</span>(<span>empty</span>(<span>$data</span><span>)){
                    </span><span>return</span> <span>null</span><span>;
                }
                </span><span>//</span><span> 在数据库中获取到数据后,重新写入缓存</span>
                <span>$this</span>->cache->set(<span>$key</span>, json_encode(<span>$data</span>), <span>$timeout</span><span>);
            }
            </span><span>else</span><span>{
                
            }
            </span><span>return</span> <span>$data</span><span>;
        }
    }
    </span><span>//</span><span> 测试</span>
    <span>$data</span> = UserModel::getInstance()->getUserInfoByUid(<span>array</span>('uid'=>17653), 5<span>);
    </span><span>echo</span> 'UserModel=><pre class="brush:php;toolbar:false">'<span>;
    </span><span>var_dump</span>(<span>$data</span>);
Copy after login

Here, we want to obtain a user's information through the user's uid. The query condition is uid, and the necessary parameter passed is uid. Originally, we want to cache each user's data in order to make repeated queries faster. , so you can consider using uid when defining cache keys. But just using this uid is not enough, because if there are queries based on uid in other tables, there will be duplicate key names, causing data confusion. So we use the getUserInfoByUid method, and you can also spell the method name in, so in In the UserModel class, a constant cache_get_userinfo_uid is defined, and the %s at the end is to splice the parameter uid. However, this may still not work. Now the company has started another project, which also needs to use this table. The method written by someone has exactly the same name as this method. After all, the function name is not patented, and operation and maintenance usually uses the server separately as a function. When using cache, several projects share a server, and it is normal for data to be written in a cache pool. At this time, you can consider adding a prefix---the project name (or project). Therefore, in the Cache class, it is defined A constant prefix is ​​used to call this project APP, which basically guarantees that there will be no conflicts. Of course, if this is a sub-project of a group, and this group has other projects, and the group is called Star, you can add the project group name in front.

Look at the effect. The first time (left) the read cache is empty, but you can see the printed cache key name,

 

The second time (on the right) there is data in the cache, because I put the place where the cache key name is printed in the set method of the Cache class. The second time I read the cache data directly without connecting to the database, so naturally there is no Reset the cache, so the cache key is not printed.

It took me a long time to ensure that the key names do not conflict. It also included how to use cache in a project. There are several methods for reference:

1. The current parameters can be spliced ​​together. Here is only one uid. If there are names, ages, etc., they can be placed at the back. How to find out specifically depends on personal preferences or code specifications;

2. The current method name, as close as possible to the current method name, is spelled in the middle of the cache key;

3. Use the current project name as a prefix (optional), which is safer;

4. The name of the project group is spelled in as a prefix again (generally not used).

Then, in the Model class, get the cache first, and if it cannot be retrieved, read the database. After reading, don’t forget to write to the cache, and set the expiration time and other details. It’s just such a process.

Of course, you can do it more carefully. For example, after reading the cached data, check its expiration time and find that it will expire in 5 seconds, so we reset it to 3000 seconds, like this It can be obtained during the first access, so that the database will not be read again next time. Frequently connecting to the database is very time-consuming.

However, I still think Redis is easy to use. The Hash table in Redis is the best>-_-<, but it happens to be not available on the machine.

Hmm...it's late, go to bed~=_=

www.bkjia.comtruehttp: //www.bkjia.com/PHPjc/950709.htmlTechArticleCache use, cache use cache, a powerful tool to improve access speed. The main ones used in work are memcache and redis. They are B/S software, similar to Apache installed on the machine during practice. It...
source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
About us Disclaimer Sitemap
php.cn:Public welfare online PHP training,Help PHP learners grow quickly!