一:这种情况下使用redis比较有优势:

  1. redis基于内存而mysql基于硬盘,速度快。
  2. 用的数据库本就是mysql,这时再用mysql进行队列缓存更造成了mysql的负担
  3. redis比memcahe的优势在于 redis定时的将数据持久化到硬盘

二:

Redis list
LPUSH/LPUSHX  :将值插入到(/存在的)列表头部
RPUSH/RPUSHX  :将值插入到(/存在的)列表尾部
LPOP :移出并获取列表的第一个元素
RPOP :移出并获取列表的最后一个元素
LTRIM :保留指定区间内的元素
LLEN :获取列表长度
LSET :通过索引设置列表元素的值
LINDEX :通过索引获取列表中的元素
LRANGE :获取列表中指定范围内的元素

三:架构设计
秒杀.png
四:代码级设计

  1. 秒杀程序把请求写入Redis.(Uid, time_stamp)
  2. 检查Redis已存放数据的长度,超出上限直接丢弃
  3. 死循环处理存入Redis的数据并入库

五: redis_queue数据库表的SQL语句:

   CREATE TABLE `redis_queue` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `uid` int(11) NOT NULL DEFAULT '0',
  `time_stamp` varchar(24) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=71 DEFAULT CHARSET=utf8;

User.php

<?php
$redis = new Redis();
$redis->connect('127.0.0.1',6379);
$redis_name = "miaosha";
for($i=1;$i<100;$i++){
    $uid = rand(100000,999999);
//接受用户的id
//$uid = $_GET['uid'];
//获取redis里面已有的数量
$num = 10;
//如果当天人数少于10时,则加入这个队列
if($redis->lLen($redis_name)<10)  {
    $redis->rPush($redis_name,$uid.'%'.microtime());
    echo $uid."秒杀成功";
}else{
    //反之,则返回秒杀已完成
    echo "秒杀已结束";
}
$redis->close();
}

savetodb.php

<?php
include '../include/db.php';
$redis = new Redis();
$redis->connect('127.0.0.1',6379);
$redis_name = "miaosha";
$db = DB::getIntance();
//死循环
while (1) {
//从队列最左侧取出一个值来,
$user = $redis->lPop($redis_name);
//然后判断这个值是否存在,
if(!$user || $user=='nil') {
    sleep(2);
    continue;
}
//切割出时间,uid
$user_arr = explode('%',$user);
$insert_data = array(
    'uid' =>$user_arr[0],
    'time_stamp'=>$user_arr[1]
);
//保存导数据库中
 $res = $db->insert('redis_queue',$insert_data);
//数据插入失败的时候的回滚机制
    if(!$res) {
        $redis->rPush($redis_name,$user);
    }
    sleep(2);
}
//释放一下redis
$redis->close();

1、查询构造器简
查询构造器提供方便,流畅的接口,简历及执行数据库查找语法
PDO参数绑定,保护程序面SQL注入,传入参数不需要转义字符
在所有支持的数据库系统上都可以执行
新增

   public function query1()
    {
//        $bool = Db::table('student')->insert([
//            'name'=>'ylxc','age'=>18
//        ]);
//        var_dump($bool);
//        $id = Db::table('student')->insertGetId([
//            'name'=>'ylxc','age'=>18
//        ]);
//        var_dump($id);
       $bool = Db::table('student')->insert([
           ['name'=>'ylxc','age'=>18],
           ['name'=>'ylxc1','age'=>18]
        ]);
        var_dump($bool);
    }

路由

Route::any('query1',['uses'=>'StudentController@query1']);

2更新,自增,自减

 public function query2()
    {
        //$num  = Db::table('student')->where('id',1001)->update(['name'=>20]);
        //var_dump($num);
        //$num = Db::table('student')->increment('age');
        //$num = Db::table('student')->where('id', 1001)->decrement('age');
        $num = Db::table('student')->where('id', 1001)->decrement('age',1,['name'=>'ylxinchen']);
        var_dump($num);
    }

路由

 Route::any('query2',['uses'=>'StudentController@query2']);

3.删除

public function query3()
    {
        $num = DB::table('student')->where('id','>=',1010)->delete();
        var_dump($num);
        //$num = DB::table('student')->truncate();
    }

