[{"data":1,"prerenderedAt":64},["ShallowReactive",2],{"article-90":3},{"code":4,"msg":5,"data":6,"count":14},200,"查询成功",{"id":7,"title":8,"keywords":9,"description":10,"category_id":11,"content":12,"body_html":13,"thumb_up":14,"clicks":15,"sort":14,"remark":16,"status":17,"is_open":17,"is_deleted":14,"is_top":14,"is_recommend":14,"create_time":18,"update_time":19,"image_id":20,"url":13,"member_id":14,"cate_name":21,"prev":22,"next":25,"tags":28,"words":35,"read_time":11,"comments":36,"cover":37,"relevant":38},90,"Redis常见使用场景","数据库,Redis","Redis是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库，并提供多种语言的API。本篇文章，主要介绍利用PHP使用Redis，主要的应用场景。",6,"\nRedis是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库，并提供多种语言的API。本篇文章，主要介绍利用PHP使用Redis，主要的应用场景。 \n\n###### 1、字符串缓存\n\n```php\n$redis->connect('127.0.0.1', 6379);\n$cacheKey  = 'cache1';\n\u002F\u002FSET 应用\n$arrCacheData = ['name'=>'job','sex'=>'男','age'=>'30'];\n$redis->set($cacheKey, json_encode($arrCacheData));\n$redis->expire($cacheKey, 30);  # 设置30秒后过期\n$json_data = $redis->get($cacheKey);\n$data = json_decode($json_data， true);\nprint_r($data['age']); \u002F\u002F输出数据\n\n\u002F\u002FHSET 应用\n$arrWebSite = [\n    'a'=>['aa','1234'],\n    'b'=>['bb','56789'],\n];\n$redis->hSet($cacheKey, 'a', json_encode($arrWebSite['a']));\n$json_data = $redis->hGet($cacheKey, 'a');\n$data = json_decode($json_data);\nprint_r($data); \u002F\u002F输出数据复制代码\n```\n\n###### 2、队列\n\n```php\n$redis->connect('127.0.0.1', 6379);\n$queuekey  = 'queue';\n\u002F\u002F进队列\n$redis->rpush($queuekey, json_encode(['uid' => 1,'name' => 'Job']));\n$redis->rpush($queuekey, json_encode(['uid' => 2,'name' => 'Tom']));\n$redis->rpush($queuekey, json_encode(['uid' => 3,'name' => 'John']));\necho \"---- 进队列成功 ---- \u003Cbr\u002F>\";\n\n\u002F\u002F查看队列\n$strCount = $redis->lrange($queuekey, 0, -1);\necho \"当前队列数据为： \u003Cbr \u002F>\";\nprint_r($strCount);\n\n\u002F\u002F出队列\n$redis->lpop($queuekey);\necho \"\u003Cbr\u002F> ---- 出队列成功 ---- \u003Cbr \u002F>\";\n\n\u002F\u002F查看队列\n$strCount = $redis->lrange($queuekey, 0, -1);\necho \"当前队列数据为： \u003Cbr \u002F>\";\nprint_r($strCount);\n```\n\n###### 3、发布订阅\n\n```php\n\u002F\u002F以下是 pub.php 文件的内容 cli下运行\nini_set('default_socket_timeout', -1);\n$redis->connect('127.0.0.1', 6379);\n$strChannel = 'test_channel';\n\u002F\u002F发布\n$redis->publish($strChannel, \"来自{$strChannel}频道的推送\");\necho \"---- {$strChannel} ---- 频道消息推送成功～ \u003Cbr\u002F>\";\n$redis->close();\n```\n\n```php\n\u002F\u002F以下是 sub.php 文件内容 cli下运行\nini_set('default_socket_timeout', -1);\n$redis->connect('127.0.0.1', 6379);\n$strChannel = 'test_channel';\n\u002F\u002F订阅\necho \"---- 订阅{$strChannel}这个频道，等待消息推送...----  \u003Cbr\u002F>\u003Cbr\u002F>\";\n$redis->subscribe([$strChannel], 'callBackFun');\n\nfunction callBackFun($redis, $channel, $msg){\n    print_r([\n        'redis' => $redis,     \n        'channel' => $channel,       \n        'msg' => $msg\n    ]);\n}\n```\n\n###### 4、计数器\n\n```php\n$redis->connect('127.0.0.1', 6379);\n$strKey = 'test_comments';\n\u002F\u002F设置初始值\n$redis->set($strKey, 0);\n$redis->INCR($strKey);  \u002F\u002F+1\n$redis->INCR($strKey);  \u002F\u002F+1\n$redis->INCR($strKey);  \u002F\u002F+1\n$strNowCount = $redis->get($strKey);\necho \"---- 当前数量为{$strNowCount}。 ---- \";\n```\n\n###### 5、排行榜\n\n```php\n$redis->connect('127.0.0.1', 6379);\n$strKey = 'test_score';\n\u002F\u002F存储数据\n$redis->zadd($strKey, '50', json_encode(['name' => 'Tom']));\n$redis->zadd($strKey, '70', json_encode(['name' => 'John']));\n$redis->zadd($strKey, '90', json_encode(['name' => 'Jerry']));\n$redis->zadd($strKey, '30', json_encode(['name' => 'Job']));\n$redis->zadd($strKey, '100', json_encode(['name' => 'LiMing']));\n$dataOne = $redis->ZREVRANGE($strKey, 0, -1, true);\necho \"---- {$strKey}由大到小的排序 ----\u003Cbr \u002F>\";\n\nprint_r($dataOne);\n$dataTwo = $redis->ZRANGE($strKey, 0, -1, true);\necho \"\u003Cbr \u002F>---- {$strKey}由小到大的排序 ----\u003Cbr \u002F>\";\nprint_r($dataTwo);\n```\n\n###### 6、字符串悲观锁\n\n解释：悲观锁(Pessimistic Lock), 顾名思义，就是很悲观。\n\n每次去拿数据的时候都认为别人会修改，所以每次在拿数据的时候都会上锁。\n\n场景：如果项目中使用了缓存且对缓存设置了超时时间。\n\n当并发量比较大的时候，如果没有锁机制，那么缓存过期的瞬间，\n\n大量并发请求会穿透缓存直接查询数据库，造成雪崩效应。\n\n```php\n\u002F**\n * 获取锁\n * @param  String  $key    锁标识\n * @param  Int     $expire 锁过期时间\n * @return Boolean\n *\u002F\npublic function lock($key = '', $expire = 5) {  \n    $is_lock = $this->_redis->setnx($key, time()+$expire);\n    \u002F\u002F不能获取锁 \n    if(!$is_lock){\n    \t\u002F\u002F判断锁是否过期  \n        $lock_time = $this->_redis->get($key);\n        \u002F\u002F锁已过期，删除锁，重新获取     \n        if (time() > $lock_time) {\n            unlock($key);\n            $is_lock = $this->_redis->setnx($key, time() + $expire);\n        }\n    }   \n    return $is_lock? true : false;\n}\n\n\u002F**\n * 释放锁\n * @param  String  $key 锁标识\n * @return Boolean\n *\u002F\npublic function unlock($key = ''){  \n    return $this->_redis->del($key);\n}\n\n\u002F\u002F 定义锁标识\n$key = 'test_lock';\n\u002F\u002F 获取锁\n$is_lock = lock($key, 10);\nif ($is_lock) { \n    echo 'get lock success\u003Cbr>';  \n    echo 'do sth..\u003Cbr>';\n    sleep(5);   \n    echo 'success\u003Cbr>';\n    unlock($key);\n} else { \n    \u002F\u002F获取锁失败    \n    echo 'request too frequently\u003Cbr>';\n}\n```\n\n###### 7、事务乐观锁\n\n解释：乐观锁(Optimistic Lock), 顾名思义，就是很乐观。\n\n每次去拿数据的时候都认为别人不会修改，所以不会上锁。\n\nwatch命令会监视给定的key，当exec时候如果监视的key从调用watch后发生过变化，则整个事务会失败。\n\n也可以调用watch多次监视多个key。这样就可以对指定的key加乐观锁了。\n\n注意watch的key是对整个连接有效的，事务也一样。\n\n如果连接断开，监视和事务都会被自动清除。\n\n当然了exec，discard，unwatch命令都会清除连接中的所有监视。\n\n```php\n$strKey = 'test_age';\n$redis->set($strKey,10);\n$age = $redis->get($strKey);\necho \"---- Current Age:{$age} ---- \u003Cbr\u002F>\";\n$redis->watch($strKey);\n\u002F\u002F 开启事务\n$redis->multi();\n\u002F\u002F在这个时候新开了一个新会话执行\n$redis->set($strKey,30);  \n\u002F\u002F新会话\necho \"---- Current Age:{$age} ---- \u003Cbr\u002F>\";\n\u002F\u002F30\n$redis->set($strKey,20);\n$redis->exec();\n$age = $redis->get($strKey);\necho \"---- Current Age:{$age} ---- \u003Cbr\u002F>\"; \u002F\u002F30\n\u002F\u002F当exec时候如果监视的key从调用watch后发生过变化，则整个事务会失败复制代码\n```\n\n",null,0,1434,"",1,"2020-06-17 16:09:42","2026-04-19 10:45:50",139,"Mysql",{"id":23,"title":24},89,"获取腾讯“邮我”的链接",{"id":26,"title":27},91,"用Python实现编程语言 20 年的动态排行榜",[29,32],{"id":30,"name":31},28,"数据库",{"id":33,"name":34},76,"Redis",2763,4,"https:\u002F\u002Ftp.myong.top\u002Fstorage\u002Farticle\u002F4d\u002F8611dcff9fff48cf5ed6c42328bb1e.jpg",[39,44,49,54,59],{"id":40,"title":41,"create_time":42,"description":43},94,"客户端连接MySQL8提示 caching-sha2-password 问题","2020-10-19 10:55:26","在安装mysql8的时候如果选择了密码加密，之后用客户端连接比如navicate，会提示客户端连接caching-sha2-password,是由于客户端不支持这种插件，可以通过如下方式进行修改：",{"id":45,"title":46,"create_time":47,"description":48},87,"MySQL中InnoDB和MyISAM区别","2020-06-12 17:11:21","InnoDB具有事务，支持4个事务隔离级别，回滚，崩溃修复能力和多版本并发的事务安全，包括ACID.如果应用中需要执行大量的INSERT或UPDATE操作，则应该使用InnoDB,这样可以提高多用户并发操作的性能。MyISAM管理非事务表，提供高速存储和检索，以及全文搜索能力，如果应用中需要执行大量的SELECT查询，那么MyISAM是更好的选择。",{"id":50,"title":51,"create_time":52,"description":53},88,"MySQL实现循环插入千万级数据","2020-06-12 17:56:22","对于一些数据量较大的系统，数据库面临的问题除了查询效率低下，还有就是数据入库时间长。特别像报表系统，可能每天花费在数据导入上的时间就会长达几个小时之久。因此，优化数据库插入性能是很有意义的。",{"id":55,"title":56,"create_time":57,"description":58},86,"MySQL查询表结构命令","2020-06-09 11:30:00","###### MySQL查询表结构命令\n\n###### 1、查询表结构\n\n主要显示字段类型主键是否允许为空等\n\n```mysql\nDESC 表名;\n```\n\n结果显示\n\n| Field | Type         | Null | Key  | Default | Extra          |\n| :---- | ------------ | ---- | ---- | ------- | -------------- |\n| id    | int(11)      | NO   | P",{"id":60,"title":61,"create_time":62,"description":63},74,"超过经理收入的员工","2020-01-02 16:21:43","###### 题目\n",1783431657367]