数据库的优化是我们web开发的重中之重,甚至很多时候我们其实是在为数据库编程。当然,用户的所有操作和行为都是以数据的形式存储的。其中,在创建数据库连接的过程中有没有可以优化的内容?答案当然是肯定的。Java等语言都有连接池设置,但是PHP在普通开发中是没有连接池这种东西的。涉及到多线程时往往会用到连接池的技术,所以PHP每次运行都会创建一个新的连接,那么这种情况下我们如何优化数据连接呢?什么是数据库连接持久化我们先来看看数据库连接持久化的定义。持久数据库连接是脚本完成运行时不会关闭的连接。收到持久连接请求时。PHP将检查是否已经存在相同的持久连接(之前打开的)。如果存在,则直接使用该连接;如果没有,将建立一个新的连接。所谓“同一”连接是指用相同的用户名和密码连接到同一台主机。对Web服务器如何工作和分配负载没有深入了解的读者可能会误解持久连接的作用。特别是,持久连接不提供通过同一连接建立“用户会话”的能力,也不提供有效建立事务的能力。事实上,严格来说,持久连接并没有提供任何非持久连接无法提供的特殊功能。这就是PHP中的连接持久性,但它也指出持久连接不提供任何非持久连接无法提供的特殊功能。这就很迷惑了,不是说这个解决方案可以提升性能吗?连接持久化有什么用?是的,从上面定义中指出的特殊功能来看,持久连接并没有带来新的或更高级的功能,但它最大的用处是提高效率,也就是性能会提高。当创建从WebServer到SQLServer的连接的开销很高时(比如需要很长时间,消耗大量的临时内存),持久连接会更高效。也就是说,当连接成本高的时候,创建数据库连接的成本会更大,当然时间也会更长。使用长连接后,每个子进程在其生命周期内只进行一次连接操作,而不是每处理一个页面就向SQLServer发起一次连接请求。也就是说,每个子进程都会与服务器建立自己独立的长连接。例如,如果有20个不同的子进程运行一个脚本来建立与SQL服务器的持久连接,那么实际上有20个不同的与SQL服务器的持久连接,每个进程一个。效率对比就不多说了,直接通过代码对比吧。首先,我们定义一个统计函数来返回当前的毫秒时间。另外,我们还需要准备数据的连接参数。functiongetmicrotime(){list($usec,$sec)=explode("",microtime());return((float)$usec+(float)$sec);}$db=['server'=>'localhost:3306','user'=>'root','password'=>'','数据库'=>'blog_test',];接下来,我们将使用普通的mysqli进行测试。$startTime=getmicrotime();for($i=0;$i<1000;$i++){$mysqli=newmysqli($db["服务器"],$db["用户"],$db["密码"],$db["数据库"]);//持久连接$mysqli->close();}echobcsub(getmicrotime(),$startTime,10),PHP_EOL;//6.5814000000循环创建数据库1000次在连接过程中,我们消耗了6秒多。接下来,我们使用持久连接的方式来创建这1000个数据库连接。只要在mysqli的$host参数前加一个p:即可。$startTime=getmicrotime();for($i=0;$i<1000;$i++){$mysqli=newmysqli('p:'.$db["server"],$db["user"],$db["密码"],$db["数据库"]);//持久连接$mysqli->close();}echobcsub(getmicrotime(),$startTime,10),PHP_EOL;//0.0965000000frommysqli从连接来看,效率提升非常明显。当然,PDO方式的数据库连接也提供了建立持久连接的属性。$startTime=getmicrotime();for($i=0;$i<1000;$i++){$pdo=newPDO("mysql:dbname={$db['database']};host={$db['server']}",$db['user'],$db['password']);}echobcsub(getmicrotime(),$startTime,10),PHP_EOL;//6.6171000000$startTime=getmicrotime();for($i=0;$i<1000;$i++){$pdo=newPDO("mysql:dbname={$db['database']};host={$db['server']}",$db['user'],$db['password'],[PDO::ATTR_PERSISTENT=>true]);//持久连接}echobcsub(getmicrotime(),$startTime,10),PHP_EOL;//0.0398000000PDO模式连接时,需要给一个PDO::ATTR_PERSISTENT参数,设置为true。这使得PDO建立的连接也是一个持久连接。注意,既然数据库的持久连接这么强大,为什么不默认这种持久连接形式,需要我们手动添加参数来实现呢?PHP的开发人员当然有顾虑。如果长连接的子进程数超过了数据库连接数的限制,系统就会出现一些问题。如果数据库有16个并发连接的限制,并且在会话繁忙的情况下,有17个线程尝试连接,那么一个线程将无法连接。如果此时,脚本中出现错误导致连接无法关闭(比如无限循环),那么这16个数据库连接将很快受到影响。同时,表锁和事务也需要注意。在长连接中使用数据表锁时,如果脚本由于某种原因未能释放数据表锁,后续使用同一连接的脚本将被持久阻塞,使用时需要重启httpd服务或数据库服务事务处理,如果脚本在事务阻塞发生之前结束,阻塞也会影响下一个使用相同连接的脚本。因此,在使用表锁和事务的情况下,最好不要使用持久数据库连接。幸运的是,持久连接和普通连接可以随时互换。我们定义了两种连接形式,在不同的情况下使用不同的连接来解决类似的问题。总而言之,事物总是有两个方面的。长连接一方面带来了效率的提升,但另一方面也可能会带来一些业务逻辑的问题,而这类问题在不了解长连接机制的情况下会非常困难。排除故障。因此,在日常开发中,我们必须在了解了相关功能特性后,选择合适的方法来完成所需的功能开发。测试代码:https://github.com/zhangyue0503/dev-blog/blob/master/php/202004/source/PHP%E4%B8%AD%E7%9A%84%E6%95%B0%E6%8D%AE%E5%BA%93%E8%BF%9E%E6%8E%A5%E6%8C%81%E4%B9%85%E5%8C%96.php参考文档:https://www.php.net/manual/zh/features.persistent-connections.php各媒体平台均可搜索【硬核项目经理】
