PHP的PDO遇到MySql has gone away的解决方法 |
发布: 2014-01-27 18:17 |
在MySQL特定的数据库参数配置的情况下,在一个超时的连接上调用任意的mysql函数, 会导致PHP的PDO扩展报"MySQL has gone away"警告,导致程序无法继续执行。 在使用多种PHP层的解决方案后,依旧无法避免这一问题的出现。 原因在于PDO架构采用了连接对象缓存机制,在使用相同的dsn串连接数据库时, PDO会从连接池对象中取出有相同dsn串的连接,问题就出在这个地方。 当该连接出现了"MySQL has gone away"之后,PDO并不知道这一情况, PDO连接对象仍旧在PDO的连接池中。 下次即使在PHP层检测到这一问题,并重试连接,PDO却返回之前报了错的连接。 问题的原因查找到了,接下来就是寻找解决方法。 由于PDO没有提供关闭连接的方法,而是依靠PHP本身的引用计数与垃圾回收机制关闭连接, 在大多数情况下这都没有问题,但这时候这种机制就略显无力了。 经过多次实践修改测试,总结出来以下两种方式, 第一种,修改dsn串后再次连接,这样能得到一个新的PDO连接,并存储到PDO连接池中。 这种情况却有个问题,原有出问题的连接并不会自动释放, 并且还有MySQL的TCP连接存在,会消耗客户端PHP进程与服务器MySQL服务进程的资源。 好处是不需要做大的修改,只需要在PHP加个检测函数即可。 第二种,修改PDO扩展,添加一个PDO方法,把当前对象使用的连接对象从连接池中删除, 并强制销毁当前的PDO对象。 这种好处是修正的比较彻底,但需要修改PDO扩展的C代码。 现在把第二种方法对PDO的补丁代码放上来,以供参考, php-5.5.8-PDO_destroy.patch: [code type="diff"] diff --git a/ext/pdo/pdo_dbh.c b/ext/pdo/pdo_dbh.c index ac8d29a..c615aa5 100644 --- a/ext/pdo/pdo_dbh.c +++ b/ext/pdo/pdo_dbh.c @@ -425,6 +425,43 @@ options: } /* }}} */ +static void dbh_free(pdo_dbh_t *dbh TSRMLS_DC); +/* {{{ proto Boolean PDO::destroy() + Force destory current PDO Object. Should only be used when got "Mysql has gone away" message. */ +static PHP_METHOD(PDO, destroy) +{ + pdo_dbh_t *dbh = NULL; + char *hashkey = NULL; + zend_rsrc_list_entry *le = NULL; + int rc = 0; + zval *object = getThis(); + + dbh = (pdo_dbh_t *)zend_object_store_get_object(object TSRMLS_CC); + if (dbh == NULL) { + RETURN_TRUE; + } + + if (dbh->is_persistent && dbh->persistent_id != NULL) { + // this is persistent PDO's DSN + hashkey = dbh->persistent_id; + rc = zend_hash_find(&EG(persistent_list), hashkey, dbh->persistent_id_len, (void*)&le); + if (rc == SUCCESS) { + rc = zend_hash_del(&EG(persistent_list), hashkey, dbh->persistent_id_len); + if (rc != SUCCESS) { + } + assert(le->ptr == dbh); + php_pdo_pdbh_dtor(le); + le == NULL; + } + } + + zval_dtor(object); + ZVAL_NULL(object); + + RETURN_TRUE; +} +/* }}} */ + static zval *pdo_stmt_instantiate(pdo_dbh_t *dbh, zval *object, zend_class_entry *dbstmt_ce, zval *ctor_args TSRMLS_DC) /* {{{ */ { if (ctor_args) { @@ -1266,6 +1303,7 @@ ZEND_END_ARG_INFO() const zend_function_entry pdo_dbh_functions[] = { ZEND_MALIAS(PDO, __construct, dbh_constructor, arginfo_pdo___construct, ZEND_ACC_PUBLIC) + PHP_ME(PDO, destroy, arginfo_pdo__void, ZEND_ACC_PUBLIC) PHP_ME(PDO, prepare, arginfo_pdo_prepare, ZEND_ACC_PUBLIC) PHP_ME(PDO, beginTransaction, arginfo_pdo__void, ZEND_ACC_PUBLIC) PHP_ME(PDO, commit, arginfo_pdo__void, ZEND_ACC_PUBLIC) [/code] 这样使用PDO的PHP框架就能比较完善的使用MySQL了。 这段补丁代码针对php-5.5.8版本,请在打补丁时使用相应的php源代码包。 如需要使用这个补丁,请先仔细测试。 目前刚写完代码,做了简单的测试,还没有在正式项目中应用。 |
原文: http://qtchina.tk/?q=node/785 |
Powered by zexport
|