PHP

php针对mysql的orm: 一个轻量级的pdo操作类

字号+ 编辑: 秦朝 修订: 秦朝 来源: 原创 2017-11-24 10:56:45 我要说两句(1)

带简单连贯操作方法和redis缓存功能的pdo操作类php源码

ORM编写目的

php换姿势curd的老话题不断, 本orm是基于最近流行的swoole扩展而提出的解决方案, 韩天峰的swoole带给phper全新的编程思路, 原来php还可以常驻内存踢掉php-fpm支配环节, 甚至可以忽略nginx中间件搞起微服务。在nginx+php-fpm业务流程下, 正常的涉及php计算的用户访问处理流程是这样的:

  1. nginx的master进程发现用户访问并将请求信息移交给worker进程

  2. worker进程路由到index.php(如果你配置写的完全正确的情况下)

  3. location里面会命令nginx加载到nginx所夹带的fast-cgi模块

  4. fast-cgi告诉nginx我要监听本机9000端口, 有事情就转发到9000端口

  5. 刚刚好php-fpm也在监听9000端口

  6. php-fpm拿到传入的请求信号, 调起它自己的worker来处理

  7. php-fpm调来的worker处理完毕, 丢还给nginx

  8. nginx回传给访问用户。


swoole创始团认为, 要不要搞这么麻烦? 干脆省下一堆, 都一次性“预热”到内存里面来, 也不要php-fpm来调来调去, 如此, 就产生了常驻内存的php进程(或是一组master+worker)来处理特定的数据请求, 诸如此类的微服务模式。

关于断线重连

接着问题来了,常驻内存虽然看起来很美丽,可是Mysql的连接并不稳定, 韩天峰先生在swoole连接池、异步、断线重连(https://wiki.swoole.com/wiki/page/350.html) 这篇文章当中就有提到过MySQL连接不稳定的几个因素:

1、MySQL服务器一定时间内自动切断连接;

2、那种长期无查询占茅坑不拉屎的TCP连接会被MySQL切断回收;

3、主动用命令kill process杀死连接, 或者MySQL服务器重新启动

笔者隔一段时间会捕获到类似下面的错误

Error while sending STMT_PREPARE packet. PID=xxxxx
# 实际就是下方这个报错导致的, PDOException错误代码为HY000
server has gone away

phper需要发明出一套名叫“断线重连”的轮子, 或者想出一套路子维持连接生命周期, 来解决这个问题。有人说搞连接池来解决,还是没有解决到点子上, 连接池里面的连接也是一样触发数据库的周期断线机制好伐……

关于Hprose抛出异常崩掉业务流程之坑

MySQL配置文件my.cnf里面的interactive_timeout和wait_timeout(特别是wait_timeout)选项, 改到3600, 也就是1小时, 你网站不至于连续1个小时都没人看吧? 做个网页爬虫1小时之内主动爬一下你的页面, 比如你开了2个worker, 那么1小时以内你要连续点两次页面来重置访问连接计数器, 不要改太长时间, 容易产生大量僵尸连接。

interactive_timeout和wait_timeout默认值为8小时。

唠叨一下报错填坑过程:

  1. 笔者参考laravel 5最新的orm, 扒了一套方法is_break外加pdo精美的捕获, 做了断线重连, 但是会报Warning错误;

  2. 网上thinkphp5.x非正式版本也遇到过这方面问题, 运用了和laravel类似的解决方式, 同样, 用swoole在内存中持续使用的时候, Warning隔三差五该出的还是会遇到的。

以上问题, 得出结论, 只能选择发呆忽略。接下来的问题笔者项目用到yaf, 其定制的异常处理机制会捕获到hprose客户端抛出的io异常(EXCEPTION/FATAL ERROR)错误, 需要设法跳开这个错误, 否则yaf会把业务流程引向error处理机制上

曾尝试过在实例化pdo时将\PDO::ATTR_ERRMODE这个选项改成\PDO::ERRMODE_SILENT, 发现pdo实例调用prepare方法时, Warning会被包裹着hrpose的swoole发送到hporse客户端, 而客户端将Warning错误升级为异常级别抛出, 此时:

  1. 服务端改用捕获pdo实例中的errorInfo方法取得数组或者errorCode方法来拿错误代码判断是否闪断;

  2. 使用try catch捕获异常(显然没门);

  3. 用@符号掩盖掉prepare这一句的Warning错误

以上都会触发Warning的前提下,在hprose调用swoole服务端的时候随后跟上一句修改报错等级, 以下是实际代码:

$server = new Server('tcp://0.0.0.0:1314');
// 将E_WARNING屏蔽
$server->setErrorTypes(E_ERROR);

实测发现加或者不加这行配置, 结果都是一样的, 现有的Hprose还是抛异常。

以我半小时都没人点一下的小博客而言, 测试结果为: swoole自带的set方法有个提高worker数量, 可以用, 但Reactor必须等于1, 就解决报错的问题了。本人底层学的很菜, 原因未知, 稀里糊涂, 相关的参考文档 https://wiki.swoole.com/wiki/page/163.html

另外,仔细翻了下文档, 其中说到dns携带的参数里可以指定ATTR_PERSISTENT和ATTR_TIMEOUT两个属性, 经过实测, 未果, 该报警告还是报警告。另外, 据某些博客说ATTR_PERSISTENT在驱动层已经集成了连接池, 这可是个不错的消息(实际对这个问题还是没用)。

代码地址

http://www.wkwkk.com/article/aee0450ce1aff796f87af84777cf8683.html

使用说明

针对该ORM的使用文档请移步地址: http://www.wkwkk.com/article/258078a0ef7a23f89655ac669a52f8a9.html


可实例化pdo操作类的基础模型类

如此一来, 再写一个BasicModel实例化这个pdo操作类就可以当基础模型来用了, 这个地址 http://wkwkk.com/article/98a742396c78db8ed15c32649c70e9c4.html 是一个在Yaf中读写分离的代码例子:


解决爬虫类脚本内存不断上升不释放的问题

对于小内存主机来说,如果你不去切割爬虫脚本的工作, 当然在php单任务生命周期内, 内存的升高问题是很难得到缓解的。

如果你偏偏就是不喜欢切割任务,那么看pdo操作类里面有一句:

PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true,

将true改为false

关掉pdo缓冲操作来节省内存。


阅完此文,您的感想如何?
  • 鼓掌

    1

  • 鄙视

    1

  • 开心

    1

  • 愤怒

    1

  • 可怜

    1

1.转来的文章都会标好来源,如对来源资料存疑,请邮件声明;
2.本站标注原创的文章,转发时烦请注明来源;
3.如文章侵犯了您的版权,请通知本站,该文章将在24小时内移除。

相关课文
  • pecl安装swoole报错 error

  • shell_exec() has been disabled for security reasons 解决方法

  • PHP框架全部显得多余的4种原因

我要说说
网上宾友点评
IP223.20.25.*的嘉宾 说道: 666666666