由于地理位置或互联网提供商问题,某些用户在使用我们的系统时连接不良。当某些用户保存一些产品信息时,我发现一些数据(字段)不是100%保存到DB中。我很难重现这个问题,因为我的连接很好。
所以我的问题是如何让服务器知道我已经在保存/更新查询执行之前发送所有字段进行处理?
case "save":
for ($i=0, $n=sizeof($languages); $i<$n; $i++)
{
$language_id = $languages[$i]['id'];
$name = preg_replace( '/\s+/', ' ', tep_db_prepare_input($_POST["products_name"][$language_id]));
$description = tep_db_prepare_input(str_replace(" ", " ", $_POST["products_description"][$language_id]));
$extra_info = tep_db_prepare_input(str_replace(" ", " ", $_POST["products_extra_info"][$language_id]));
tep_db_perform(TABLE_PRODUCTS_DESCRIPTION, $sql_data_array, 'update', 'products_id = "' . $pID . '" AND language_id="'.$language_id.'"');
// update other language that empty
$sql_data_array = array('products_name' => $name);
tep_db_perform(TABLE_PRODUCTS_DESCRIPTION, $sql_data_array, 'update', 'products_id = "'.$pID.'" and products_name = ""');
$sql_data_array = array('products_description' => $description);
tep_db_perform(TABLE_PRODUCTS_DESCRIPTION, $sql_data_array, 'update', 'products_id = "'.$pID.'" and products_description = ""');
$sql_data_array = array('products_extra_info' => $extra_info);
tep_db_perform(TABLE_PRODUCTS_DESCRIPTION, $sql_data_array, 'update', 'products_id = "'.$pID.'" and products_extra_info = ""');
}
... etc
答案 0 :(得分:2)
使用数据库事务可以防止出现这些错误。 出现问题时,不会对数据库进行更新。 请注意,您无法在MyISAM表上使用事务,您需要使用 InnoDB 引擎
答案 1 :(得分:1)
您需要使用transaction
来执行多个数据库查询。优点是,如果其中一个查询在执行中失败,则执行的所有先前操作都将在数据库中撤消。这样,您的数据库中没有任何损坏或不完整的数据。
答案 2 :(得分:-1)
除了@Mark Baker所说的明显之外,您可以使用PHP的connection_aborted()函数来检测用户何时断开连接。以下是评论部分的摘录:
-
检测连接是否已关闭而不必发送否则会破坏数据流的数据(如二进制文件)的技巧您可以通过发送“0”来组合使用HTTP / 1.1上的数据进行分块(“零”)作为一个没有其他任何东西的领先块大小。
注意重要的是要注意,每隔几秒检查一次流不是一个好主意。通过这样做,您可能会增加发送给用户的数据而不会增加用户的利益。
这样做的一个很好的理由是,如果您生成的报告需要很长时间才能运行并占用大量服务器资源。这将允许服务器检测用户是否取消下载并进行任何清理而不会破坏正在下载的文件文件。
以下是一个例子:
<?php
ignore_user_abort(true);
header('Transfer-Encoding:chunked');
ob_flush();
flush();
$start = microtime(true);
$i = 0;
// Use this function to echo anything to the browser.
function vPrint($data){
if(strlen($data))
echo dechex(strlen($data)), "\r\n", $data, "\r\n";
ob_flush();
flush();
}
// You MUST execute this function after you are done streaming information to the browser.
function endPacket(){
echo "0\r\n\r\n";
ob_flush();
flush();
}
do{
echo "0";
ob_flush();
flush();
if(connection_aborted()){
// This happens when connection is closed
file_put_contents('/tmp/test.tmp', sprintf("Conn Closed\nTime spent with connection open: %01.5f sec\nLoop itterations: %s\n\n", microtime(true) - $start, $i), FILE_APPEND);
endPacket();
exit;
}
usleep(50000);
vPrint("I get echo'ed every itteration (every .5 second)<br />\n");
}while($i++ < 200);
endPacket();
?
注意:此行ignore_user_abort(true);
允许脚本在用户断开连接后继续在后台运行,没有它(即默认情况下),PHP进程会立即被终止。这就是为什么使用交易将解决您的问题,因为交易已经启动,从未完成。