路由

 Route::any('query3',['uses'=>'StudentController@query3']);

4.查询
get() --> 获取所有符合条件的数据(对象数组)
lists() --> 指定一个查询的列,可为查询出来的数组指定键(单投影)
first() --> 获取所有符合条件的数据中的排在第一条的数据(对象)
select() --> 可指定一个或多个要查询的列(多投影)
where() --> 添加查询条件
chunk() --> 每次查询的条数(可添加闭包函数,在函数中对数据进行处理或终止查询)
pluck() --> 指定一个查询的列(单投影)

  public function query4()
        {
        //$bool = Db::table('student')->insert([
        //           ['name'=>'ceshi','age'=>18],
        //           ['name'=>'ceshi1','age'=>18],
        //           ['name'=>'ceshi2','age'=>18],
        //           ['name'=>'ceshi','age'=>18],
        //           ['name'=>'ceshi','age'=>18]
        //       ]);
        //       var_dump($bool);
            //$student = Db::table('student')->get();
            //$student = Db::table('student')->orderBy('id','desc')->first();
            //$student = Db::table('student')->where('id','>=',10)->get();
            //$student = Db::table('student')->whereRaw('id>=? and age>?',[10,18])->get();
            //$student = Db::table('student')->whereRaw('id>=? and age>?',[10,18])->pluck('name');
            //$student = Db::table('student')->lists('name','id');
            //$student = Db::table('student')->select('name','id')->get();
            echo '<per>';
            $student = Db::table('student')->chunk(2,function ($student){
                dump($student);
                return false;
            });
            dd($student);
        }

路由

Route::any('query4',['uses'=>'StudentController@query4']);

5.聚合函数

 public function query5()
        {
            $num = Db::table('student')->count();
            //var_dump($num);die;
            $max = Db::table('student')->max('age');
            $min = Db::table('student')->min('age');
            $avg = Db::table('student')->avg('age');
            $sum = Db::table('student')->sum('age');
            var_dump($sum);die;
        }

路由

 Route::any('query5',['uses'=>'StudentController@query5']);

1.新建本地数据库laravel,新建数据表

