目录
echo、print、print_r、var_dump的区别
echo、print、print_r、var_dump的区别
print、echo:是语言结构,只能输出简单类型的值(int,string),它们在输出数组时提示Notice错误,输出对象时提示Catchable fatal error。而这二者的区别是echo可以可多参,print只单参
print_r、var_dump:是函数,可用于打印数组和对象,就像echo和print_r的升级版,而其二者的区别,print_r只单参,简单打印,var_dump可多参,连数据类型也打印
strlen和mb_strlen的区别
echo mb_strlen('W.X 你好啊'); // 7 = 4 + 1*3
echo mb_strlen('W.X 你好啊', 'gbk'); // 9 约等于 4 + 1.5*3
echo strlen('W.X 你好啊'); // 13 = 4 + 3*3
/**
* 可以看出:
* mb_strlen默认utf-8计算,中文字符=1字节,若为gbk计算,中文字符=1.5字节
* strlen 把中文字符当作3字节
* mb_strlen是属于MBString扩展的一个函数,而strlen是php核心函数
*/
PHP单引号和双引号的区别
$one = 1;
$two = 2;
class A{
protected $name;
public function __construct()
{
$this->name = 'X.W.X';
}
public function __toString()// 不使用这魔术方法时,print_r会报错
{
return strval($this->name);
}
}
$a = new A();
print_r('$one"$two"'.PHP_EOL); // 单引号不会把$one和$two解析成变量,注意:为啥单引号中的双引号不解析
print_r("自动解析'$one''{$two}'{$two }{ $two}{ $two }{$a}"); // 双引号自动解析变量$one和$two
/* result:
$one"$two"
自动解析'1''2'2{ 2}{ 2 }X.W.X
*/
/* 可以推出:
1.双引号解释变量,单引号不解释变量
2.单引号比双引号效率高,所以尽量使用单引号
3.双引号可放单引号,单引号也可放双引号,但嵌套之后的引号不再具备之前的功能
*/
GET和POST提交方式的区别
- GET请求会被浏览器主动cache,所以可回退;而POST不会,除非手动设置,所以回退时POST会再次提交请求
- GET请求只能进行url编码,而POST支持多种编码方式
- GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息
include和require的区别
都是导入文件,都有返回值。
有无_once的区别?
- 当重复执行require_once一个文件时,但需要注意的是返回值再第一次require_once之后,都为true,require的返回值会是相同的。所以require执行一次
- require比require_once效率高,因此开发之初,尽量不要使用_once的情况
<>php
class Test1
{
public function __construct()
{
echo __CLASS__.PHP_EOL;
}
}
return [1,2,3];
<?php
$a = include_once './test1/Test1.php';
$b = include_once './test1/Test1.php';
var_dump($a);
var_dump($b);
/*
array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
}
bool(true)
*/
但require(需要)当文件不存在或者无法打开的时候,会报E_ERROR,停止脚本
include(包含)当文件不存在或者无法打开的时候,也会E_WARNING,但不会停止脚本
AJAX的优势是什么?
页面局部刷新,减轻服务器压力
SESSION与COOKIE的区别?
- 存储位置:session存储在服务器,cookie存储在浏览器
- 安全性:session比cooike安全
PHP错误和异常的区别?
其它语言一般只剩下异常,无错误和异常之分,php有错误和异常之分
错误:不会被catch捕捉到,不过php提供产生错误之后的钩子:set_error_handler($err_type),需要注意的是这个函数还是捕捉不到 E_ERROR
、 E_PARSE
、 E_CORE_ERROR
、 E_CORE_WARNING
、 E_COMPILE_ERROR
、 E_COMPILE_WARNING
等级别的
错误,但可使用三种方法
方法一:@mysql_connect(...) or die("Database Connect Error")。
方法二:编辑php.ini ,查找"display_errors =" ,将“=”后面的值改为"off。
方法三:在php脚本前加error_reporting(0),屏蔽所有错误提示。
去屏蔽E_ERROR等级别的错误,但需要注意的是若使用了set_error_handler函数代理错误会使@魔法糖失效
异常:可手动抛出异常,若抛出不主动catch,则会fatal错误,停止脚本,若抛出主动catch,则是异常,可通过set_exception_handler代理所有异常
二者语法:
mixed set_error_handler ( callable $error_handler
[, int $error_types
= E_ALL | E_STRICT ] )
bool error_handler ( int $errno , string $errstr [, string $errfile [, int $errline ]] )
第一个参数 errno,包含了错误的级别,是一个 integer。
第二个参数 errstr,包含了错误的信息,是一个 string。
第三个参数是可选的,errfile, 包含了发生错误的文件名,是一个 string。
第四个参数是一个可选项, errline, 包含了错误发生的行号,是一个 integer。
callable set_exception_handler (callable $exception_handler
)
<?php
//自定义IO异常
class IoException extends Exception {
public function __construct($message, $code=0, Exception $previous=null)
{
parent::__construct($message, $code, $previous);
}
}
function exception_handler($e){
echo "异常信息如下<br/>";
echo $e->getMessage();
}
set_exception_handler("exception_handler");
if(!function_exists("write")){
//抛出自定义IO异常 若无exception_handler代理异常,会报fatal错,停止脚本
throw new IoException("方法write()不存在");
}
PHP中的魔术常量、预定义常量和预定义变量
一、魔术常量
特点:它们的值会随着它们在代码中的位置的改变而改变。这些特殊的常量不区分大小写
__LINE__ :返回文件中的当前行号。也可写成__line__。
__FILE__:返回当前文件的绝对路径(包含文件名)。
__DIR__:返回当前文件的绝对路径(不包含文件名),等价于 dirname(__FILE__)。
__FUNCTION__:返回当前函数(或方法)的名称。
__CLASS__:返回当前的类名(包括该类的作用区域或命名空间)。
__TRAIT__:返回当前的trait名称(包括该trait的作用区域或命名空间)。
__METHOD__:返回当前的方法名(包括类名)。
__NAMESPACE__:返回当前文件的命名空间的名称。
二、魔术方法
点击此链接:魔术方法
三、预定义常量
特点:已经在PHP的内核中就定义好了的常量。区分大小写。
PHP_VERSION:返回PHP的版本。
PHP_OS:返回执行PHP解释器的操作系统名称。
PHP_EOL:系统换行符,Windows是(\r\n),Linux是(\n),MAC是(\r)
四、预定义变量
特点:都是数组类型,是对于全部脚本而言的(全部脚本都能使用的环境变量)
$GLOBALS:global全局变量,是一个包含了所有全局变量的组合数组,全局变量的名称就是该组合数组的键。
$_GET:HTTP GET 变量,通过 URL 参数传递给当前脚本的变量的数组。
$_POST:HTTP POST 变量,通过 HTTP POST 方式传递给当前脚本的变量的数组。
$_COOKIE:HTTP Cookies 变量,通过 HTTP Cookies 方式传递给当前脚本的变量的数组。
$_SESSION:session 变量,当前脚本可用的 SESSION 变量的数组。
$_REQUEST:HTTP Request 变量,默认情况下包含了 $_GET,$_POST 和 $_COOKIE 的数组。
$_FILES:HTTP 文件上传变量,通过 HTTP POST 方式上传到当前脚本的项目的数组。
$_SERVER:服务器信息变量,包含了诸如头信息(header)、路径(path)、以及脚本位置(script locations)等信息的数组。这个数组中的项目由 Web 服务器创建。
$_ENV:环境变量,通过环境方式传递给当前脚本的变量的数组。
$php_errormsg:前一个错误信息,$php_errormsg 变量包含由 PHP 生成的最新错误信息。这个变量只在错误发生的作用域内可用,并且要求 track_errors 配置项是开启的(默认是关闭的)。
$HTTP_RAW_POST_DATA:包含 POST 提交的原始数据。
$http_response_header:HTTP 响应头,$http_response_header 数组与 get_headers() 函数类似。当使用HTTP包装器时,$http_response_header 将会被 HTTP 响应头信息填充。
$argc:传递给脚本的参数数目,包含当运行于命令行下时传递给当前脚本的参数的数目。脚本的文件名总是作为参数传递给当前脚本,因此 $argc 的最小值为 1,这个变量仅在 register_argc_argv 打开时可用。
$argv:传递给脚本的参数数组,包含当运行于命令行下时传递给当前脚本的参数的数组。第一个参数总是当前脚本的文件名,因此 $argv[0] 就是脚本文件名,这个变量仅在 register_argc_argv 打开时可用。
特别注意:
php 4.2.0 以及后续版本中,php 指令 register_globals 的默认值为 off。这是 php 的一个主要变化。
让 register_globals 的值为 off 将影响到预定义变量集在全局范围内的有效性。例如,为了得到 DOCUMENT_ROOT 的值,
将必须使用 $_SERVER['DOCUMENT_ROOT'] 代替 $DOCUMENT_ROOT,又如,
使用 $_GET['id'] 来代替 $id 从中获取 id 值,亦或使用 $_ENV['HOME'] 来代替 $HOME 获取环境变量 HOME 的值。
1,1,2,3,5,8,13,21...,求出第n个数
// 1,1,2,3,5,8,13,21...,求出第n个数
// 采用 for控制循环
/**
* @param int $n 输入循环次数
*
* @return int 返回值
*
*/
function _add($n){
$pre = 0;
$next = 1;
$tmp = null;
for($i=0; $i<$n; $i++){
$tmp = $pre + $next;
$pre = $next;
$next = $tmp;
}
return $pre;
}
// 采用 递归控制循环
/**
* @param int $pre 输入前一个数
* @param int $next 输入后一个数
* @param int $n 输入循环次数
*
* @return int 返回值
*
*/
function rec($pre, $next, $n){
// 使用递归,必须有退出条件,不然就死循环
if($n<=0){
return $pre;
}
$n--;
return rec($next, $pre+$next, $n);
}
echo _add(7); // 13
echo rec(0,1,7); // 13
// 可以看出
// for循环和递归循环的区别
// for循环: 使用临时值$tmp,来记录每一次和的值
// 递归循环: 使用两个输入参数,来记录每一次和的值
接口类和抽象类的区别
二者差异:
// 接口类使用interface class_name定义,而抽象类使用abstract class class_name定义
// 接口类使用implements继承,可以多继承interface类,而抽象类是使用extends继承,只能单继承抽象类
// 接口类默认都是abstract,纯粹是接口,且不能自己实现方法,而抽象类都不一定
遍历出某文件夹下的文件夹和文件
// 使用了四个函数
bool is_dir(string $dir_name)
resource||false opendir(string $dirname) // resource代表文件句柄
string||false readdir(resource $dir_handler)
bool is_file(string $file_name)
// 实现方法
$dir = 'D:\Temp';
function getAll($dir){
$allFile = [];
if (is_dir($dir)) {
$dir_h = opendir($dir);
if ($dir_h) {
// 万一返回 目录名为 '0',所以采用 !==
while (false !== ($row = readdir($dir_h))){
if ($row == '.' || $row == '..'){
continue;
}
if (is_file($dir . '/' . $row)){
$allFile[] = $row;
}
elseif (is_dir($dir . '/' . $row)){
$allFile[$row] = getAll($dir . '/' . $row);
}
}
closedir($dir_h);
}
}
return $allFile;
}
var_dump(getAll($dir));
防止SQL注入的函数
// 注意:本扩展自 PHP 5.5.0 起已废弃,并在自 PHP 7.0.0 开始被移除。应使用 MySQLi 或 PDO_MySQL 扩展来替换之
string mysql_real_escape_string ( string $unescaped_string [, resource $link_identifier = NULL ] )
// mysqli扩展的函数
string mysqli_real_escape_string ( string $unescaped_string [, resource $link_identifier = NULL ] )
解决多进程读写一个文件的方法
// 使用了fopen、flock、fwrite、fclose四个函数
function putFile($file,$mode="w"){
$file = fopen($file,$mode);
if(flock($file,LOCK_EX)){
fwrite($file,'write a word');
flock($file,LOCK_UN);
}else{
echo "无法访问";
}
fclose($file);
}
while,外循环是释放不了内循环
$s_ = 0;
$e_ = 2;
while ($s_ < $e_){
while (true){
$s_++;
echo '死循环';
}
}
测试代码块执行时间
string|float microtime ([ bool $get_as_float ] ); //返回当前 Unix 时间戳的微秒数
string number_format ( float $number , int $decimals = 0 , string $dec_point = "." , string $thousands_sep = "," ); //通过千位分组来格式化数字
mixed call_user_func_array ( callback $funcname , array $param_arr ); //动态调用函数
Class Debug
{
// 记录时间点
protected static $info;
/**
* @param string $name 标记时间名
* @param int $overide 是否重写标记时间名
*/
public static function remark($name='start', $overide=0){
if ($overide){
static::$info[$name] = microtime(true);
}
else{
if (!isset(static::$info[$name])){
static::$info[$name] = microtime(true);
}
else {
echo '您输入的标记时间名已经存在';
}
}
}
/**
* @param string $start_name 起始标记时间名
* @param string $end_name 结束标记时间名
* @param int $dec 数字格式化,保留两个小数点
*
* @return int|string 返回时间差
*/
public static function getRangeTime($start_name, $end_name, $dec = 2){
if (!isset(static::$info[$start_name])){
echo '输入的起始时间名不存在';
return -1;
}
elseif (!isset(static::$info[$end_name]))
{
echo '自动帮您以当前时间戳作为您的结束时间名';
static::$info[$end_name]=microtime(true);
}
return number_format(static::$info[$end_name]-static::$info[$start_name], $dec);
}
/**
* 计算某函数使用时间
* @param callback(string|array) $function [空间名+类名+]函数名
* @param array $arr 传参数组
*/
public static function countClassTime($function, $arr){
Debug::remark('start',1);
call_user_func_array($function, $arr);
Debug::remark('end',1);
echo Debug::getRangeTime('start', 'end').PHP_EOL;
}
}
PHP获取真实IP
/**
* 获取客户端IP地址
* @param integer $type 返回类型 0 返回IP地址 1 返回IPV4地址数字
* @param boolean $adv 是否进行高级模式获取(有可能被伪装)
* @return mixed
*/
public function ip($type = 0, $adv = true)
{
$type = $type ? 1 : 0;
static $ip = null; // 为什么ip变量要使用static?防止一个请求多次执行$httpAgentIp以下代码
if (null !== $ip) {
return $ip[$type];
}
// 是否使用自己配置的代理ip
$httpAgentIp = Config::get('http_agent_ip');
if ($httpAgentIp && isset($_SERVER[$httpAgentIp])) {
$ip = $_SERVER[$httpAgentIp];
} elseif ($adv) {
if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$arr = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
$pos = array_search('unknown', $arr);
if (false !== $pos) {
unset($arr[$pos]);
}
$ip = trim(current($arr));
} elseif (isset($_SERVER['HTTP_CLIENT_IP'])) {
$ip = $_SERVER['HTTP_CLIENT_IP'];
} elseif (isset($_SERVER['REMOTE_ADDR'])) {
// 为什么使用$_SERVER['REMOTE_ADDR'],而不使用getenv('REMOTE_ADDR')
// getenv在一些web服务器下是不支持,例如iis服务器
$ip = $_SERVER['REMOTE_ADDR'];
}
} elseif (isset($_SERVER['REMOTE_ADDR'])) {
$ip = $_SERVER['REMOTE_ADDR'];
}
// IP地址合法验证
$long = sprintf("%u", ip2long($ip));
$ip = $long ? [$ip, $long] : ['0.0.0.0', 0];
return $ip[$type];
}
谈谈数据库的事务?
事务,为了高并发导致数据不一致而生,
SELECT @@TRANSACTION_ISOLATION; // 查看事务隔离级别
SELECT @@AUTOCOMMIT; // 查看语句是否被自动提交
1、事务四大特性:ACID
原子性(Atomicity,或称不可分割性)、一致性(Consistency)、隔离性(Isolation,又称独立性)、持久性(Durability)
2、隔离性的四个等级(重点)
高并发的情况下会主要产生以下情况:
①、脏读(未提交读):又称无效数据的读出,一个事务读取到了另一个事务未提交的数据操作结果。若依据脏数据update、insert、delete,这是相当危险的,因为很可能所有的操作都被回滚。
假设在秒杀活动中,某一商品的库存数量剩100?
事务A 事务B
select查询 库存=100
update更新 库存=99
select查询 库存=100
事务回滚库存=100
事务结束库存=100
②、更新丢失:两个事务都同时更新一行数据,一个事务对数据的更新把另一个事务对数据的更新覆盖了。
第一类丢失更新 (通过设置事务隔离级别为 Repeatable Read可以防止)
时间 | 取款事务A | 转账事务B |
T1 | 开始事务 |
|
T2 |
| 开始事务 |
T3 | 查询账户余额为1000元 |
|
T4 |
| 查询账户余额为1000元 |
T5 |
| 汇入100元把余额改为1100元 |
T6 |
| 提交事务 |
T7 | 取出100元把余额改为900元 |
|
T8 | 撤销事务 |
|
T9 | 余额恢复为1000 元(丢失更新) |
|
A事务在撤销时,把1100的数据替换成1000,导致银行把汇入的100抹去,进而导致用户亏了100
第二类丢失更新 (需要应用程序控制,乐观锁)
时间 | 转账事务A | 取款事务B |
T1 |
| 开始事务 |
T2 | 开始事务 |
|
T3 |
| 查询账户余额为1000元 |
T4 | 查询账户余额为1000元 |
|
T5 |
| 取出100元把余额改为900元 |
T6 |
| 提交事务 |
T7 | 汇入100元 |
|
T8 | 提交事务 |
|
T9 | 把余额改为1100 元(丢失更新) |
|
A事务提交在提交时,把900替换成1100,导致银行把取出的100抹去,进而导致银行亏了100
二者的区别:第一类丢失更新是回滚覆盖丢失,第二类丢失更新是提交覆盖丢失
③、不可重复读:一个事务对同一行数据重复读取两次,但是却得到了不同的结果。包括以下情况:
- 虚读:事务T1读取某一数据后,事务T2对其做了修改,当事务T1再次读该数据时得到与前一次不同的值。
- 幻读(Phantom Reads):事务在操作过程中进行两次查询,第二次查询的结果包含了第一次查询中未出现的数据或者缺少了第一次查询中出现的数据(这里并不要求两次查询的sql语句相同)。这是因为在两次查询过程中有另外一个事务插入数据造成的。
- 虚读和幻读的差异:一个update、一个insert、delete
为了避免上面出现的几种情况,在标准SQL规范中,定义了4个事务隔离级别,不同的隔离级别对事务的处理不同。
未授权读取
也称为读未提交(Read Uncommitted):允许脏读取,但不允许更新丢失。如果一个事务已经开始写数据,则另外一个事务则不允许同时进行写操作,但允许其他事务读此行数据。该隔离级别可以通过“排他写锁”实现。
授权读取
也称为读提交(Read Committed):允许不可重复读取,但不允许脏读取。这可以通过“瞬间共享读锁”和“排他写锁”实现。读取数据的事务允许其他事务继续访问该行数据,但是未提交的写事务将会禁止其他事务访问该行。
可重复读取(Repeatable Read)<==>mysql的默认隔离级别
禁止不可重复读和脏读取,但是有时可能出现幻读数据。这可以通过“共享读锁”和“排他写锁”实现。读取数据的事务将会禁止写事务(但允许读事务),写事务则禁止任何其他事务。
序列化(Serializable)
提供严格的事务隔离。它要求事务序列化执行,事务只能一个接着一个地执行,不能并发执行。仅仅通过“行级锁”是无法实现事务序列化的,必须通过其他机制保证新插入的数据不会被刚执行查询操作的事务访问到。
隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大。对于多数应用程序,可以优先考虑把数据库系统的隔离级别设为Read Committed。它能够避免脏读取,而且具有较好的并发性能。尽管它会导致不可重复读、幻读和第二类丢失更新这些并发问题,在可能出现这类问题的个别场合,可以由应用程序采用悲观锁或乐观锁来控制。
三、乐观锁、悲观锁、行锁、表锁
1、乐观锁
乐观锁:顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新提交的时候才会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。
实现方式:多增加个字段version,代表当前数据版本,当写(增、删、改)表的时候,必须在原来数据版本上自增1;
2、悲观锁
悲观锁:顾名思义,就是很悲观,总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁。
innodb有行锁、表锁,myisam只有表锁
①、行锁
- 行锁又分排它锁(事务A对某一行数据上锁,事务A可进行读、写,但其它事务不可对那一行数据进行读、写)和共享锁(事务A对某一行数据上锁,事务A可进行读、写,其它事务仍可对那一行可读、但不可写)
- 加排他锁可以使用select ...for update语句,加共享锁可以使用select ... lock in share mode语句
②、表锁
- 有索引的行锁就是行锁,没有索引的行锁就是表锁
主键、外键和索引的区别?
一、三者区别
- 作用
主键--用来保证数据完整性,能够唯一标识表中某一行数据
外键--用来和其他表建立联系用的(一般不使用用、废弃状态)
索引--是提高查询排序的速度 - 个数
主键--主键只能有一个,且是一种特殊的唯一索引,不允许有空值
外键--一个表可以有多个外键
索引--一个表可以有多个唯一索引
二、索引的分类
1、从数据结构角度
1、B+树索引(O(log(n))):关于B+树索引,可以参考 MySQL索引背后的数据结构及算法原理
2、hash索引:
- 仅仅能满足"=","IN"和"<=>"查询,不能使用范围查询
- 其检索效率非常高,索引的检索可以一次定位,不像B-Tree 索引需要从根节点到枝节点,最后才能访问到页节点这样多次的IO访问,所以 Hash 索引的查询效率要远高于 B-Tree 索引
- 只有Memory存储引擎显示支持hash索引
3、FULLTEXT索引(现在MyISAM和InnoDB引擎都支持了)
4、R-Tree索引(用于对GIS数据类型创建SPATIAL索引)
2、从物理存储角度
- 聚集索引(clustered index)
- 非聚集索引(non-clustered index)
3、从逻辑角度
- 主键索引:主键索引是一种特殊的唯一索引,不允许有空值
- 普通索引或者单列索引
- 多列索引(复合索引):复合索引指多个字段上创建的索引,只有在查询条件中使用了创建索引时的第一个字段,索引才会被使用。使用复合索引时遵循最左前缀集合
- 唯一索引或者非唯一索引
- 空间索引(patical):空间索引是对空间数据类型的字段建立的索引,MYSQL中的空间数据类型有4种,分别是GEOMETRY、POINT、LINESTRING、POLYGON。
- 全文索引:仅可用于 MyISAM 表,针对较大的数据,生成全文索引很耗时好空间
MySQL存储引擎的选择?
点击链接:Mysql数据库存储引擎
堆内存和栈内存的区别?
栈是编译期间就分配好的内存空间,因此你的代码中必须就栈的大小有明确的定义;
堆是程序运行期间动态分配的内存空间,你可以根据程序的运行情况确定要分配的堆内存的大小,也就是new的时候。
redis是单线程的么,为什么?
是啊!Redis属于内存数据库,进程废内存,多线程不也废内存,这样cpu才不会成为负担
Redis和Memcached的区别?
- Redis和Memcache都是将数据存放在内存中,都是内存数据库。但是Memcache还可以缓存其他东西,比如图片、视频
- Redis不只支持简单的k/v类型的数据,同时还提供list、set、hash等数据结构的存储
- 虚拟内存,当物理内存用完时Redis可以将一些很久没有用到的value交换到磁盘
- 过期策略,memcache在set时就指定,例如
set key1 0 0 8
即永不过期,redis可以通过expire设定,例如:expire name 10
- 分布式,设定memcache集群,利用magent做一主多从;redis也可以做一主多从。
- 存储安全,memcache挂掉后,数据没了;redis可以定期保存在磁盘(持久化)
- 灾难恢复,memcache挂掉后数据不可恢复;redis数据丢失后可以通过aof恢复
- redis支持数据的备份,即master-slave模式的数据备份
- 应用场景不同:redis除了可以做nosql数据库之外,还能做消息队列、数据堆栈和数据缓存等。memcache适合于缓存sql语句、数据集、用户临时性数据、延迟查询数据和session等
redis有哪些数据结构?
string、hash、list、set等
-
String
字符串类型是redis最基础的数据结构,首先键是字符串类型,而且其他几种结构都是在字符串类型基础上构建的
字符串类型实际上可以是字符串、数字、二进制(图片、音频),单最大不能超过512M
使用场景:- 缓存
字符串最经典的使用场景,redis作为缓存层,mysql作为存储层,绝大部分请求数据都是redis中获取,由于redis具有支撑高并发特性,所以缓存通常能起到加速读写和降低后端压力的作用 - 计数器
许多应用都会使用redis作为技术的基础工具,它可以实现快速技术、查询缓存的功能。 - 共享session
处于负载均衡的考虑,分布式服务会将用户信息的访问均衡到不同服务器,用户刷新一次访问可讷讷个会需要重新登录,为了避免这个问题可以使用redis将用户session集中管理,在这种模式下只要保证redis的高可用和扩展性,每次获取用户更新或查询登录信息都直接从redis中集中获取 - 限速
出于安全考虑,每次进行登录时让用户输入手机验证码,为了短信接口不被频繁访问,会限制用户每分钟获取验证码的频率
- 缓存
-
Hash
在redis中哈希类型是指键本身又是一种键值对结构,如value = {{field1,value1}...{fieldn,valuen}}
使用场景:- 哈希结构相对于字符串序列化缓存信息更加直观,并且在更新操作上更加便捷。
-
list
列表类型是用来存储多个有序的字符串,列表的每个字符串成为一个元素,一个列表最多可以存储2的32次方减1个元素。在redis中,可以对列表插入(push)和弹出(pop),还可以获取指定范围的元素列表。列表是一种比较灵活的数据结构,它可以充当栈和队列的角色。
使用场景:- 消息队列
redis的lpush+brpop
命令组合就可以实现阻塞队列,生产者客户端是用lpush
从列表左侧插入元素,多个消费者客户端使用brpop
命令阻塞式的抢列表尾部的元素,多个客户端保证了消费的负载均衡的高可用性。 -
使用技巧列表
rpush+rpop = lpush+lpop = Stack(栈) 先进后出 rpush+lpop = lpush+rpop = Queue(队列) 先进先出 lpush+ltrim=Capped Collection(有限集合) rpush+blpop = lpush+brpop=Message Queue(消息队列)
- 消息队列
- set
- sortedset