IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> PHP知识库 -> PDO超时参数研究 -> 正文阅读

[PHP知识库]PDO超时参数研究

一、简单介绍

当用PHP访问数据库时,常见的选择是 PDO和MySQLi,PDO和MySQLi都支持通过面向对象的形式提供API,其中MySQLi也提供了面向过程的API。MySQLi只支持MySQL,而PDO支持多种数据库,因此使用PDO可以不改代码,就讲后端存储的数据库进行替换。

PHP 数据对象 (PDO) 扩展为PHP访问数据库定义了一个轻量级的一致接口。还需要更具体驱动扩展,才能真正连接相应的数据库。
具体的驱动扩展列表如下

;extension=php_pdo_firebird.so
;extension=php_pdo_informix.so
;extension=php_pdo_mssql.so
;extension=php_pdo_mysql.so
;extension=php_pdo_oci.so
;extension=php_pdo_oci8.so
;extension=php_pdo_odbc.so
;extension=php_pdo_pgsql.so
;extension=php_pdo_sqlite.so

以 php_pdo_mysql.so 为例,就是用来连接mysql数据库的驱动。

执行 phpinfo(),pdo部分输出如下,可以看到这里PDO支持的驱动有sqlite, mysql,也就是该环境PDO目前支持连接sqlite, mysql这两种数据库。

PDO

PDO support => enabled
PDO drivers => sqlite, mysql

pdo_mysql

PDO Driver for MySQL => enabled
Client API version => mysqlnd 5.0.12-dev - 20150407 - $Id: b396954eeb2d1d9ed7902b8bae237b287f21ad9e $

Directive => Local Value => Master Value
pdo_mysql.default_socket => /tmp/mysql.sock => /tmp/mysql.sock

二、PDO::ATTR_TIMEOUT参数研究

PDO在创建对象的时候,可以通过 PDO::ATTR_TIMEOUT 参数设置超时时间,官方文档对这个参数的说明如下,

PDO::ATTR_TIMEOUT: 指定超时的秒数。并非所有驱动都支持此选项,这意味着驱动和驱动之间可能会有差异。比如,SQLite等待的时间达到此值后就放弃获取可写锁,但其他驱动可能会将此值解释为一个连接或读取超时的间隔。 需要 int 类型。

这个说明比较模糊,没有说明是连接超时,还是读写超时,只是说和具体驱动的实现有关。于是研究 php 7.1.2的源码,进行确认。
用 ATTR_TIMEOUT 关键字到 ext目录搜索,

vim pdo_dbh.c +255
driver = pdo_find_driver(data_source, colon - data_source);
vim pdo_dbh.c +356
driver->db_handle_factory(dbh, options)

vim pdo.c +185
db_handle_factory 方法是 pdo_driver_t 结构体的一个成员
搜索 grep pdo_driver_t -rn *,找到下面的结果
vim pdo_mysql/mysql_driver.c +805

pdo_driver_t pdo_mysql_driver = {
        PDO_DRIVER_HEADER(mysql),
        pdo_mysql_handle_factory
};

搜索 pdo_mysql_handle_factory 函数的定义 vim mysql_driver.c +540,
超时相关的代码如下

