数据库的长连接和短链接

什么是长连接和短链接?

顾名思义,长连接相对短链接,长时间保持客户端和服务端的链接状态
短连接: 连接-》数据传输-》关闭连接;
长连接:连接-》数据传输-》保持连接-》数据传输-》保持连接-》…………-》关闭连接;
当然由于php没有连接池的概念,长连接也是有个时间限度的,对应的是数据库中的wait_timeout(默认是8小时),在一段时间没有操作数据库后,数据库会断掉这个连接。
PS:如何保持类似的永久连接呢,可以通过类似于socket通信中的心跳机制,不断的发送心跳包,保持和数据的连接。(因为数据库的timeout计时会在每次数据库访问重新开始计时)

分别在什么情况下使用?

1.长连接较短链接并没有什么特殊功能,唯一的是效率
当webserver连接sql(overhead高的原因有很多,比如数据库种类,数据库服务,服务器负载。。)的耗费较高时候,持久连接因为没有重新建立连接所以效率会更高。
2.有利也有弊,由于数据库连接数是有限的,比如数据库连接设置为100个,而apache访问最大数为200个时,当超过100个请求所有的请求都取访问数据库,如果使用长连接,之前的100个没有被释放掉的话,接下来的100个都会无法连接数据库,直到之前的数据库连接被复用或者释放,所以当并发访问量很大的时候就要考虑下是否采用长连接的方式了(前100个由于长连接可能是被占用状态,也可能是和后100个所请求的数据库不一致,导致无法被复用)

php的几个运行模式下的长连接

1.cgi,php用作单独的语言解释器,php 会为向 web 服务器提出的每个 PHP 页面请求生成并结束一个 PHP解释器线程。由于该线程会随每个请求的结束而结束,因此任何在这个线程中利用的任何资源(例如指向SQL 数据库服务器的连接)都会随线程的结束而关闭。在这种情况下,使用持久连接和非持久连接没有任何区别——因为PHP脚本本身的执行不是持久的。
2.通常(我们系统),php用作web服务的一个模块,apache会加载php模块,一个请求过来,通常有父子两个进程协调处理的,子进程通常用作处理web页面的生成,父进程通常用于数据的写入,而数据库连接是建立在父进程里的,所以当子进程关闭的时候,并不会影响长连接的重用
3.与cgi类似,无法使用长连接

具体使用,测试

mysql_connect 短链接
mysql_pconnect 长连接
1.对于一些常驻进程,为什么不能使用this->load->model的方式去访问数据库
第一次连接数据库是可以访问的,但由于这个进程长时间没有访问数据库,超过了数据库设置的wait_timeout,数据库自动断开了此连接,下次常驻进程监听到消息,再去操作数据库的时候,就会报错。

解决方案:
可以通过自己手动关闭数据库连接,从而下次监听消息再次主动连接数据库
采用pconnect方式,并定时向数据库发送数据,保持数据库永久连接

2.测试后,mysql数据库连接的消耗并不是很大,所以绝大部分情况可以不使用长连接,避免产生数据库连接过多,因为当数据库连接快满的时候,产生新的连接的消耗,会明显增加。

js中==运算

js类型的科普

1.js的值可以分为2种类型,基本类型和对象类型
2.基本类型包括:Undefined、Null、Boolean、Number和String等五种
3.其中Undefined类型和Null类型的都只有一个值,即undefined和null;Boolean类型有两个值:true和false;Number类型的值有很多很多;String类型的值理论上有无数个

类型转换图
类型转换图
ps:N表示tonumber转化为数字比较,P表示转为基本类型比较

多情况比较
一、有和无

1.如图所示,很显然,左边表示的都是确定的,有和非空的,而右侧就是不确定的,无,或者空的,很显然两者==作比较是false的

二、空和空

1.undefined和null是比较难以区分的点
首先我们看下两者的类型

alert(typeof undefined); //output "undefined"
alert(typeof null); //output "object"
前者很容易理解undefined的类型是undefined
后者你会想为什么null的类型是object有点无语,看别人解释是说这是一个最初设计的问题
alert(null == undefined); //output "true"
为什么会是true呢,null表示不存在对象,该出不应该有值
而undefined是该处缺少值,没有赋值
那如何区分两者呢(1.===;2.根据类型比较)
三、真与假

