我有一个存储过程(从现在开始的SP),它将数据插入数据库(SaveClient,见下文)。完成SP后,我将PHP页面重定向到列出条目的不同PHP页面(FetchObjectList,见下文)。在我重新加载/刷新页面之前,列表不会返回新创建的记录。
存储过程最后有COMMIT
,我在调用SP后关闭PHP代码中的数据库连接,并检查错误但没有出错。
页面本身返回200状态代码,这意味着它不会被缓存,因此也不能与浏览器相关。
当前的解决方法是PHP代码中的sleep(1)
但是当代码生效时我不知道它是否足够。我更倾向于让MySQL发出正确的结果集。
编辑:我正在使用PHP的MySQLi对象接口,可能有用。 ;)
我的devcomputer在Windows 7 x64上安装并运行了PHP 5.2.17,MySQL 5.0.51a(InnoDB)和Apache 2.2.17。
更新
在SaveClient的末尾添加了以下行CALL FetchObjectList('client_tbl', NULL, NULL, 1, 'client_tbl.name ASC', NULL, NULL);
。结果集在显示的结果集中没有新创建的客户端。
更新2
我尝试使用SQL_NO_CACHE
here,但无济于事。
我现在将直接在PHP中尝试相同的SQL,而不是调用SP。
更新3 - 20月9日
我已经尝试过任何合理的答案/评论我到目前为止没有任何运气。我今天尝试更新我的PHP和MySQL版本(因为我今天了解到实时服务器将在PHP 5.3.something和MySQL 5.1.something上运行)但是没有让它工作。我需要更新PHP以获得更新的php_mysqli.dll
/ libmysql.dll
,因为我得到的只支持高达5.0.51a并且可能存在我的问题,因为实际数据库中没有任何工作。我试过MySQL安装中的libmysql.dll
无济于事。
请注意,我还更改了我所包含的PHP代码,因为我实际上复制了一个调用user_tbl
而不是client_tbl
的错误代码,并且还简化了它(删除了多个查询)但仍然同样的结果。
我不知道赏金会发生什么,如果它回复给我,我会再次添加它。
存储过程SaveClient
DELIMITER //
DROP PROCEDURE IF EXISTS work.SaveClient//
CREATE PROCEDURE work.SaveClient(
IN ObjectID INT,
IN UserID INT,
IN ClientName VARCHAR(60),
IN VersionFrom DATETIME,
IN VersionTo DATETIME)
root:BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION ROLLBACK;
/*
Default values ---------------------------------------------------------------------------------------------------------
*/
# Used to block INSERT/UPDATEs
SET @DoChanges = TRUE;
SET @Fields = '*';
SET @Version = NULL;
SET @UserVersion = NULL;
SET @DateNow = NOW();
SET @VersionActive = CONCAT(
'( ( NOW() BETWEEN ',
'version_from AND ',
'version_to ) OR ( ',
'version_from < NOW() AND ',
'version_to IS NULL ) )'
);
IF VersionFrom IS NULL THEN
SET VersionFrom = @DateNow;
END IF;
/*
Search for client ------------------------------------------------------------------------------------------------------
*/
IF ObjectID IS NOT NULL THEN
SET @Client = CONCAT(
'SELECT version INTO @Version FROM client_tbl WHERE object_id = ',
ObjectID,
' AND ',
@VersionActive
);
PREPARE stmt FROM @Client;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
# Check if there are any changes
IF @Version IS NOT NULL THEN
SELECT name INTO @Name FROM client_tbl WHERE name = ClientName AND version = @Version;
IF @Name = ClientName THEN
SET @errorMsg = "Duplicate entry";
SET @errorCode = "S0000002";
SELECT @errorCode, @errorMsg;
LEAVE root;
END IF;
END IF;
END IF;
/*
Search for user ---------------------------------------------------------------------------------------------------------
*/
# Create this as a function
IF UserID IS NOT NULL THEN
SET @User = CONCAT(
'SELECT version INTO @UserVersion FROM user_tbl WHERE object_id = ',
UserID,
' AND ',
@VersionActive
);
PREPARE stmt FROM @User;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END IF;
IF @UserVersion IS NULL THEN
SET @errorMsg = "User is missing";
SET @errorCode = "U0000099";
SELECT @errorCode, @errorMsg;
LEAVE root;
END IF;
/*
Add the client ---------------------------------------------------------------------------------------------------------
*/
# Close the current version
IF @Version IS NOT NULL THEN
IF @DoChanges = TRUE THEN
CALL UpdateVersion(
ObjectID,
UserID,
@Version,
@DateNow,
'client_tbl'
);
SET @Version = @Version + 1;
END IF;
ELSE
SET @Version = 1;
END IF;
IF @DoChanges = TRUE THEN
IF ObjectID IS NULL THEN
INSERT INTO
object_tbl
(
object_class_id,
created,
created_by
)
VALUES(
2,
NOW(),
UserID
)
;
SET ObjectID = LAST_INSERT_ID();
END IF;
INSERT INTO
client_tbl
(
object_id,
version,
version_from,
version_to,
changed,
changed_by,
name
)
VALUES(
ObjectID,
@Version,
VersionFrom,
NULL,
@DateNow,
UserID,
ClientName
)
;
END IF;
COMMIT;
END //
DELIMITER ;
存储过程FetchObjectList
DELIMITER //
DROP PROCEDURE IF EXISTS work.FetchObjectList//
CREATE PROCEDURE work.FetchObjectList(
IN ObjectType VARCHAR(60),
IN ObjectSubType VARCHAR(60),
IN ObjectSubID INT,
IN IsActive INT,
IN OrderBy VARCHAR(100),
IN SetStart INT,
IN MaxResults INT)
root:BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION ROLLBACK;
# Allow the "JSON" output be a max of 8kb
SET GLOBAL group_concat_max_len = 8096;
/*
Default values ---------------------------------------------------------------------------------------------------------
*/
SET @Fields = '*';
SET @VersionWhere = '1'; # Get everything
SET @Special = '';
SET @OrderBy = '';
SET @SetStart = '';
SET @MaxResults = '';
SET @JoinIn = '';
IF IsActive = 1 THEN
SET @VersionWhere = CONCAT(
'( NOW() BETWEEN ',
ObjectType,
'.version_from AND ',
ObjectType,
'.version_to OR ( ',
ObjectType,
'.version_from < NOW() AND ',
ObjectType,
'.version_to IS NULL ) )'
);
END IF;
IF OrderBy != '' THEN
SET @OrderBy = CONCAT(
'ORDER BY ',
OrderBy
);
END IF;
/*
Specials for each type -------------------------------------------------------------------------------------------------
*/
/*
- Clients ------------
*/
IF ObjectType = 'client_tbl' THEN
SET @Fields = '
*,
client_tbl.object_id AS object_id,
(
SELECT
COUNT(*) AS Total
FROM
client_user_privilege_tbl cup
WHERE
cup.client_id = client_tbl.object_id
) AS usercount
';
END IF;
/*
- Configuration ------------
*/
IF ObjectType = 'configuration_tbl' THEN
SET @Fields = '
*
';
END IF;
/*
Add upp the query to run -----------------------------------------------------------------------------------------------
*/
SET @Query = CONCAT(
'SELECT ',
@Fields,
' FROM ',
ObjectType,
' ',
@JoinIn,
' WHERE ',
@VersionWhere,
' ',
@Special,
@OrderBy
);
PREPARE stmt FROM @Query;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
COMMIT;
END //
DELIMITER ;
PHP CODE SNIPPET(9月20日更新)
$query = "CALL FetchObjectList('client_tbl', NULL, NULL, 1, NULL, NULL, NULL)";
addTrace($query);
$rs = $db->query($query);
if( $rs ) {
addTrace('Query done -> Results: ' . $rs->num_rows);
while($r = $rs->fetch_assoc()){
$fetchArray[] = $r;
}
$count = $rs->num_rows;
$rs->close();
$db->next_result();
} else {
addTrace('Query failed -> ' . $db->error);
flushTrace();
exit;
}
答案 0 :(得分:1)
因为它是一个相当老化的mysql版本,所以这不会让我感到惊讶,因为这将与bug有关,但有一件事我想 - 你想知道的是,如果这可以通过不使用交易完全。 (例如autocommit = on)。
对于那个版本5.0,我还会检查查询缓存并一起禁用它而不是每个查询(参见SHOW VARIABLES LIKE'has_query_cache'; SET GLOBAL query_cache_size = 0;)。这至少会消除那些在这个问题中发挥作用的人,重现(或尝试)问题,看看是否有任何改变。如果没有,我会开始搜索特定的错误,特别是当查询缓存被禁用时,它仍然在不使用事务的情况下执行此操作。
我验证了对5.0 mysql(innodb)的支持。
在my.cnf中专门设置这些选项,最重要的是。他们很好地解释了那些做了什么。
请参阅http://dev.mysql.com/doc/refman/5.0/en/innodb-parameters.html#sysvar_innodb_flush_log_at_trx_commit
答案 1 :(得分:1)
mysql_query的问题是它不支持多个结果集。这正是您的存储过程所做的 - 它们往往返回多个结果集。无论何时调用SP,退出状态都会在(空)结果集中秘密携带。如果使用自己的过程输出添加它,则PHP检索代码将忽略查询中的某些结果集。当您尝试运行另一个查询时,挂起的结果集仍将在缓冲区中。