Mic*_*ael 4 php mysql centos fetch
CentOS 6.4 PHP 5.3.3 MySQL 5.1.69 x86_64
mysql_stmt::fetch()
Run Code Online (Sandbox Code Playgroud)
当使用预准备语句执行fetch时,PHP会产生错误:PHP致命错误:允许的内存大小为134217728字节耗尽(尝试分配4294967296字节).
当用于创建临时表的SELECT语句中包含的变量未设置时,无论是否在调用存储过程之前在环境中设置该变量,都会发生这种情况.必须在存储过程中设置变量.当SELECT语句用于将临时表中的数据返回给PHP,并且PHP使用mysql_stmt :: fetch()来访问数据时,PHP会生成上述致命错误.
MySQL代码:
DELIMITER $$
CREATE PROCEDURE test_sp()
BEGIN
# uncomment below line, and PHP call to mysqli_stmt::fetch() works
# SET @status = 1;
# remove tmp table
DROP TABLE IF EXISTS tmp_table;
# CREATE TEMPORARY TABLE
CREATE TEMPORARY TABLE tmp_table
SELECT @status AS status;
SELECT * FROM tmp_table;
END $$
DELIMITER ;
Run Code Online (Sandbox Code Playgroud)
PHP代码:
// obtain MySQL login info
require_once(MYSQLOBJ);
// initialize status
$status = "";
$db = new mysqli(
DB_HOST,
DB_USER,
DB_PASSWORD,
DB_NAME
);
$query = "CALL test_sp";
$stmt = $db->prepare($query);
$stmt->execute();
$stmt->bind_result( $status );
$stmt->store_result();
$stmt->fetch(); // PHP FATAL ERROR OCCURS HERE
$stmt->free_result();
$db->close();
print "<p>status = $status</p>\n";
Run Code Online (Sandbox Code Playgroud)
你会发现只有在@status是NULL或字符串时才会发生这种情况.
问题是双重的:
与局部变量不同,MySQL 用户变量支持一组非常有限的数据类型:
可以从一组有限的数据类型为用户变量分配值:整数,十进制,浮点,二进制或非二进制字符串或
NULL值.
该文件没有提到的是,实际的数据类型使用的分别为BIGINT,DECIMAL(65,30),DOUBLE,LONGBLOB,LONGTEXT和LONGBLOB.关于最后一本,手册至少解释了:
如果引用尚未初始化的变量,则其值为NULL且字符串类型.
存储前三种这些数据类型(即整数,十进制和浮点值)分别需要8,30和8个字节.其他数据类型(即字符串和NULL值)需要(最多)4千兆字节的存储空间.
由于您使用的是v5.4.0之前的PHP版本,因此默认的MySQL驱动程序是libmysql,在数据绑定时只能从服务器获得列类型元数据 - 因此MySQLi尝试分配足够的内存来保存每个可能的值(甚至如果最终不需要完整的缓冲区); 因此NULL- 字符串值的用户变量,最大可能的大小为4GiB,导致PHP超过其默认内存限制(自PHP v5.2.0起为128MiB).
您的选择包括:
覆盖表定义中的列数据类型:
DROP TEMPORARY TABLE IF EXISTS tmp_table;
CREATE TEMPORARY TABLE tmp_table (
status VARCHAR(2)
) SELECT @status AS status;
Run Code Online (Sandbox Code Playgroud)将用户变量显式地转换为更具体的数据类型:
DROP TEMPORARY TABLE IF EXISTS tmp_table;
CREATE TEMPORARY TABLE tmp_table
SELECT CAST(@status AS CHAR(2)) AS status;
Run Code Online (Sandbox Code Playgroud)使用使用显式数据类型声明的局部变量:
DECLARE status VARCHAR(2) DEFAULT @status;
DROP TEMPORARY TABLE IF EXISTS tmp_table;
CREATE TEMPORARY TABLE tmp_table
SELECT status;
Run Code Online (Sandbox Code Playgroud)通过调用mysqli_stmt::store_result() before来 解决这个问题mysqli_stmt::bind_result(),导致结果集存储在libmysql中(在PHP的内存限制之外),然后PHP只会在获取记录时分配保存记录所需的实际内存:
$stmt->execute();
$stmt->store_result();
$stmt->bind_result( $status );
$stmt->fetch();
Run Code Online (Sandbox Code Playgroud)提高PHP的内存限制,以便它可以容纳4GiB缓冲区的分配(尽管应该知道这样做会对硬件资源产生影响) - 例如,完全消除内存限制(尽管意识到潜在的负面影响)从这样做,例如从真正的内存泄漏):
ini_set('memory_limit', '-1');
Run Code Online (Sandbox Code Playgroud)重新编译PHP,配置为使用本机mysqlnd驱动程序(自v5.3.0以来包含在PHP中,但在PHP v5.4.0之前未配置为默认值)而不是libmysql:
./configure --with-mysqli=mysqlnd
Run Code Online (Sandbox Code Playgroud)升级到PHP v5.4.0或更高版本,以便默认使用mysqlnd.
| 归档时间: |
|
| 查看次数: |
1540 次 |
| 最近记录: |