NoSQL(Redis)
一、了解Redis
1、什么是Redis
- Redis是一个用C语言编写的开源软件
- Redis是基于内存的存储的键值对(Key-Value)数据库(注:默认支持数据持久化)
- Redis支持丰富的数据类型,如: String(字符串)、hash(哈希)list (列表)、
set(集合)、sorted set(有序集合)。
键值对形式存储
js -> {键:值}
数组 -> [键=>指]
数据持久化:数据不会丢失
2、Redis的优势
- 性能极高 – Redis能读的速度是11万次/s,写的速度是8.1万次/s 。
- 支持丰富的数据结构:String(字符串)、hash(哈希)、list (列表)、set(集合)、
sorted set(有序集合)等。
- 支持数据持久化(服务器重启后数据不会丢失,自动从文件中加载到内存中)
Redis与Memcache的区别
都是基于内存存储的
redis支持的数据类型更多、memcache只支持字符串
redis支持数据持久化
二、Redis的安装和部署
步骤一,下载安装包
去官网下(http://redis.io/download)载并上传到服务器
步骤二,编译源程序
- tar -zxvf redis-2.6.14.tar.gz #解压
- cd redis-2.6.14 #进入解压目录
- make #编译(将源代码文件编译成可执行文件)
步骤三,将redis源码目录下的 src目录里的 redis-cli和 redis-server 拷贝到工作目录里.同时将源码根目录下的redis.conf 也拷贝到工作目录里
- mkdir -p /php/server/redis #创建redis文件夹
- \cp -rf /php/tools/redis-2.6.14/src/redis-cli /php/server/redis #拷贝redis客户端文件
- \cp -rf /php/tools/redis-2.6.14/src/redis-server /php/server/redis #拷贝redis服务端文件
- \cp -rf /php/tools/redis-2.6.14/redis.conf /php/server/redis #拷贝redis配置文件
步骤四,启动redis服务器
- 语法:./redis-server ./redis.conf
脚下留心:默认是前台启动,启动后将无法继续执行其他指令
解决:
步骤四,登陆验证
- 语法:./redis-cli
三、操作Redis
- 使用redis客户端redis-cli操作(CRUD)
- 使用PHP程序来操作(CURD)
四、使用redis客户端redis-cli操作(CRUD)
1、连接redis服务通过redis客户端redis-cli
- 语法:./redis 参数
- 参数:
- -h 服务器地址(host)
- -p 端口(6379)
2、Redis操作基础命令
1)添加、修改(CU)
- 语法:set 键 值
- 说明:存在-修改,不存在-则创建
2)获取指定key的值(R)
- 语法:get 键
- 说明:不存在则返回nil(表示无值)
3)删除指定key的值(D)
- 语法: del 键1….键n
- 说明: 返回删除成功的个数(多个之间用空格隔开)
redis常用的数据类型
■ 介绍
http://www.redis.net.cn/tutorial/3502.html
1、字符串(String)类型及操作
1)概念
2)设置N个键(mset)
语法:mset 键1 值1 … 键n 值n
说明:m开头一般代表操作多个键
3)获取N个键(mget)
语法:mget 键1 …. 键n
说明:一次性返回多个值(不存在则返回nil)
4)递增递减(incr和decr)
- 语法:
- incr 键
- decr 键
- 说明:默认增加1(必须是整型)、返回增加后的数字
5)增减指定值(incrby和decrby)
- 语法:
- incrby 键 数字
- decrby 键 数字
- 说明:给键设置指定值
6)拼接-字符串追加(append)
- 语法:append 键 追加的内容
- 说明:返回追加之后的字符长度
7)字符串截取(substr)
- 语法:substr 键 起始位置 结束位置
- 说明:下标从0开始(含前含后)
︴场景案例
网站计数统计
文章详情页统计
http://web.umeng.com/main.php?c=user&a=index
incr 键
2、哈希(Hash)类型
︴思考:为什么学习该类型
用来存储复杂的数据结果,如存储人信息(有姓名、年龄、电话等)存储商品(有价格、颜色等属性)。
1)概念
2)设置/获取hash字段(hset)
语法:hset 键 字段 值
3)键获取一个字段值(hget)
语法:hget 键 字段
4)键添加N个字段(hmset)
语法:hmset 键 字段1 值1 … 字段n 值n
5)键获取N个字段(hmget)
语法:hmget 键 字段1 字段n
6)字段增值(hincrby)
语法:hincrby 键 字段 数字
7)检测键字段(hexists)
语法:hexists 键 字段
说明:1-存在,0-不存在
8)删除键字段(hdel)
语法:hdel 键 字段
9)键个数(hlen)
语法:hlen 键
10)哈希查询(hkeys 和 hvals 和 hgetall)
- 语法:
- 查询所有键 hkeys*
- 查询所有值 hvals
- 查询所有键和值 hgetall
列表(List)类型(注:后期可以当消息队列来使用 ★★★★★)
1)概念
先进后出:lpush lpop
先进先出:lpush rpop
2)左进(lpush)
语法:lpush 键 值
说明:返回数据长度(从左边压入)
3)查询(lrange)
语法:lrange 键 起始位置 结束位置
说明:下标从0开始含前含后(注:-1表示倒数第一个,-2倒数第二个)
4)右进(rpush)
语法:rpush 键 值
说明:返回数据长度(从右边压入)
5)头出(lpop)
语法:lpop 键
说明:从左边弹出,返回弹出的数据
6)尾出(rpop)
语法:rpop 键
说明:从右边弹出,返回弹出的数据
4、集合(Set)类型
︴案例:可能认识好友
用户表
张三 1
李四 2
王五 3
———————-
好友关系表
自增主键 用户ID 粉丝
1 1 2
2 1 3
3 2 1
4 2 3
查出关注张三的用户(张三的粉丝) 2 3
查出关注李四的用户(李四的粉丝) 1 3
通过PHP赛选公共用户
步骤1:查询张三的粉丝
select * from 好友表 where id = 1
步骤2:查询李四的粉丝
select * from 好友表 where id = 2
步骤3:通过php赛选获取公共好友
︴语法图
1)添加(sadd)
语法: sadd 集合名 数据
说明: 给指定集合添加数据
2)查看 (smembers key)
- 语法:smembers key
- 作用:查看指定集合中的数据
3)差集(sdiff)
- 语法:sdiff 集合名1 … 集合名n
- 作用:获取输入第一个集合不属于其他集合的数据
︴案例1
set_1 1 2 3
set_2 2 4 5
指令:sdiff set_1 set_2
答案:1 3
︴案例2
set_1 1 2 3
set_2 1 4 5
set_3 2 6 8
指令:sdiff set_1 set_2 set_3
结果:3
4)并集(sunion)
- 语法:sunion 集合1 … 集合n
- 作用:合并去重
- 案例:
张三:1,2,3
李四:3,4,5
合并:1,2,3,3,4,5
去重:12345
5)交集(sinter)
- 语法:sinter 集合名1 … 集合名n
- 作用:相同数据
应用场景
新浪共同的好友,你可能认识的好友
键(Key)操作
键是否存在(exists)
语法:exists 键名
说明:1-存在,0-不存在
键类型(type)
语法:type 键
键查询 (keys *)
- 语法:keys *
- 说明:
- 查询所有键 keys *
- 查询指定开头键 keys 内容*
- 查询指定结尾键 keys *内容
- 查询包含键 keys *内容*
随机键(randomkey)
语法:randomkey
键更名(rename oldkey newkey)
语法:rename 旧键 新键
键统计(dbsize)
语法:dbsize
键设置过期时间(expire key 秒数 和 ttl key)
语法1:expire 键 秒数
含义1:设置指定键等待多久后过期
语法2:ttl 键
含义2:查看状态(-1 表示过期或者键不存在)
选择数据库(select)
- 语法:select 下标
- 说明:默认16个数据库,下标从0开始也就是最大小标是15
配置文件
键移库(move)
语法:move 旧键 数据库下标
说明:将指定键移动到指定数据库中
键删除-当前库(flushdb)
键删除-全部库(flushall)
总结
【字符串(string)类型】
设置1个键:set 键 值
设置n个键:mset 键1 值1 .. 键n 值n
获取1个键:get 键
获取n个键:mget 键1 .. 键n
递增递减: incr 键 或 decr 键
增加减少: incrby 键 数字 或者 decrby 键 数字
拼接: append 键 内容
截取: substr 键 起始位置 结束位置 (注:含前含后,从0开始下标)
【哈希(hash)类型】
设置1个值:hset 键 字段 值
设置n个值:hmset 键 字段1 值1 …字段n 值n
获取1个值:hget 键 字段
获取n个值:hmget 键 字段1 … 字段n
检测字段: hexists 键 字段
删除字段: hdel 键 字段
字段个数: hlen 键
所有键: hkeys
所有值: hvals
所有键值: hgetall
【列表(list)类型】
左进:lpush 键 值 (返回压入后数据长度)
右进:rpush 键值
左弹:lpop 键 (返回弹出的值)
右弹:rpop 键
查询:lrange 键 起始位置 结束位置(下标从0开始,-1表示倒数第一个 -2 表示第二个)
【集合(set)类型】
添加数据: sadd 集合名 值
查看集合: smembers 集合名
差集: sdiff 集合名1 .. 集合名n (我有你没有)
并集: sunion 集合名1 .. 集合名n (合并去重)
交集: sinter 集合名1 .. 集合名n (共有的)
【键(Key)类型】
键是否存在: exists 键
键类型:type 键
键查询:keys *
键随机:randomkey
键更名:rename 旧键 新键
键统计:dbsize
键设置过期: expire 键 时间/s
查看过期时间:ttl 键 (-1表示不存在或者已经过期)
选择数据库 : select 索引
键移库: move 键 索引
删除当前库:flushdb
删除所有库:flushall
Redis的持久化方式
概念
说明:Redis持久化就是指数据当重启电脑后数据不会丢失
原因:Redis开发者将数据在磁盘文件中保存了一份,当重启电脑时将数据加载到内存中。
Snapshotting快照持久化(默认)
- 快照模式将内存中的数据以快照的方式写入二进制文件中(dump.rbd)
- 通过修改配置文件(redis.conf)可以更改快照备份规则
快照模式相对而言不够安全
3、AOF持久化(Append only file)
1)概念
AOF方式是只保存我们的写、修改、删除动作到文件中(appendonly.aof)当系
统重启的时候会讲该文件中的数据重新加载到内存中。
︴如何开启AOF方式?
- 关闭快照备份
- 开启AOF备份
八、安全性
- 问题:不需要密码就可以登录
- 解决:修改配置设置密码
脚下留心:记得重启服务
- 登录1:./redis-cli -a 密码
- 登录2:登录后,语法: auth 密码
九、主从复制(配置)
1、概念
主从复制:当主服务器有写入/删除/修改数据动作,从服务器会自动同步
读写分离:通过PHP控制器将增/改/删到主服务器,从服务器负责读取数据
2、配置
从服务器端口和主服务器端口不能一直
主服务器必须关闭防火墙
十、PHP与Redis结合
1、安装php的redis扩展
1)安装autoconf-2.62.tar.gz(依赖)
/php/tools/
tar -zxvf autoconf-2.62.tar.gz
cd autoconf-2.62
./configure && make && make install
安装phpredis
#步骤1:安装扩展
/php/tools
tar -zxvf phpredis.tar.gz
cd phpredis
./configure –with-php-config=/php/server/php/bin/php-config #路径不同需要自己修改
make && make install
#步骤2:让PHP加载redis.so扩展
vi /php/server/php/lib/php.ini
#步骤3:最后重启Apache即可
/php/server/apache/bin/apachectl stop
/php/server/apache/bin/apachectl start
#步骤4:同步phpinfo检测是否安装成功
通过php操作redis
phpredis中文手册——《redis中文手册》 php版
http://www.cnblogs.com/ikodota/archive/2012/03/05/php_redis_cn.html
<?php
#phpinfo();
//1.创建redis对象
$redis = new Redis;
//2.连接Reids
$redis->connect(‘127.0.0.1’, 6379);
//3.身份认证
$redis->auth(1234);
//4.添加数据
$redis->set(‘yaoyiyao’, ‘girl’);
//5.获取数据
echo $redis->get(‘yaoyiyao’);
十一、TP中使用Redis
脚下留心:tp只支持简单的设置获取删除
秒杀功能的实现(★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★)
架构示意图
代码
︴MySQL(问题:负库存)
create database shop charset=utf8;
use shop
create table goods (id int primary key auto_increment,num int ) engine=innodb;
insert into goods values (null, 100);
<?php
// 语法:ab -n 1000 -c 100 http://localhost/test/test.php
// 说明:n – 请求总数 , c – 并且
$conn = @mysql_connect(‘192.168.21.134′,’test’,’admin888′);
mysql_query(‘set names utf8’);
mysql_query(‘use shop’);
$sql = “select num from goods where id = 1”;
$res = mysql_query($sql);
$tmp = mysql_fetch_assoc($res);
$num = $tmp[‘num’];
if ($num) {
//减库存
$sql=”update goods set num=num-1 where id = 1″;
mysql_query($sql);
}
echo ‘ok’;
实现步骤1:将商品放到队列中
<?php
//1.创建redis对象
$redis = new Redis();
//2.连接服务器
$redis->connect(‘127.0.0.1’, ‘6379’);
//3.登录(开启密码就写)
$redis->auth(‘1234’);
//4.选择数据库
$redis->select(0);
//将商品ID=1的数据压入到redis队列中
for($i=0; $i<100; $i++){
$redis->lpush(‘goods1’, 1);
}
echo $redis->llen(‘goods1’);
实现步骤3:Redis(队列处理)
<?php
// 语法:ab -n 1000 -c 100 http://localhost/test/test.php
// 说明:n – 请求总数 , c – 并且
$redis=new Redis();
$redis->connect(‘127.0.0.1’,6379);
$redis->auth(‘123456’);
// 从头部弹出商品
$count=$redis->lpop(‘goods1’);
if($count){
//连接数据库
$conn = @mysql_connect(‘127.0.0.1′,’root’,’admin888′);
mysql_query(‘set names utf8’);
mysql_query(‘use shop’);
//减库存
$sql=”update goods set num=num-1 where id = 1″;
$data= mysql_query($sql);
echo ‘ok’;
}else{
echo ‘error’;
}
︴扩展:session入库(redis)
修改配置文件
<?php
ini_set(“session.save_handler”, “redis”);
ini_set(“session.save_path”, “tcp://127.0.0.1:6379?auth=1234”);
session_start();
$_SESSION[‘test_huangyihuang’] = 123;
print_r($_SESSION);
die;
通过设置用户自定义会话存储函数(session_set_save_handler)
语法:session_set_save_handler(开启session机制函数,关闭session机制函数,
读取session数据函数,写入session函数,销毁session函数,后手过期session函数)
自 PHP 5.4 开始,可以使用SessionHandlerInterface接口实现(注:接口里面都是抽象方法)
抽象类:有抽象方法的类就是抽象类
抽象方法:用关键词abstract并且没有函数体的方法
接口:特殊的抽象类(注:因为里面的方法都是抽象方法)
redis.php
<?php
class RedisSessionHandler implements \SessionHandlerInterface
{
private $redis;
public static function start()
{
session_set_save_handler(new self, true);
session_start();
}
public function open($savePath, $sessionName) {
$this->redis = new Redis;
$this->redis->connect(‘127.0.0.1’, 6379);
$this->redis->auth(‘123’);
$this->redis->select(0);
return true;
}
public function close() {
return true;
}
public function read($sessionId) {
return $this->redis->get( $sessionId ) ? : ”;
}
public function write($sessionId, $data) {
return $this->redis->set($sessionId, $data);
}
public function destroy( $sessionId ) {
//$this->memcache->delete($sessionId)
return true;
}
public function gc( $lifetime ) {
return true;
}
}
RedisSessionHandler::start();
$_SESSION[‘aa’] = 123;
$_SESSION[‘bb’] = 456;
echo session_id();
?>
memcache.php
<?php
class MemcacheSessionHandler implements \SessionHandlerInterface
{
private $memcache;
public static function start()
{
session_set_save_handler(new self, true);
session_start();
}
public function open($savePath, $sessionName) {
$this->memcache = new Memcache();
$this->memcache->addServer(‘127.0.0.1’, 11211);
return true;
}
public function close() {
return true;
}
public function read($sessionId) {
return $this->memcache->get( $sessionId ) ? : ”;
}
public function write($sessionId, $data) {
return $this->memcache->set($sessionId, $data, 0, 0);
}
public function destroy( $sessionId ) {
//$this->memcache->delete($sessionId)
return true;
}
public function gc( $lifetime ) {
return true;
}
}
MemcacheSessionHandler::start();
$_SESSION[‘aa’] = 123;
$_SESSION[‘bb’] = 456;
echo session_id();
?>