CREATE TABLE `student` (
`id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL DEFAULT '' COMMENT '姓名',
  `age` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '年龄',
  `sex` tinyint(3) unsigned NOT NULL DEFAULT '10' COMMENT '性別',
  `created_at` int(11) NOT NULL DEFAULT '0' COMMENT '新增时间',
  `updated_at` int(11) NOT NULL DEFAULT '0' COMMENT '修改时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1001 DEFAULT CHARSET=utf8 COMMENT='学生表';

2.找到数据库的配置 config/database.php

'default' => env('DB_CONNECTION', 'mysql'), //查看默认数据库是否正确
    //看mysql的具体配置是否正确
        'mysql' => [
            'driver'    => 'mysql',
            'host'      => env('DB_HOST', 'localhost'),
            'database'  => env('DB_DATABASE', 'forge'),
            'username'  => env('DB_USERNAME', 'forge'),
            'password'  => env('DB_PASSWORD', ''),
            'charset'   => 'utf8',
            'collation' => 'utf8_unicode_ci',
            'prefix'    => '',
            'strict'    => false,
            'engine'    => null,
        ],

3.找env文件
Laravel .env 文件
修改配置

DB_HOST=localhost
DB_DATABASE=laravel
DB_USERNAME=root
DB_PASSWORD=root

4.新建appHttpControllersStudentController.php

<?php

namespace App\Http\Controllers;
use Illuminate\Support\Facades\Db;

class StudentController extends Controller
{
    public function test1()
    {

        //$bool = DB::insert('insert into student(name,age) values(?,?)',['ylxinchen',18]);
        //var_dump($bool);die;
        //更新
        //$num = DB::update('update student set age = ? where name = ?',['20','ylxinchen']);
        //var_dump($num);die;
        //查询
        //$result = DB::select('select * from student');
        //dd($result);
        //删除
        //$num  = DB::delete('delete from student where id > ?',[1001]);
        //var_dump($num);die;
    }
}

5.设置路由appHttproutes.php

Route::any('test1',['uses'=>'StudentController@test1']);

1.查询

 public function orm1()
        {
            //$students = Student::all();
            //$students = Student::find(1);
            //$students = Student::findOrFail(1006);
            //$students = Student::get();
            //$students = Student::where('id','>','10')->orderBy('age','desc')->first();
            //echo '<pre>';
            //Student::chunk(2,function ($students){
                //var_dump($students);
            //});
            //dd($students);
            //$num = Student::count();
            $max = Student::where('id','>',10)->max('age');
            var_dump($max);
        }

路由

Route::any('orm1',['uses'=>'StudentController@orm1']);

2.新增,自定义时间戳及批量赋值

 public function orm2()
    {
        //$student = new Student();
        //$student->name = 'cheshi';
        //$student->age = '18';
        //$bool = $student->save();
        //dd($student);
        //$student = Student::find(26);
        //echo $student->created_at;die;
        //$student = Student::create(
            //['name'=>'immoc','age'=>18]
        //);
        //$student = Student::firstOrCreate(
            //['name'=>'imooc']
        //);
        $student = Student::firstOrNew(
            ['name'=>'imoocs']
        );
        $bool = $student->save();
        dd($bool);
    }

路由

Route::any('orm2',['uses'=>'StudentController@orm2']);

2.修改

 public function orm3()
        {
            //$student = Student::find(30);
            //$student ->name = 'kity';
            //$bool = $student->save();
            //var_dump($bool);die;

            $num = Student::where('id','>',10)->update(
                ['age'=>18]
            );
            var_dump($num);
        }

路由

Route::any('orm3',['uses'=>'StudentController@orm3']);

3.删除

 public function orm4()
        {
            //$student = Student::find(10);
            //$bool = $student->delete();
            //var_dump($bool);
            //$num = Student::destroy(11);
            //$num = Student::destroy([12,13]);
            $num = Student::where('id','>',28)->delete();
            var_dump($num);
        }

路由

Route::any('orm4',['uses'=>'Stu dentController@orm4']);

前言
在以前,一个网站的完成总是“all in one”,页面,数据,渲染全部在服务端完成,这样做的最大的弊端是后期维护,扩展极其痛苦,开发人员必须同时具备前后端知识。于是慢慢的后来兴起了前后端分离的思想:
后端负责数据编造,而前端则负责数据渲染,前端静态页面调用指定api获取到有固定格式的数据,再将数据展示出来,这样呈现给用户的就是一个”动态“的过程,而关于api这部分的设计则成了一个问题。如何设计出一个便于理解,容易使用的api则成了一个问题。
而所谓的restful就是用来规范我们的api的一种约束。

介绍
rest是REpresentational State Transfer三个单词的缩写,由Roy Fielding于2000年论文中提出,它代表着分布式服务的架构风格。而如果想你的api被称为restful api,只要遵循其规定的约束即可。

rest设计原则
客户端-服务器:通过将用户UI与数据存储分开,我们可以简化服务器组件来提高跨多个平台的用户界面的可移植性并提高可伸缩性。 它可以比表现成前后端分离的思想。
无状态:从客户端到服务器的每个请求都必须包含理解请求所需的所有信息,并且不能利用服务器上任何存储的上下文。 这表示你应该尽可能的避免使用session,由客户端自己标识会话状态。(token)
规范接口:REST接口约束定义:资源识别; 请求动作; 响应信息; 它表示通过uri标出你要操作的资源,通过请求动作(http method)标识要执行的操作,通过返回的状态码来表示这次请求的执行结果。
可缓存: 缓存约束要求将对请求的响应中的数据隐式或显式标记为可缓存或不可缓存。如果响应是可缓存的,则客户端缓存有权重用该响应数据以用于以后的等效请求。 它表示get请求响应头中应该表示有是否可缓存的头(Cache-Control)
其中1,2,3约束最为重要,其中1容易理解。接下来我们就谈谈无状态和规范接口的原则。
uri规范
资源的描述构成了uri,它一般有以下约束:

使用名词。如 user, student, class
http://api.example.com/class-management/students
http://api.example.com/device-management/managed-devices/{device-id}
http://api.example.com/user-management/users/
http://api.example.com/user-management/users/{id}

http method对应不同的请求动作(数据库或者业务逻辑)
GET:查询操作:
HTTP GET /devices?startIndex=0&size=20
HTTP GET /configurations?startIndex=0&size=20
HTTP GET /devices/{id}/configurations
HTTP GET /devices/{id}
POST:新增操作:
HTTP POST /device
PUT 更新操作(代表更新一个实体的所有属性)
HTTP PUT /devices/{id}
PATCH 部分更新(代表更新一个尸体的部分属性)由于有的浏览器兼容性问题,一般推荐使用put
HTTP PATCH /devices/{id}
DELETE 删除操作
HTTP DELETE /devices/{id}

使用连字符( - )而不是(_)来提高URI的可读性
http://api.example.com/inventory-management/managed-entities/{id}/install-script-location //更易读
http://api.example.com/inventory_management/managed_entities/{id}/install_script_location //更容易出错

在URI中使用小写字母
http://api.example.org/my-folder/my-doc

不要使用文件扩展名 文件扩展名看起来很糟糕,不会增加任何优势。删除它们也会减少URI的长度。没理由保留它们。
http://api.example.com/device-management/managed-devices.xml / 不要使用它 /
http://api.example.com/device-management/managed-devices / 这是正确的URI /

使用查询组件过滤URI集合
很多时候,我们会遇到需要根据某些特定资源属性对需要排序,过滤或限制的资源集合的要求。为此,请不要创建新的API - 而是在资源集合API中启用排序,过滤和分页功能,并将输入参数作为查询参数传递。例如
http://api.example.com/device-management/managed-devices
http://api.example.com/device-management/managed-devices?region=USA
http://api.example.com/device-management/managed-devices?region=USA&brand=XYZ
http://api.example.com/device-management/managed-devices?region=USA&brand=XYZ&sort=installation-date

不要在末尾使用/
作为URI路径中的最后一个字符,正斜杠(/)不会添加语义值,并可能导致混淆。最好完全放弃它们。

使用http状态码定义api执行结果
1xx:信息
通信传输协议级信息。

2xx:成功
表示客户端的请求已成功接受。

3xx:重定向
表示客户端必须执行一些其他操作才能完成其请求。

4xx:客户端错误
此类错误状态代码指向客户端。

5xx:服务器错误
服务器负责这些错误状态代码。
另外完整的更为详细的状态码此处不做赘述。一般简化版本的api会使用200,400,500,其中400代表客户端调用有误,将错误信息放入response:

{
"error": "username.or.password.error"
}
api版本定义
当我们需要对现有的api接口升级的时候,因为该api接口已经投入使用,所以新添加的业务可能无法保证兼容原来的逻辑,这个时候就需要新的接口,而这个接口一般表示对原来的接口的升级(不同版本),那版本怎么定义呢?
URI版本控制(推荐)
http://api.example.com/v1
http://apiv1.example.com
使用自定义请求标头进行版本控制
Accept-version:v1
Accept-version:v2
使用Accept header 进行版本控制
Accept:application / vnd.example.v1 + json
Accept:application / vnd.example + json; version = 1.0
无状态
使REST API无状态有一些非常显着的优点:

无状态通过将API部署到多个服务器,有助于将API扩展到数百万并发用户。任何服务器都可以处理任何请求,因为没有与会话相关的依赖。(集群)
无状态使得REST API不那么复杂 - 可以删除所有服务器端状态同步逻辑。(删除session,清理多余空间)
无状态API也很容易缓存。特定软件可以通过查看该一个请求来决定是否缓存HTTP请求的结果。从先前的请求中获得的状态可能会影响这个请求的可缓存性,这并不存在任何不确定性。它提高了应用程序的性能。
服务器永远不会忘记每个客户端身份”,因为客户端会在每个请求中发送所有必要的信息。(携带token)
那么无状态又要怎么实现呢?前面我们已经说了,服务端不应该再保存session会话,这个工作全部交由http请求去标识,而最常见的做法则是使用token。生成token可以考虑使用jwt,oauth。

作者:jsbintask
链接:https://www.jianshu.com/p/a35bad7dbc54
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。