邢栋博客

邢栋博客,Action博客,记录工作和生活中的点点滴滴

关于redis pipeline
=====为什么需要 pipeline ?=====
Redis 的工作过程是基于 请求/响应 模式的。正常情况下,客户端发送一个命令,等待 Redis 应答;Redis 接收到命令,处理后应答。请求发出到响应的时间叫做往返时间,即 RTT(Round Time Trip)。在这种情况下,如果需要执行大量的命令,就需要等待上一条命令应答后再执行。这中间不仅仅多了许多次 RTT,而且还频繁的调用系统 IO,发送网络请求。为了提升效率,pipeline 出现了,它允许客户端可以一次发送多条命令,而不等待上一条命令执行的结果。

=====实现思路=====
客户端首先将执行的命令写入到缓冲区中,最后再一次性发送 Redis。但是有一种情况就是,缓冲区的大小是有限制的:如果命令数据太大,可能会有多次发送的过程,但是仍不会处理 Redis 的应答。

=====实现原理=====
要支持 pipeline,既要服务端的支持,也要客户端支持。对于服务端来说,所需要的是能够处理一个客户端通过同一个 TCP 连接发来的多个命令。可以理解为,这里将多个命令切分,和处理单个命令一样。对于客户端,则是要将多个命令缓存起来,缓冲区满了就发送,然后再写缓冲,最后才处理 Redis 的应答。

=====Redis pipeline 的参考资料=====
https://redis.io/topics/pipelining

=====在php中使用Redis pipeline=====
<?php
 //实例化redis
$redis = new Redis();
//连接
$redis->connect('127.0.0.1', 6379);
$redis->pipeline();//开启管道
if(!$redis){
    throw new Exception('redis连接失败!',1);
}
$key = "pipeline_test";
$len = 200000;
$succ = 0;
for($i=0;$i<$len;$i++){
    $res = $redis->hset($key,"test_".$i,1);
    if($res){
        $succ ++;
    }
}
$redis->exec();

=====总结:Redis pipeline 的特性以及使用时需要注意的地方=====
pipeline 减少了 RTT,也减少了IO调用次数(IO 调用涉及到用户态到内核态之间的切换)
如果某一次需要执行大量的命令,不能放到一个 pipeline 中执行。数据量过多,网络传输延迟会增加,且会消耗 Redis 大量的内存。应该将大量的命令切分为多个 pipeline 分别执行。

常用正则表达式总结

一、校验数字的表达式

1 数字:^[0-9]*$
2 n位的数字:^\d{n}$
3 至少n位的数字:^\d{n,}$
4 m-n位的数字:^\d{m,n}$
5 零和非零开头的数字:^(0|[1-9][0-9]*)$
6 非零开头的最多带两位小数的数字:^([1-9][0-9]*)+(.[0-9]{1,2})?$
7 带1-2位小数的正数或负数:^(\-)?\d+(\.\d{1,2})?$
8 正数、负数、和小数:^(\-|\+)?\d+(\.\d+)?$
9 有两位小数的正实数:^[0-9]+(.[0-9]{2})?$
10 有1~3位小数的正实数:^[0-9]+(.[0-9]{1,3})?$
11 非零的正整数:^[1-9]\d*$ 或 ^([1-9][0-9]*){1,3}$ 或 ^\+?[1-9][0-9]*$
12 非零的负整数:^\-[1-9][]0-9"*$ 或 ^-[1-9]\d*$
13 非负整数:^\d+$ 或 ^[1-9]\d*|0$
14 非正整数:^-[1-9]\d*|0$ 或 ^((-\d+)|(0+))$
15 非负浮点数:^\d+(\.\d+)?$ 或 ^[1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0$
16 非正浮点数:^((-\d+(\.\d+)?)|(0+(\.0+)?))$ 或 ^(-([1-9]\d*\.\d*|0\.\d*[1-9]\d*))|0?\.0+|0$
17 正浮点数:^[1-9]\d*\.\d*|0\.\d*[1-9]\d*$ 或 ^(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*))$
18 负浮点数:^-([1-9]\d*\.\d*|0\.\d*[1-9]\d*)$ 或 ^(-(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*)))$
19 浮点数:^(-?\d+)(\.\d+)?$ 或 ^-?([1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0)$

二、校验字符的表达式

1 汉字:^[\u4e00-\u9fa5]{0,}$
2 英文和数字:^[A-Za-z0-9]+$ 或 ^[A-Za-z0-9]{4,40}$
3 长度为3-20的所有字符:^.{3,20}$
4 由26个英文字母组成的字符串:^[A-Za-z]+$
5 由26个大写英文字母组成的字符串:^[A-Z]+$
6 由26个小写英文字母组成的字符串:^[a-z]+$
7 由数字和26个英文字母组成的字符串:^[A-Za-z0-9]+$
8 由数字、26个英文字母或者下划线组成的字符串:^\w+$ 或 ^\w{3,20}$
9 中文、英文、数字包括下划线:^[\u4E00-\u9FA5A-Za-z0-9_]+$
10 中文、英文、数字但不包括下划线等符号:^[\u4E00-\u9FA5A-Za-z0-9]+$ 或 ^[\u4E00-\u9FA5A-Za-z0-9]{2,20}$
11 可以输入含有^%&',;=?$\"等字符:[^%&',;=?$\x22]+
12 禁止输入含有~的字符:[^~\x22]+

