代码如下:

$t1 = microtime(true);
// ... 执行代码 ...
$t2 = microtime(true);
echo '耗时 '.round($t2-$t1, 3).' 秒';

microtime() 如果带有 true 参数,将返回一个浮点类型。

这样 t1 和 t2 得到的就是两个浮点数,相减之后得到之间的差。

由于浮点的位数很长,或者说不确定,所以再用 round() 取出小数点后 3 位。

代码如下:

// 设置HTTP状态码
function http_header($num) {
    $http = array(
        100 => "HTTP/1.1 100 Continue",
        101 => "HTTP/1.1 101 Switching Protocols",
        200 => "HTTP/1.1 200 OK",
        201 => "HTTP/1.1 201 Created",
        202 => "HTTP/1.1 202 Accepted",
        203 => "HTTP/1.1 203 Non-Authoritative Information",
        204 => "HTTP/1.1 204 No Content",
        205 => "HTTP/1.1 205 Reset Content",
        206 => "HTTP/1.1 206 Partial Content",
        300 => "HTTP/1.1 300 Multiple Choices",
        301 => "HTTP/1.1 301 Moved Permanently",
        302 => "HTTP/1.1 302 Found",
        303 => "HTTP/1.1 303 See Other",
        304 => "HTTP/1.1 304 Not Modified",
        305 => "HTTP/1.1 305 Use Proxy",
        307 => "HTTP/1.1 307 Temporary Redirect",
        400 => "HTTP/1.1 400 Bad Request",
        401 => "HTTP/1.1 401 Unauthorized",
        402 => "HTTP/1.1 402 Payment Required",
        403 => "HTTP/1.1 403 Forbidden",
        404 => "HTTP/1.1 404 Not Found",
        405 => "HTTP/1.1 405 Method Not Allowed",
        406 => "HTTP/1.1 406 Not Acceptable",
        407 => "HTTP/1.1 407 Proxy Authentication Required",
        408 => "HTTP/1.1 408 Request Time-out",
        409 => "HTTP/1.1 409 Conflict",
        410 => "HTTP/1.1 410 Gone",
        411 => "HTTP/1.1 411 Length Required",
        412 => "HTTP/1.1 412 Precondition Failed",
        413 => "HTTP/1.1 413 Request Entity Too Large",
        414 => "HTTP/1.1 414 Request-URI Too Large",
        415 => "HTTP/1.1 415 Unsupported Media Type",
        416 => "HTTP/1.1 416 Requested range not satisfiable",
        417 => "HTTP/1.1 417 Expectation Failed",
        500 => "HTTP/1.1 500 Internal Server Error",
        501 => "HTTP/1.1 501 Not Implemented",
        502 => "HTTP/1.1 502 Bad Gateway",
        503 => "HTTP/1.1 503 Service Unavailable",
        504 => "HTTP/1.1 504 Gateway Time-out"
    );
    header($http[$num]);
}

相同表结构

INSERT INTO table1 SELECT * FROM table2;

不同表结构

INSERT INTO table1(filed1, ..., filedn) SELECT table2.filed1, ..., table2.filedn FROM table2;

不同数据库

INSERT into db1.table1(id, number, name) 
  SELECT stu.person_id
     , stu.number
     , person.name
FROM db2.t_stu_info AS stu
    , db2.t_person_info as person
    WHERE stu.person_id = person.id

1695043.jpg

问题描述

一般电子商务网站都会遇到如团购、秒杀、特价之类的活动,而这样的活动有一个共同的特点就是访问量激增、上千甚至上万人抢购一个商品。

然而,作为活动商品,库存肯定是很有限的,如何控制库存不让出现超卖,以防止造成不必要的损失,是众多电子商务网站程序员头疼的问题,这同时也是最基本的问题。

条件

总库存:4个商品
请求人:a、1个商品 b、2个商品 c、3个商品

错误示例

$pdo->beginTransaction();
try{
    $result = $pdo->query('select amount from s_store where postID = 12345');
    if($result->amount > 0){
        // quantity 为请求减掉的库存数量
        $pdo->query('update s_store set amount = amount - quantity where postID = 12345');
    }
    // 没有错误则提交事务
    $pdo->commit();
}catch($e \PDOException){
    // 遇到错误则回滚事务
    $pdo->rollBack();
    echo "Failed: " . $e->getMessage();
}