Boolean类型的值,与其他值作比较的时候,会转化为1和0

四、字符的序列

string和number分在一起是因为它们都是字符的序列,数字可以当做一种特殊的字符串
字符串和数字作比较的时候,会把字符串转化为数字的形式,看是否是一个合法的数字比如 123->123;123abc->NaN;\r\n\t123\v\f->0;

五、对象与基本类型

概括一下,对象是各种属性的集合(而属性又可以是对象),所以对象是复杂度是无限制的
而一般我们使用toString来得到关于对象的文字描述(通常是字符串);用valueOf获取对象的原始值;
根据图1,当一个对象与一个非对象比较时,需要将对象转化为原始类型;
var str = new String('hello,world');
console.log(typeof str.toString()); //string
console.log(typeof str.valueOf());//number

六、自身比较

基本类型的比较,如果2个值相同,则为true,而对象比较特殊,只有地址相同才相等。当比较两个引用值时,比较的是两个引用地址,看它们引用的原值是否为同一个副本,而不是比较它们的原值字节是否相等。

数据库索引浅析

数据库索引

众所周知,索引是用来提高sql语句的查询效率的,那么索引到底是什么,我们该在什么时候建立索引,该如何取建立一个好的索引呢?

索引的原理

索引是一种数据结构,来看一下几个最基本的算法,比如我要查找一个id = 8888的用户,
select * from users where id=8888 limit 1;
首先想到的就是顺序查找,直到查到一条id为1 的元素为止,显而易见,这个算法的复杂度是O(n),是很糟糕的,理论上当n越大,开销越大。进而想到有些比较好的算法,二叉树,二分查找,但是都是有要求的,二叉树只能针对二叉树的数据结构起作用,二分查找也只能对有序的数据结构起作用,而数据库本身可以维护着一套符合特定算法的数据结构,可以用某种方式指向数据的数据结构,而我们使用的mysql采用的是B+树的方式建立所索引的。

a4a89204-44ec-38f0-a011-dad4f05acfdf
如图所示,是一棵高度为2的B+树,也可以很清晰的看到其特点
1.所有的记录都存放在叶子节点
2.所有的数据都按顺序排列(到最后通过二分查找获取数据)
3.叶子结点通过双向链起来,便于定位插入新的叶子结点
为什么说它优秀呢?通常数据库索引的消耗来源于磁盘io,而B+树,一个叶子节点对应着一个页,理论上,只需要读取m次(树的高度)磁盘,就可以得到数据所在节点

当产生一个新的元素,存在两种情况
1.插入所在页的叶子结点没满,直接插入
2.当叶子结点已满,会将此叶子结点一分为二,在父节点增加一个新的结点,因此这种方式不会影响兄弟结点

索引的类型

1.普通索引
正常的索引,没有限制
2.唯一索引
与普通索引类似,不同的就是:索引列的值必须唯一,如果是组合索引,则列值的组合必须唯一,创建方法和普通索引类似。
坑:如果一开始没有想好该字段建唯一索引后,由于表中已经存储了大量的数据,这时候就需要考虑去除重复项的事情了,而唯一索引有条语句
alert ignore table wx_fans add unique index(openid)是可以帮你省却很多操作的
3.全文索引
与普通索引不同,适合于大字段处理,举个例子,搜索一段文字,你不需要把全文都输入查询,只需要输入关键字
4.组合索引
较为复杂点,多经常有多个限制条件的sql语句适用,比如搜索来源为4,访问途径是2的用户
select user_id from users where from=4 and mtype=2 limit 100;
这时候可以建立 (from,mtype)的组合索引,比2个索引分开建立更有效率,但需要注意的是mysql有最左前缀的组合,所以只有from,mtype或者from查询的时候才能使用索引,而单mtype是无法享受的

什么情况建立索引?

1.对经常使用where查询的字段设置索引
2.数据库不要出现null值,因为索引是无法检索null值所在的列的
3.短索引(没用过),意思就是去某个字段的前几个字符建立索引
4.对数据量很大,但是重复值很多的不要去建立索引
5.索引的数据类型最好是简单而又小的,比如int型

工厂模式在实际中的应用