三、特殊需求表达式

1 Email地址:^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$
2 域名:[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(/.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+/.?
3 InternetURL:[a-zA-z]+://[^\s]* 或 ^http://([\w-]+\.)+[\w-]+(/[\w-./?%&=]*)?$
4 手机号码:^(13[0-9]|14[0-9]|15[0-9]|16[0-9]|17[0-9]|18[0-9]|19[0-9])\d{8}$ (由于工信部放号段不定时,所以建议使用泛解析 ^([1][3,4,5,6,7,8,9])\d{9}$)
5 电话号码("XXX-XXXXXXX"、"XXXX-XXXXXXXX"、"XXX-XXXXXXX"、"XXX-XXXXXXXX"、"XXXXXXX"和"XXXXXXXX):^(\(\d{3,4}-)|\d{3.4}-)?\d{7,8}$ 
6 国内电话号码(0511-4405222、021-87888822):\d{3}-\d{8}|\d{4}-\d{7} 
7 18位身份证号码(数字、字母x结尾):^((\d{18})|([0-9x]{18})|([0-9X]{18}))$
8 帐号是否合法(字母开头,允许5-16字节,允许字母数字下划线):^[a-zA-Z][a-zA-Z0-9_]{4,15}$
9 密码(以字母开头,长度在6~18之间,只能包含字母、数字和下划线):^[a-zA-Z]\w{5,17}$
10 强密码(必须包含大小写字母和数字的组合,不能使用特殊字符,长度在8-10之间):^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,10}$  
11 日期格式:^\d{4}-\d{1,2}-\d{1,2}
12 一年的12个月(01~09和1~12):^(0?[1-9]|1[0-2])$
13 一个月的31天(01~09和1~31):^((0?[1-9])|((1|2)[0-9])|30|31)$ 
14 钱的输入格式:
15    1.有四种钱的表示形式我们可以接受:"10000.00" 和 "10,000.00", 和没有 "分" 的 "10000" 和 "10,000":^[1-9][0-9]*$ 
16    2.这表示任意一个不以0开头的数字,但是,这也意味着一个字符"0"不通过,所以我们采用下面的形式:^(0|[1-9][0-9]*)$ 
17    3.一个0或者一个不以0开头的数字.我们还可以允许开头有一个负号:^(0|-?[1-9][0-9]*)$ 
18    4.这表示一个0或者一个可能为负的开头不为0的数字.让用户以0开头好了.把负号的也去掉,因为钱总不能是负的吧.下面我们要加的是说明可能的小数部分:^[0-9]+(.[0-9]+)?$ 
19    5.必须说明的是,小数点后面至少应该有1位数,所以"10."是不通过的,但是 "10" 和 "10.2" 是通过的:^[0-9]+(.[0-9]{2})?$ 
20    6.这样我们规定小数点后面必须有两位,如果你认为太苛刻了,可以这样:^[0-9]+(.[0-9]{1,2})?$ 
21    7.这样就允许用户只写一位小数.下面我们该考虑数字中的逗号了,我们可以这样:^[0-9]{1,3}(,[0-9]{3})*(.[0-9]{1,2})?$ 
22    8.1到3个数字,后面跟着任意个 逗号+3个数字,逗号成为可选,而不是必须:^([0-9]+|[0-9]{1,3}(,[0-9]{3})*)(.[0-9]{1,2})?$ 
23    备注:这就是最终结果了,别忘了"+"可以用"*"替代如果你觉得空字符串也可以接受的话(奇怪,为什么?)最后,别忘了在用函数时去掉去掉那个反斜杠,一般的错误都在这里
24 xml文件:^([a-zA-Z]+-?)+[a-zA-Z0-9]+\\.[x|X][m|M][l|L]$
25 中文字符的正则表达式:[\u4e00-\u9fa5]
26 双字节字符:[^\x00-\xff]    (包括汉字在内,可以用来计算字符串的长度(一个双字节字符长度计2,ASCII字符计1))
27 空白行的正则表达式:\n\s*\r    (可以用来删除空白行)
28 HTML标记的正则表达式:<(\S*?)[^>]*>.*?</\1>|<.*? />    (网上流传的版本太糟糕,上面这个也仅仅能部分,对于复杂的嵌套标记依旧无能为力)
29 首尾空白字符的正则表达式:^\s*|\s*$或(^\s*)|(\s*$)    (可以用来删除行首行尾的空白字符(包括空格、制表符、换页符等等),非常有用的表达式)
30 腾讯QQ号:[1-9][0-9]{4,}    (腾讯QQ号从10000开始)
31 中国邮政编码:[1-9]\d{5}(?!\d)    (中国邮政编码为6位数字)
32 IP地址:\d+\.\d+\.\d+\.\d+    (提取IP地址时有用)
33 IP地址:((?:(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d)\\.){3}(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d))    
php简单工厂、工厂模式、抽象工厂实例总结

简单工厂


<?php
/**
 * Created by PhpStorm.
 * User: xingdong
 * Date: 2019/8/3
 * Time: 上午10:05
 */

//简单工厂
interface Product
{
    public function getPrice();
    public function getName();
}

class ProductA implements Product
{
    public function getPrice()
    {
        return 100;
    }

    public function getName()
    {
        return 'ProductA';
    }
}

class ProductB implements Product
{
    public function getPrice()
    {
        return 200;
    }

    public function getName()
    {
        return 'ProductB';
    }
}

class ProductC implements Product
{
    public function getPrice()
    {
        return 300;
    }

    public function getName()
    {
        return 'ProductC';
    }
}

class Factory
{
    public static function createProduct($type)
    {
        $product = null;
        switch ($type){
            case "A":
                $product = new ProductA();
                break;
            case "B":
                $product = new ProductB();
                break;
            case "C":
                $product = new ProductC();
                break;
        }
        return $product;
    }
}


$productA = Factory::createProduct('A');
$productB = Factory::createProduct('B');
$productC = Factory::createProduct('C');


/**
 * 以上便是简单工厂模式的一个典型事例,当用户需要新增产品ProductD时,必须在工厂类的生产方法中增加
对应的判断分支,所以简单工厂模式违背了开放封闭原则。
简单工厂模式,利用静态方法根据输入参数生成对应的产品,隐藏了产品实例化的细节。
总结: 简单工厂模式最大的优点在于工厂类中包含了必要的逻辑判断,根据客户端的选择条件动态实例化相关的类,
对于客户端来说,去除了与具体产品的依赖。但是当需求变动的时候,需要对原有的类进行修改,违背了开放封闭原则。
 *
 *
 */
工厂模式



<?php
/**
 * Created by PhpStorm.
 * User: xingdong
 * Date: 2019/8/3
 * Time: 上午10:05
 */

//工厂方式模式
interface Product
{
    public function getPrice();
    public function getName();
}

class ProductA implements Product
{
    public function getPrice()
    {
        return 100;
    }

    public function getName()
    {
        return 'ProductA';
    }
}

class ProductB implements Product
{
    public function getPrice()
    {
        return 200;
    }

    public function getName()
    {
        return 'ProductB';
    }
}

class ProductC implements Product
{
    public function getPrice()
    {
        return 300;
    }

    public function getName()
    {
        return 'ProductC';
    }
}

interface IFactory{
    public function createProduct();
}

class FactoryA implements IFactory
{
    public function createProduct()
    {
        return new ProductA();
    }
}
class FactoryB implements IFactory
{
    public function createProduct()
    {
        return new ProductB();
    }
}
class FactoryC implements IFactory
{
    public function createProduct()
    {
        return new ProductC();
    }
}

$factoryA = new FactoryA();
$factoryA->createProduct();

$factoryB = new FactoryB();
$factoryB->createProduct();

$factoryC = new FactoryC();
$factoryC->createProduct();

/**
 * 当需要增加一个新产品ProductD,只需要新建对应的FactoryD来实现生产功能即可,对原有的代码
没有任何影响,非常符合开放封闭原则,但是由于每增加一个产品,都需要新增对应的生产工厂,导致增加额外的开发工作量。

总结:由于使用了多态,工厂方法克服了简单工厂违背的开放封闭原则的缺点,又保持了封装对象创建过程的优点。
 */
抽象工厂



<?php
/**
 * Created by PhpStorm.
 * User: xingdong
 * Date: 2019/8/3
 * Time: 上午10:05
 */

//抽象工厂方式
//商品
interface Product
{
    public function getPrice();
    public function getName();
}

class ProductA implements Product
{
    public function getPrice()
    {
        return 100;
    }

    public function getName()
    {
        return 'ProductA';
    }
}

class ProductB implements Product
{
    public function getPrice()
    {
        return 200;
    }

    public function getName()
    {
        return 'ProductB';
    }
}

class ProductC implements Product
{
    public function getPrice()
    {
        return 300;
    }

    public function getName()
    {
        return 'ProductC';
    }
}

//礼品
interface Gift
{
    public function getGiftName();
}

class GiftA implements Gift
{
    public function getGiftName()
    {
        return 'GiftA';
    }
}

class GiftB implements Gift
{
    public function getGiftName()
    {
        return 'GiftB';
    }
}

class GiftC implements Gift
{
    public function getGiftName()
    {
        return 'GiftC';
    }
}

interface IFactory{
    public function createProduct();
    public function createGift();
}

class FactoryA implements IFactory
{
    public function createProduct()
    {
        return new ProductA();
    }

    public function createGift()
    {
        return new GiftA();
    }
}
class FactoryB implements IFactory
{
    public function createProduct()
    {
        return new ProductB();
    }
    public function createGift()
    {
        return new GiftB();
    }
}
class FactoryC implements IFactory
{
    public function createProduct()
    {
        return new ProductC();
    }
    public function createGift()
    {
        return new GiftC();
    }
}

$factoryA = new FactoryA();
$factoryA->createProduct();

$factoryB = new FactoryB();
$factoryB->createProduct();

$factoryC = new FactoryC();
$factoryC->createProduct();

/**
 * 总结:抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口,而无需制定他们具体的类。
抽象工厂接口,应该包含所有的产品创建的抽象方法,我们可以定义实现不止一个接口,
一个工厂也可以生产不止一种产品类,和工厂方法模式一样,抽象工厂模式同样实现了开发封闭原则
 */


数据结构之数组和链表
====数组=====
1.在内存中,数组是一块连续的区域
2.数组需要预留空间,在使用前需要提前申请所占内存的大小
3.在数组起始位置处,插入数据和删除数据效率低
-插入数据时,待插入位置的元素和它后面的所有元素都需要向后搬移
-删除数据时,待删除位置后面的所有元素都要向前搬移
4.随机访问速度效率很高,时间复杂度可以到达O(1)
因为数组的内存是连续的,想要访问那个元素,直接从数组的首地址向后偏移就可以访问到了
5.数组开辟的空间,在不够使用的时候需要扩容,扩容的话,就会涉及需要把旧数组的所有数据向新数组中搬移
6.数组的空间是从栈分配的
====数组的优点====
随机访问性强,查找速度快,时间复杂度O(1)
====数组的缺点====
1.头插和头删的效率低,时间复杂度O(N)
2.空间利用率不高
3.内存空间要求高,必须有足够的连续的内存空间
4.数组空间的大小固定,不能动态扩展


=====链表=====
1.在内存中,元素的空间可以在任意地方,空间是分散的,不需要连续 
2.链表中的元素都会两个属性,一个是元素的值,另一个是指针,此指针标记了下一个元素的地址
每一个数据都会保存下一个数据的内存的地址,通过此地址可以找到下一个数据
3.查找数据时效率低,时间复杂度为O(N)
因为链表的空间是分散的,所以不具有随机访问性,如要需要访问某个位置的数据,需要从第一个数据开始找起,依次往后遍历,直到找到待查询的位置,故可能在查找某个元素时,时间复杂度达到O(N)
4.空间不需要提前指定大小,是动态申请的,根据需求动态的申请和删除内存空间,扩展方便,故空间的利用率较高 
5.任意位置插入元素和删除元素效率较高,时间复杂度为O(1) 
6.链表的空间是从堆中分配的
====链表的优点====
1.任意位置插入元素和删除元素的速度快,时间复杂度为O(1) 
2.内存利用率高,不会浪费内存 
3.链表的空间大小不固定,可以动态拓展

====链表的缺点====
随机访问效率低,时间复杂度为0(N)

centos7查看开机启用服务列表以及启用禁用相关服务
查看开机启动服务列表
systemctl list-unit-files
systemctl list-unit-files |grep php
加入启动
systemctl enable postfix
启动
systemctl start postfix
停止
systemctl stop postfix
禁用
systemctl disable postfix
状态
systemctl status postfix
windows和mac下安装java并配置路径
进入
https://www.oracle.com/technetwork/java/javase/downloads/index.html
下载对应的平台+版本的安装包

====WINDOWS平台下====== 公用JRE 不用安装

我的电脑--属性--高级系统设置 --环境变量
配置环境遍历
JAVA_HOME D:\Program Files\Java\jdk1.8.0_201
PATH 加入 D:\Program Files\Java\jdk1.8.0_201\bin
CLASSPATH .;D:\Program Files\Java\jdk1.8.0_201\lib



====MAC平台下====== 
查看java_home 
/usr/libexec/java_home -V
加入环境变量
vim /etc/profile
JAVA_HOME="/Library/Java/JavaVirtualMachines/jdk1.8.0_201.jdk/Contents/Home"
export JAVA_HOME
CLASS_PATH="$JAVA_HOME/lib"
PATH=".$PATH:$JAVA_HOME/bin"
执行
source /etc/profile

解决页面加载防盗链图片失败问题


在页面head标签内加入
<meta name="referrer" content="never">

referer的metedata属性可设置content属性值为以下集合:
1.never 
2.always 
3.origin
说明:
如果referer-policy的值为never:删除http head中的referer;
如果referer-policy的值为default:如果当前页面使用的是https协议,而正要加载资源使用的是普通的http协议,则将http header中额referer置为空;
如果referer-policy的值origin:只发送origin部分;
如果referer-policy的值为always:不改变http header中的referer的值;
举例
如果页面中包含了如下 meta 标签,所有从当前页面中发起的请求将不会携带 referer:<meta name="referrer" content="never">
如果页面中包含了如下 meta 标签,则从当前页面中发起的 http请求将只携带 origin 部分:<meta name="referrer" content="origin">

SpringBoot项目打包简记
项目目录 first-app-demo

模型层:model
持久层:persistence
表示层:web

把 jar 修改成 pom,默认是 jar
pom.xml(first-app-demo)

模型层:model
持久层:persistence
表示层:web
web 依赖于 persistence ,persistence 依赖于 model
web Controller ->UserRepository -> User


------------jar打包方式-------------

cd D:\JAVA_PROJECT\first-app-demo

在pom.xml(fisrt-app-demo)中加入 ,mainClass 复制接口 ,然后把下面这段话 剪贴 到 web 模块下的 pom.xml 里面
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
-----
<configuration>
<mainClass>com.imooc.firstappdemo.FirstAppDemoApplication</mainClass>
</configuration>
----
</plugin>
</plugins>
</build>

mvn -Dmaven.test.skip -U clean package

会显示如下::::
Building jar: D:\JAVA_PROJECT\first-app-demo\web\target\web-0.0.1-SNAPSHOT.jar

执行
cd web\target\
java -jar web-0.0.1-SNAPSHOT.jar 


-------------war打包方式-------------

在web pom.xml中加入下面这句话,在  <artifactId>web</artifactId> 之后
<!-- 将packaging 值(默认jar) 调整成 war -->
<packaging>war</packaging>

并在web/src/main/下新建 webapp/WEB-INF/web.xml 文件

cd D:\JAVA_PROJECT\first-app-demo //回到项目根目录
mvn -Dmaven.test.skip -U clean package
会显示如下::::
Building war: D:\JAVA_PROJECT\first-app-demo\web\target\web-0.0.1-SNAPSHOT.war
cd web\target\
java -jar web-0.0.1-SNAPSHOT.jar



-------------maven插件方式运行-------------
cd D:\JAVA_PROJECT\first-app-demo
cd web 
mvn -Dmaven.test.skip -U clean install
mvn spring-boot:run

---------------war打包方式并在tomcat下运行----------------------------------------
在web pom.xml中加入下面这句话,在  <artifactId>web</artifactId> 之后
<!-- 将packaging 值(默认jar) 调整成 war -->
<packaging>war</packaging>

并增加tomcat依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</dependency>

并在web/src/main/下新建 webapp/WEB-INF/web.xml 文件,不能为空
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0">
    <display-name>version</display-name>
</web-app>

修改启动文件,让其类集成 SpringBootServletInitializer,并重写configure方法

@SpringBootApplication
public class FirstAppDemoApplication extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(FirstAppDemoApplication.class);
}
public static void main(String[] args) {
SpringApplication.run(FirstAppDemoApplication.class, args);
}
}
cd D:\JAVA_PROJECT\first-app-demo //回到项目根目录
mvn -Dmaven.test.skip -U clean package
会显示如下::::
Building war: D:\JAVA_PROJECT\first-app-demo\web\target\web-0.0.1-SNAPSHOT.war
复制 web-0.0.1-SNAPSHOT.war 此文件到 tomcat/webapp下面
然后运行tomcat即可


优惠券
广告位-淘宝
最新微语