603         if (driver_options) {
604                 zend_long connect_timeout = pdo_attr_lval(driver_options, PDO_ATTR_TIMEOUT, 30);

631                 if (mysql_options(H->server, MYSQL_OPT_CONNECT_TIMEOUT, (const char *)&connect_timeout)) {
632                         pdo_mysql_error(dbh);
633                         goto cleanup;
634                 }

其中 pdo_attr_lval 函数的定义如下,也就是超时时间没有设置的话,默认为 30s

// vim pdo/php_pdo_driver.h +197
static inline zend_long pdo_attr_lval(zval *options, enum pdo_attribute_type option_name, zend_long defval)
{
        zval *v;

        if (options && (v = zend_hash_index_find(Z_ARRVAL_P(options), option_name))) {
                return zval_get_long(v);
        }
        return defval;
}

所以对于pdo_mysql驱动来说,结论如下:

1、PDO::ATTR_TIMEOUT设置的是连接超时时间
2、不设置超时时间的话,默认的连接超时时间是 30s

三、读写超时参数

数据库往往还有读/写超时时间,那么PDO是否可以设置读/写超时时间呢?

https://www.cnblogs.com/feng18/p/6523646.html

grep MYSQL_OPT_WRITE_TIMEOUT -rn *
查看以下代码 vim mysqlnd/mysqlnd_connection.c +1681

MYSQLND_METHOD(mysqlnd_conn_data, set_client_option)(MYSQLND_CONN_DATA * const conn,
                                                                                                enum_mysqlnd_client_option option,
                                                                                                const char * const value
                                                                                                )
{
        const size_t this_func = STRUCT_OFFSET(MYSQLND_CLASS_METHODS_TYPE(mysqlnd_conn_data), set_client_option);
        enum_func_status ret = PASS;
        DBG_ENTER("mysqlnd_conn_data::set_client_option");
        DBG_INF_FMT("conn=%llu option=%u", conn->thread_id, option);

        if (PASS != conn->m->local_tx_start(conn, this_func)) {
                goto end;
        }
        switch (option) {
#ifdef WHEN_SUPPORTED_BY_MYSQLI
                case MYSQL_OPT_READ_TIMEOUT:
                case MYSQL_OPT_WRITE_TIMEOUT:
#endif
                case MYSQLND_OPT_SSL_KEY:
                case MYSQLND_OPT_SSL_CERT:
                case MYSQLND_OPT_SSL_CA:
                case MYSQLND_OPT_SSL_CAPATH:
                case MYSQLND_OPT_SSL_CIPHER:
                case MYSQL_OPT_SSL_VERIFY_SERVER_CERT:
                case MYSQL_OPT_CONNECT_TIMEOUT:
                case MYSQLND_OPT_NET_READ_BUFFER_SIZE:
                        ret = conn->vio->data->m.set_client_option(conn->vio, option, value);
                       

看代码似乎是只有 mysqli才支持设置读/写超时时间,网上也有搜到文档,通过修改php源码,让pdo支持读/写超时,pdo应该是不支持这两个参数的。接下来通过一个程序,验证pdo支持读/写超时的效果。

测试方法:
预先登录数据库,
开启事务,
通过select for update锁定一条记录,
但是不commit,
然后通过接口向数据库发出请求,update此记录,此时请求会因为拿不到锁,而一直等待
开始时php-fpm 设定的请求终止时间为 30s
request_terminate_timeout = 30
所以请求达到30s后,会自动终止脚本运行,接口返回502,没有错误日志,

接下来,修改 request_terminate_timeout = 60
重启php-fpm

重复以上测试步骤,发现超过了 30s,接口请求仍然在正常等待,等到55s,执行commit动作后,请求可以正常返回

说明 数据库读写超时不止30s,目前完全是依赖php-fpm 设定的请求终止时间来结束请求

MYSQL_OPT_READ_TIMEOUT,
MYSQL_OPT_WRITE_TIMEOUT,
这两个常量是 mysqlnd 扩展定义的常量,
pdo_mysql 扩展没有引用这两个常量,
看pdo的文档,也没有搜到可以使用这两个常量,
目前基本上可以确定,pdo不支持设置读/写超时时间。

四、数据库处理

像上面这种,一个进程提交了sql,sql在等待数据库执行,然后进程突然被kill掉了,数据库会怎么对待sql?

  PHP知识库 最新文章
Laravel 下实现 Google 2fa 验证
UUCTF WP
DASCTF10月 web
XAMPP任意命令执行提升权限漏洞(CVE-2020-
[GYCTF2020]Easyphp
iwebsec靶场 代码执行关卡通关笔记
多个线程同步执行,多个线程依次执行,多个
php 没事记录下常用方法 (TP5.1)
php之jwt
2021-09-18
上一篇文章      下一篇文章      查看所有文章
加:2022-04-06 15:58:20  更:2022-04-06 15:59:19 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 6:00:05-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码