MySQL double insert happinging in mijn php-applicatie

Ik heb een php-toepassing die informatie krijgt van een SAML POST en een record maakt in de MySQL-database, als de record al aanwezig is, wordt deze bijgewerkt

Hier is de code

//getMemberRecord returns true for successful insertion.
$row = $this->getMemberRecord($data);
if ($row) {
   //if the row already exists
   $this->updateMemberRecord($data)
} else {
  //creates a new record
   $this->setMemberRecord($data);
}

Deze code veroorzaakt dubbele invoegingen in de database, we hebben geen unieke sleutel voor de tabel vanwege enkele slechte ontwerpbeperkingen, maar ik zie twee HTTP-berichten in de toegangslogboeken op hetzelfde moment gebeuren.

De kolom voor het maken van de datum is hetzelfde of verschilt een seconde voor de dubbele record.

Dit probleem speelt zich af voor slechts enkele mensen, het werkt voor de meeste. De tabel is de innoDB-tabel en we kunnen sessies op onze architectuur niet gebruiken.

Om het even welke ideeën van waarom dit zou gebeuren

2
Zoals Jasper zegt, we moeten de code zien voor die get/set-methoden. Ook merk ik dat je een puntkomma mist na updateMemberRecord
toegevoegd de auteur Jonah, de bron
voor succesvolle invoeging , zoals in die methode wordt ingevoegd in de database? Past setMemberRecord ook in de db?
toegevoegd de auteur Shad, de bron
Is de code die je in een lus hebt gepost? Welke databasequery maakt setMemberRecord() aan?
toegevoegd de auteur Jasper, de bron
de puntkomma was een typfout, ik heb de vragen hieronder neergelegd
toegevoegd de auteur Jeetendra Pujari, de bron

4 antwoord

Jij zei:

Ik zie twee HTTP-berichten in de toegangslogboeken

  1. Probeer dit te voorkomen en gebruik slechts één http POST-aanroep
  2. Misschien is het een probleem met betrekking tot gelijktijdigheid en wederzijdse uitsluiting. De opgegeven code moet worden uitgevoerd in een zone die uitsluiting uitsluit, dus u moet sommige semafoor/mutex gebruiken om gelijktijdige uitvoering te voorkomen.
2
toegevoegd

Als je twee HTTP POST-acties hebt, is je probleem niet aan de kant PHP/MYSQL.

One thing is allowing a second 'transparent' HTTP POST in the HTTP protocol. It's the empty url. If you have an empty GET url in the page most browsers will replay the request which rendered the page. Some recent browser are not doing it, but most of them are still doing it (and it's the official way of HTTP). An empty GET url on a page is for example or < script url=""> but also an url() in a CSS file.

Het feit dat je een seconde tussen de twee berichten hebt, doet me denken dat dit is wat er voor je gebeurt. De POST-antwoordpagina bevat heel zeker een lege Get die de browser opvult door de POST opnieuw af te spelen ... Ik haat dit gedrag.

1
toegevoegd
public function setMemberRecord($data, $brand_id, $organization_id, $context = null)
{
    global $gRegDbManager;


    $sql = "insert into member ......"
    $gRegDbManager->DbQuery($sql);

   //Popuplate the iid from the insert
    $params['iid'] = $gRegDbManager->DbLastInsertId();

    $data =  some operations 
    return (int)$data;
}

public function getMemberRecord($field, $id, $brand_id, $organization_id, $organization_level_account = null)
{
    global $gRegDbManager;

    $field = mysql_escape_string($field);
    $id = mysql_escape_string($id);

    $sql = "SELECT * FROM " . DB_REGISTRATION_DATABASE . ".member WHERE $field = '$id' ";

    if($organization_level_account) {
        $sql .= "AND organization_fk = " . $organization_id;
    } else {
        $sql .= "AND brand_fk = " . $brand_id;
    }
    $sql .= " LIMIT 1";

    $results = $gRegDbManager->DbGetAll($sql);

    if(count($results) > 0) {
        return $results[0];
    }
    return;
}

/*     * ******************************************************************************************************
 * Updates member record in the member table
 * *******************************************************************************************************
 */

public function updateMemberRecord($id, $changes)
{
    global $gRegDbManager;
    $id = mysql_escape_string($id);

    if(!empty($changes)) {
        $sql = "UPDATE " . DB_REGISTRATION_DATABASE . ".member SET ";
        foreach($changes as $field => $value) {
            $sql .= mysql_escape_string($field) . " = '" . mysql_escape_string($value) . "', ";
        }
        $sql = rtrim($sql, ", ");
        $sql .= " WHERE iid = '$id'";

        $gRegDbManager->DbQuery($sql);
    } else {
        return false;
    }
}
1
toegevoegd

Ik ontdekte dat de dubbele inserts plaatsvonden vanwege dubbele indieningen en onze applicatie behandelt geen dubbele submits op efficiënte wijze, ik heb hierover enkele artikelen gelezen, hier zijn enkele van de oplossingen

het is altijd het beste om dubbele berichten aan de serverkant te verwerken

de beste oplossing is om een ​​UNIEKE SLEUTEL op tafel te zetten of een INSERT OP DUPLICATIESLEUTEL UPDATE te doen

if you have sessions then use the unique token , one of the technique in this article http://www.freeopenbook.com/php-hacks/phphks-CHP-6-SECT-6.html

or use can use the Post/Redirect/Get technique which will handle most double submit problems http://en.wikipedia.org/wiki/Post/Redirect/Get

opmerking: het Double submit probleem gebeurt alleen bij een POST-aanvraag, het GET-verzoek is immuun

0
toegevoegd