使用 SELECT ... FOR UPDATE

$pdo->beginTransaction();
try{
    // 使用 SELECT ... FOR UPDATE 将此行数据锁住,在提交事务或者回滚事务时自动解开。
    $result = $pdo->query('select amount from s_store where postID = 12345 for update');
    if($result->amount < 0){
        // 抛出异常
        throw new \PDOException('库存不足');
    }
    // quantity 为请求减掉的库存数量
    $pdo->query('update s_store set amount = amount - quantity where postID = 12345');
    // 没有错误则提交事务
    $pdo->commit();
}catch($e \PDOException){
    // 遇到错误则回滚事务
    $pdo->rollBack();
    echo "Failed: " . $e->getMessage();
}

其他方法

- 阅读剩余部分 -

在工作中,我们经常会遇到这样的问题,需要更新库存,当我们查询到可用的库存准备修改时,这时,其他的用户可能已经对这个库存数据进行修改了,导致,我们查询到的数据会有问题,下面我们就来看解决方法。

如果SELECT 后面若要UPDATE 同一个表单,最好使用SELECT ... UPDATE。

举个例子

假设商品表单 products 内有一个存放商品数量的 quantity,在订单成立之前必须先确定 quantity 商品数量是否足够( quantity > 0 ),然后才把数量更新为 1 。

SELECT quantity FROM products WHERE id = 3; UPDATE products SET quantity = 1 WHERE id = 3;

开启事务

为什么不安全呢?

高并发时会出现问题,如果我们需要在 quantity > 0 的情况下才能扣库存,假设程序在第一行 SELECT 读到的 quantity 是 2,但是当 MySQL 正准备要 UPDATE 的时候,可能已经有人把库存扣成 0 了,但是程序却浑然不知,将错就错的 UPDATE 下去了。因此必须利用事务机制来确保读取及提交的数据都是正确的。

BEGIN WORK; SELECT quantity FROM products WHERE id = 3 FOR UPDATE;

此时 products 数据中 id = 3 的数据被锁住,其它事务必须等待此次事务提交后才能执行。

SELECT * FROM products WHERE id = 3 FOR UPDATE;

- 阅读剩余部分 -

事务处理

事务 (transaction) 是由查询和/或更新语句的序列组成。用 begin、start transaction 开始事务,rollback 回滚事务,commit 提交事务。

在开始事务后,可以有若干个 SQL 查询或更新语句,每个 SQL 递交执行后,还应该有判断是否正确执行的语句,以确定下一步是否回滚,若都被正确执行则最后提交事务。

事务一旦回滚,数据库则保持开始事务前状态。就好象一个被编辑的文件不存盘退出,自然还是保持文件原来的样子。

所以,事务可被视为原子操作,事务中的 SQL,要么全部执行,要不一句都不执行。

如果需要一个事务,则必须用 PDO::beginTransaction() 方法来启动,一旦开始了事务,可用 PDO::commit() 或 PDO::rollBack()来完成,这取决于事务中的代码是否运行成功。

Tips: MySQL只有 InnoDB 驱动支持事务处理,默认 MyIsAM 驱动不支持。

代码示例

连接数据库:

<?php
try {
    // 数据库 PDO 连接
    $pdo = new \PDO('mysql:host=localhost;dbname=mydb', 'root', 'root', array(PDO::ATTR_PERSISTENT => true));
    // 开启异常处理
    $pdo->setAttribute(PDO::ATTR_ERRMODE,  PDO::ERRMODE_EXCEPTION);
} catch (\PDOException $e) {
    echo "数据库连接失败:".$e->getMessage();
    exit;
}

事务处理:
在下面例子中,假设为新员工创建一组条目,分配一个为 23 的 ID。除了登记资料,还需要记录工资。

- 阅读剩余部分 -

原理

