PHP如何封装pdo
这篇文章主要介绍了PHP如何封装pdo,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。
一、前言
最近需要写脚本来实现崩溃日志的入库,不出所料又是脱离于框架的,那么行吧,咱们只能自己封装数据库相关操作了。这里选择了封装pdo
操作数据库相关。
二、为什么选择pdo
众所周知的,php
在早期的时候是带有mysql
扩展的,但是后来由于过于古老缺失了mysql
的新特性,因此主键没落。
从php5
开始,更建议大家使用mysqli
扩展,这个是mysql
扩展的增强版,是一个面向对象的MySQL
接口,更容易使用。缺点是只能操作mysql
,不够强大。
还有就是pdo
扩展了,这个是最丰富的的一个扩展,支持多种数据库,重要的是,在安全上是比其他两种扩展都要强的,通过使用prepared
预处理更是有效的防止sql
注入。因此,博主这里选择了封装pdo
相关的操作。
三、pdo的长连接
1、什么是pdo的长连接
长连接顾名思义就是一直保持连接,相对于平时的短连接,每次请求都会重新创建链接来说,长连接可以有效的减少创建的过程,可以更好的节省性能。
在操作上是在连接数据库的时候,多加一个参数:
$pdo = new PDO($dsn, $username, $passwd, [PDO::ATTR_PERSISTENT => true]);
后面的PDO::ATTR_PERSISTENT => true
就是开启长连接的方法。
2、长连接对nginx无效吗
博主在搜索长连接相关知识的时候,看到一篇文章,结论是长连接仅适用于apache,不适用于nginx
,这是真的吗?
参考博文地址:https://www.cnblogs.com/wpjamer/articles/7106389.html
大致结论是:长连接更多的是针对于apache
的,因为apache
维护一个进程池,开启了apache mpm
功能之后,apache
会默认维持一个进程池,mysql
长连接之后的连接,并没有作为socet
连接关闭,而是作为一个不释放的东西,放进了进程池/线程池里面去。
而对于nginx
来说,长连接是无效的,脚本执行结束则释放资源?
3、php-fpm下的长连接测试
这里前辈已经测试过了,咱们给出前辈的地址,大家有兴趣的可以看看
参考博文地址:https://hacpai.com/article/1526490593632
结论:
事实证明php-fpm
是可以实现长连接的,只是如果该进程空闲的话,会造成资源浪费。
php-fpm
的配置文件可以考虑设置pm.max_requests = 1000
,代表每一个子进程的最大请求服务数量,如果超过了这个值,该子进程会被自动重启。
比如max_requests
这个参数,如果设置很大的话,那这个子进程要运行很多次才会重启,假如这个请求发生了错误或者内存泄漏,那么这个值设置很大是不合适的。但如果请求没有问题,这个值设置小的话就会频繁的重启,这样也会碰到不少502
的问题,所以要仁者见仁,智者见智的设置了,这里初始化设置1000
,如果测试没有内存泄漏等问题,可以再大一些。
4、长连接对事务的影响
参考博文地址:https://www.zhihu.com/question/62603122
总结: 如果业务并发比较大且带有事务,不建议使用长连接的方式。
5、总结
博主在不断的搜索中,发现长连接要发挥出最佳性能始终是避不开连接池这点的,而php恰恰又不能很好的实现连接池,这点确实是有点小遗憾。
整体来说在php
中是暂时无法配置和mysql
的完美连接池的,在业务比较复杂的地方,还是谨慎试用长连接,每个连接都是1个线程,会造成大量的资源浪费。
如果是某些业务需要持续的数据库操作,比如提交日志接口等,那么是可以考虑打开长连接的,记得设置max_requests
来定量关闭php-fpm
连接,fpm
关闭之后也会自动释放mysql
的连接。
还有pm.max_spare_servers
设置服务器空闲时最大php-fpm
进程数量。
例如: pm.max_spare_servers = 25
如果空闲时,会检查进程数,多于25
个了,就会关闭几个,达到25
个的状态。
擅长swoole
的同学,可以参考这篇文章:
基于swoole扩展实现真正的PHP数据库连接池
四、pdo部分demo的封装
首先这部分博主是参考了一个网友的封装,github
地址如下:
https://github.com/nadirvishun/php-pdo-class
这个网友基本的增删改查都封装好了,而且都有参数预处理,安全性还是可以的。不过既然作为一个基准的类,还是缺少一些东西。
1、断线重连机制
例如重连函数:
/** * @params:重连函数,上限3次 * @date:2020/3/18 * @time:17:03 */ public function customConnect() { try { $this->pdo = new PDO($this->config['dsn'], $this->config['username'], $this->config['password'], $this->config['params']); $this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); //需要将错误处理模式变成异常模式 return true; } catch (Exception $e) { if (stripos($e->getMessage(), 'MySQL server has gone away') !== false || stripos($e->getMessage(),' bytes failed with errno=10053') !==false) { $this->close(); $this->tryNums++; if ($this->tryNums > 3) { return false; } self::customConnect(); } else { $this->throw_exception($e->getMessage()); return false; } } }
2、转化php warnings为try…catch可捕获的错误
这步原因是长连接会频繁的造成mysql gone away
错误,而这个错误是php
的warnings
级别错误,try..catch
根本就捕获不到,所以博主这里自定义错误处理函数来处理。
这部分是转化php
的warnings
错误为try..catch
可以捕获的error
错误,关于php
的报错机制以及错误处理这块,咱们下篇再讨论。
//自定义warnings处理函数set_error_handler('customException');//拿到warnngs错误之后,转化为error错误抛出,这样就可以被try..catch捕获function customException( $error_no, $error_msg, $error_file, $error_line){ throw new \Exception($error_msg,0,null); //throw new \Exception($error_msg);}
3、析构方法回收资源
/** * destruct 关闭数据库连接 */ public function destruct() { $this->pdo = null; }
4、query的时候ping一下
public function query($sql = null, $param = null) { //检测连接是否活跃 $this->pdo_ping(); //判断之前是否有结果集 if (!empty($this->PDOStatement)) { $this->free(); } xxxxxxxxxx }
感谢你能够认真阅读完这篇文章,希望小编分享的"PHP如何封装pdo"这篇文章对大家有帮助,同时也希望大家多多支持,关注行业资讯频道,更多相关知识等着你来学习!