首页 > 解决方案 > 为什么数据库返回旧信息?

问题描述

(编辑:我在下面添加了示例。我还按照评论中的建议在我的表中添加了一个 public_ip)

(只是免责声明,我对 Web 开发还是很陌生。我对 MySQL 和 PhP 的了解尤其少。)

我有一个包含数字记录的数据库表。对于此示例,它包含 DVD 记录。我的 php 页面之一收到要删除的 DVD 的 ID,然后继续这样做。($chosenTable 是一个变量,因为我也有不同的 CD、Vinyls 和其他表格 - 它们都有相同的列)

$sql = "DELETE FROM $chosenTable WHERE id=$removeID";
$conn->exec($sql);

然而我注意到最近它会删除不存在的记录。例如,我的数据库中有这个:

ID - 标题 - 评论 - 文件位置
1 - Mr Bones - 非常新 - Folder/Bones.jpg
2 - Avengers - Secondhand - Folder/Avengers.jpg

第一次使用删除查询。如果我发送“2”,它会删除记录二。所以正如预期的那样,我还剩下一条记录:

ID - 标题 - 评论 - 文件位置
1 - Mr Bones - 非常新 - 文件夹/Bones.jpg

然后我会添加一条新记录。从 phpMyAdmin 的数据库中,我绝对确定它已被添加:

ID - 标题 - 评论 - 文件位置
1 - Mr Bones - 非常新 - Folder/Bones.jpg
2 - Intersteller - Broken - Folder/Intersteller.jpg

这里是我没有任何解释的地方。如果我再次删除第二条记录(这次是Intersteller),那么什么也不会发生。当我检查它应该删除的记录的标题时,它返回的第二条记录的标题。

获取我要删除的记录的信息:

$temp = $conn->query("SELECT Title from $chosenTable WHERE ID='$removeID')->fetch()["Title"];
echo $temp;

当我这样做时,它返回Avengers。考虑到上面的示例,返回的标题应该是Intersteller,而不是 Avengers复仇者联盟不再存在于表中。我对此非常肯定。所以现在我知道它不会删除第二条记录(Intersteller),因为它正在删除的第二条记录,复仇者联盟。当我删除第三条或第四条记录时也是如此(它会删除不存在的旧的第三条和第四条记录)。

由于某种原因,Chrome 或服务器似乎将自己的伪表存储在它使用的某个地方,而不是我的实际表。

我已经看了一整天,我找不到解决方案。我再次为任何愚蠢的错误道歉。我真的希望我能明白我到底是如何度过这个难关的。

我注意到当我使用另一个浏览器时,比如 Firefox,甚至是我智能手机的浏览器,它再次允许我删除一次记录。如果我上传并删除另一个项目,我会遇到完全相同的问题。它发生在不同的浏览器上让我认为问题出在我身上。

我正在使用数据库 MySQL 客户端版本:5.6.43

有什么帮助吗?

编辑:我制作了两个 php 页面来模拟问题。同样的事情也会发生。我不知道如何连接到 DB fiddle,所以我希望代码本身就足够了。upload.php 提交信息并将其添加到数据库表中。remove.php 删除表中的记录之一:

上传.php

<?php
if ($_SERVER["REQUEST_METHOD"] == "POST"){ 
     
     //Get info from POST
    $uTitle = $_POST["iTitle"]; 
    $uComment = $_POST["tComment"];
    $uPrice = $_POST["iPrice"];
    
    echo "<script>console.log('$uTitel - $uComment - $uPrice);</script>";
    
    //Set a file location for the uploaded picture
    $fileName = basename($_FILES["iFile"]["name"]);
    echo "<script>console.log('filenaam: $fileName');</script>";
    $saveLocation = "uploads/".$fileName;
    
    echo "<script>console.log('Saved locationk: $saveLocation');</script>";
    
    //Upload file
    if (move_uploaded_file($_FILES["iFile"]["tmp_name"], $saveLocation))
    { 
        
        //If file is successfully uploaded
        echo "<script>console.log('File uploaded');</script>";
        
        //For connecting to database table - these four variables obviously just for illustration:
        $servername = "localhost"; 
        $connectusername = "alyosha";
        $connectpassword = "alyoshaPassword";
        $dbname = "alyoshaDB";
    
     try { //If connected to database
        $conn = new PDO("mysql:host=$servername;dbname=$dbname", $connectusername, $connectpassword);
        
        echo "<script>console.log('Connected to Database');</script>";
        
        //I first see how many records are already in the table so that I can add the appropriate value for my 'public_ip' column
        $m = $conn->prepare("SELECT * from testTable");
        $m->execute();
        $amountRows = $m->rowCount();
        
        echo "<script>console.log('Amount in table before adding record: $amountRows');</script>";
        
        //newIP is the current amount+1 so that it is added below my previous records (if there are 3 records, the new one should obviously be record public_ip 4)
        $newIP = $amountRows +1;
        
        //Now for adding a row to the table with the submitted informaton:
            
            $sql = "INSERT INTO testTable (public_ip, Title, Comment, Price, File_Location) VALUES ($newIP, '$uTitle', '$uComment', $uPrice, '$saveLocation')";

            $conn->exec($sql);
            echo "<script>console.log('New row added');</script>";
            
            //Count again to make sure there is one more record than before
            $m = $conn->prepare("SELECT * from testTable");
            $m->execute();
            $amountRows = $m->rowCount();
            echo "<script>console.log('Amount in table after adding record: $amountRows');</script>";
        
     }
     catch (PDOException $e){ //if database did not connect
         echo "<script>console.log('Failed to connect to database');</script>";
     }
        
    }//if move
    
}//if post

?>

<!DOCTYPE html>
<html>
<head>
    <title>Add item</title>
    <meta name="viewport" content="width=device-width, initial-scale=1"/>
</head>
<body>
    <header>
        <h1>Upload</h1>
    </header>
          
        <form action='upload.php'  method='post' enctype='multipart/form-data'>
            <input type='file' name='iFile' required>
            <br/>
            <br/>
            
            
            <label for='iTitle'>Title:</label>
            <input type='text' name='iTitle' required>
            <br/>
            <br/>
            
            <label for='iPrice'>Price:</label>
            <input id='iPriceUpload' type='number' name='iPrice' min='1' required>
            <br/>
            <br/>
            
            <label for='tComment'>Comments (optional):</label>
            <br/>
            <textarea type='text' name='tComment'></textarea>
            <br/>
            <br/>
            
            <input type='reset' name='iReset'>
            <input type='submit' name='iSubmit'>
            <br/>
        
        <a href='remove.php?num=1'>Remove record 1</a>
             <!--In practise the user would not be able to choose this by altering the link, but for my example this is easier to change this here -->
        

</body>
</html>

删除.php:

<?php
    if ($_SERVER["REQUEST_METHOD"] == "GET"){ 
        
        $removeIP = $_GET["num"]; //The public_ip record to be deleted
        
        //Connect to table
        servername = "localhost"; 
        $connectusername = "alyosha";
        $connectpassword = "alyoshaPassword";
        $dbname = "alyoshaDB";
    
     try { //If connected to database
        $conn = new PDO("mysql:host=$servername;dbname=$dbname", $connectusername, $connectpassword);
        
        echo "<script>console.log('Connected to Database in Remove.php');</script>";
        
         //All the remaining records should have their public_ips shifted upwards (5->4, 4->3, 3->2, 2->1)
        //It is necessary to again count the amount of rows left to achieve this
        $m = $conn->prepare("SELECT * from testTable");
        $m->execute();
        $amountRows = $m->rowCount();
        
        echo "<script>console.log('Amount of rows before deleting: $amountRows');</script>";
        
        //For debugging purposes get the title of removeIP:
        $gotTitle = $conn->query("SELECT Title from testTable WHERE public_ip='$removeIP'")->fetch()["Title"];
     
         echo "<script>console.log('Title of record $removeIP to be deleted: $gotTitle');</script>";
     
        
        //
        
        $sql = "DELETE FROM testTable WHERE public_ip=$removeIP"; //public_ip=1
        $conn->exec($sql);
        
        echo "<script>console.log('Record $removeIP deleted');</script>";
        
        //count again to make sure one record is removed:
        $m = $conn->prepare("SELECT * from testTable");
        $m->execute();
        $amountRows = $m->rowCount();
        
        echo "<script>console.log('Amount of rows affter deleting: $amountRows');</script>";
        
        if ($removeIP < ($amountRows+1)){ //in case the removed record is the only one in the table it won't be necessary to change the public_ips of the rest
            
            for ($x = 1; $x < ($amountRows+2); $x++)
                {
                    echo "<script>console.log('Changing record: $x');</script>";
                    $lowerIP = $x-1; //The record with public_ip 2 should become public_ip 1, and 3->2, etc
                    
                    $sql = "UPDATE testTable SET public_ip=$lowerIP WHERE public_ip=$x";
                         
                    $stmt = $conn->prepare($sql);
                    $stmt->execute();
                }
            echo "<script>console.log('Loop finished');</script>";
        }
     }
     catch (PDOException $e){
         echo "<script>console.log('Failed to connect to database in Remove.php');</script>";
     }
        
        
    }//if GET
    
    //After everything go back to upload page
    echo "<script>window.location = 'upload.php';</script>";

?>

这是我正在使用的表格类型的屏幕截图: 我的表,'testTable'

更新:从广泛的评论看来,PHP 和浏览器之间的某处正在缓存页面。@Martin 提出了一个解决方法,在我解决这个问题之前它似乎很有帮助。这是在页面 url 中添加日期字符串,强制浏览器读取新页面而不是缓存页面(如果我理解正确的话)。

但是,如果有人仍然可以首先解释为什么这是一个问题,我将不胜感激。我可以理解浏览器或使用旧版本页面的任何内容,但我无法理解这会在某处保留过时的表格。

标签: phpmysqlsql

解决方案


恕我直言,在删除行时重新编号是一个非常糟糕的主意

为什么?

一方面,这样做的成本会随着您拥有的行数越多而增加。SQL 的全部意义在于允许您有效地处理大量表。

另一方面,当您有多个用户这样做时,您会感到困惑。如果一个用户正在查找内容,而另一个用户正在删除它们,则第一个用户将在她下面更改行号。您可以通过明智地使用数据库事务来管理它,但它们只会阻止第二个用户,直到第一个用户完成。这种情况通常被称为“竞争条件”。

您提到您是 MySql 的新手。再次尊重,我建议您坚持使用经过验证的方式处理您的 ID 号码:自动递增。当您从自动递增表中删除一行时,插入的下一行不会重新使用已删除的 ID。

每个人都使用自动递增的 ID 值——从学生到拥有难以想象的巨大桌子的信用卡公司。我建议你也这样做,至少在你对这项技术更加熟练之前。

编辑如果要按插入的顺序显示行,只需执行SELECT whatever FROM tbl ORDER BY idwhere idis the autoincrementing ID column。由于删除的行导致的 ID 序列中的间隙不是问题。

如果你有一个特定的 ID 值并且你想要下一行,按照你插入它们的顺序,你可以做

  SELECT whatever 
    FROM tbl
   WHERE id > <<<the value you have>>
   ORDER BY id
   LIMIT 1;

id > <<<the value you have>>即使 ID 值有间隙,过滤器也能正常工作。

你说只有一个用户。但是,如果该用户碰巧同时打开了两个在数据库上工作的网页,那么您的重新编号设置将失败。壮观。当您拥有 Web 界面时,假设您将具有并发访问权限始终是最安全的。


推荐阅读