当版本库代码更新时,通过 git 的 webhook(git web 钩子)触发 push 事件。用户提交代码(git push)服务器的宝塔 webhook 插件拉取当前 git 最新代码(git pull)。

步骤

1、CentOS 服务器安装宝塔面板:宝塔面板
linux_pc_free.png

2、安装 git:

yum install git

Tips: Git 生成 SSH 公钥

3、宝塔面板软件商店安装 宝塔WebHook;
20191110195119.png

4、添加 HOOK 命令:

#!/bin/bash
echo ""
#输出当前时间
date --date='0 days ago' "+%Y-%m-%d %H:%M:%S"
echo "Start"
#判断宝塔WebHook参数是否存在
if [ ! -n "$1" ];
then
          echo "param参数错误"
          echo "End"
          exit
fi
#git项目路径
gitPath="/www/wwwroot/web/$1"
#git 网址
gitHttp="http://git.xxxxx.com/web/$1.git"

echo "Web站点路径:$gitPath"

#判断项目路径是否存在
if [ -d "$gitPath" ]; then
        cd $gitPath
        #判断是否存在git目录
        if [ ! -d ".git" ]; then
                echo "在该目录下克隆 git"
                git clone $gitHttp gittemp
                mv gittemp/.git .
                rm -rf gittemp
        fi
        #拉取最新的项目文件
        git reset --hard origin/master
        git pull
        #设置目录权限
        chown -R www:www $gitPath
        echo "End"
        exit
else
        echo "该项目路径不存在"
        echo "End"
        exit
fi

- 阅读剩余部分 -

071305064859837.png

SSH 存储位置

默认情况下,用户的 SSH 密钥存储在其 ~/.ssh 目录下。(CentOS 存储在 /root/.ssh;Windows 存储在 C:\Users\Administrator\.ssh)

查看目录下是否存在 SSH 公钥:

$ cd ~/.ssh
$ ls
authorized_keys2  id_dsa       known_hosts
config            id_dsa.pub

id_dsa 或 id_rsa 文件应该成对出现,其中一个带有 .pub 扩展名。.pub 文件是你的公钥,另一个则是私钥。

运行 ssh-keygen 生成

ssh-keygen -t rsa -C "your@example.com"

your@example.com 是你的邮箱。

测试连通性

ssh -T git@github.com

配置 name 和 email

git config --global user.name "yourname"
git config --global user.email "your@example.com"

2018-07-05更新

再次修改插件,主要包含一下更新:

  1. 常规更新,使用最新Release版阿里云SDK;
  2. 应博客中留言的朋友们要求,使上传和下载时的文件名保持一致;
  3. 可以自定义http或https的加速域名;
  4. 添加若干区域的支持。

插件使用说明

插件基于aliyun-oss-php-sdk Release 2.3.0开发, 若以后SDK开发包更新导致插件不可用,请到 我的博客 ^ - ^获取新版本插件, 如果我还用typecho还用阿里云就会更新。
请赋予 文件上传目录 以及 插件日志目录 写权限,否则可能导致上传失败。

若开启“在服务器保留备份”功能:
成功保存文件到OSS但没有成功保存到服务器的情况下插件不会报错, 这将导致当前文件在服务器上没有备份,但是会插件日志目录下生成错误日志"error.log",请定期查阅并清理。

运行在云应用引擎上的站点“在服务器保留备份”选项无效。

旧版本Typecho存在无法上传大写扩展名文件的bug,请更新Typecho程序。

下载地址:

本地下载:AliOssForTypecho_v1.1.1.zip

磁盘挂载方法

查看已使用的磁盘情况:

df -HT

查看所有磁盘:

fdisk -l

查看指定磁盘的分区情况:

fdisk -l /dev/xvdb1

对磁盘进行分区:

fdisk /dev/xvdb1

查看刚刚分配的磁盘号:

fdisk -l

格式化磁盘:

mkfs -t ext4 /dev/xvdb1

-t 表示指定格式化磁盘的文件系统类型为ext4,默认不指定为ext2(比较老的linux文件系统类型)centos7默认系统格式是xfs格式,格式化磁盘的时候也可以指定类型为xfs格式;

- 阅读剩余部分 -