前言:为什么要使用设计模式?
设计模式并不是生来就有的,也是前人大量编码,最后总结出来的一套代码结构设计经验,根本目的也是为了增加代码的复用性和可维护性。
顺便说一下设计模式很看重一个原则->开闭原则,会在下面的示例中得到体现!简单的来说就是说对扩展开放,对修改关闭。

工厂模式
工厂模式是一种实例化对象的模式,是用工厂方法代替new操作的一种方式
工厂模式根据抽象的程度,可以分为简单工厂模式,工厂方法模式,抽象工厂模式。
Ps:对于一些功能相似的类,我们通常会提供一个抽象接口,把公共方法暴露出来,供调用者实现具体的逻辑。
示例讲解

以保险为例

1.简单工厂模式
由一个工厂类根据传入的参数决定创建哪一种产品的类,其实属于一种比较自然的再封装,我们通常也会在代码设计中不经意的使用

interface Create_product {
    public function getProducts();
}
//xyz的产品类
class Product implements Create_product
{
    public fucntion getProducts()
    {
        //todo get products by api
        echo 'get products successfully';
    }
}
//anlian的产品类
class Product implements Creat_product
{
     public fucntion getProducts()
    {
        //todo get products by api
        echo 'get products successfully';
    }
}
class Simple_facrtory {
    public static function createProduct($supp_name)
    {
        if ($supp_name=='Xyz') {
            return new  Xyz\Product;
        }
        if ($supp_name=='Anlian') {
            return new Anlian\Product;
        }
    }
}
$product = Simple_factory::createProduct('Xyz');
$product->getProducts();

优点:客户端免除了具体产品对象的创建,统一使用工厂去创建对象
缺点:违背了开闭原则,当需要有新的产品的时候,会在工厂类的基础上修改,很容易引发错误。

2.工厂方法模式
对简单工厂模式进行了抽象,有一个简单抽象工厂类负责制定以下规范,一般在这种模式中,工厂类会与某个具体的产品类一一对应。

//抽象产品类的方法
interface Create_product {
    public function getProducts();
}
//xyz的产品类
class Product implements Create_product
{
    public fucntion getProducts()
    {
        //todo get products by api
        echo 'get products successfully';
    }
}
//anlian的产品类
class Product implements Creat_product
{
     public fucntion getProducts()
    {
        //todo get products by api
        echo 'get products successfully';
    }
}
//将对象的创建抽象成一个接口
interface Create{
    public function product();
}
class FactoryXyz implements Create{
    public function product()
    {
        return new Xyz\Product;
    }
}
class FactoryAnlian implements Create{
    public function product()
    {
        return new Anlian\Product
    }
}
$factory = new FactoryAnlian();
$product = $factory->product();

优点:实现了开闭原则,对于新增的产品,只需要新增对应的产品类和工厂类,不需要对已有代码的修改,降低修改的风险
缺点:对于不同种类的产品,表示无能为力

3.抽象工厂模式
先举个例子,通过上面2个示例,我们制造这个产品了,但是我们有产品后,又需要去搞订单了,是不是又要创建另外的一个工厂类专门来处理订单呢?显然是不合适的,这时候,我们就会想,是不是可以把相关联的产品(产品和订单)放到一个工厂里,也就没必要再新开一个工厂了!

interface Create{
    public function product();
    public function order();
}
class FactoryXyz implements Create{
    public function product()
    {
        return new Xyz\Product;
    }
    public function order()
    {
        return new Xyz\Order;
    }
}
class FactoryAnlian implements Create{
    public function product()
    {
        return new Anlian\Product;
    }
    public function order()
    {
        return new Anlian\Order;
    }
}
$factory = new FactoryXyz();
$product = $factory->product();

优点:抽象工厂模式,核心在于'一系列', 单个工厂可以生产多个相关的产品。便于在业务中切换工厂。
缺点:显而易见,当出现新的产品的时候,改动开销就很大了,需要在每个工厂类中都加入对应的产品。比如说新增了一个用户,那么就需要在这每个工厂里都加一个用户的实现了,也就是无法支持新增产品,但可以支持多个不同的工厂!

总结:这三种模式并不是说哪个一定好,具体的使用要根据对应的环境来决定的!