Frage

Dies ist eine schwierige Sache zu erklären (und sehr komisch), so Bär mit mir. Ich werde das Problem und die Lösung für sie erklären, aber ich würde gerne sehen, wenn jemand erklären kann, warum es so funktioniert, funktioniert es:)

ich eine Web-Anwendung, dass Verwendungen mod_perl. Es nutzt MySQL-Datenbank, und ich Daten in eine Datenbank regelmäßig zu schreiben. Es ist modular aufgebaut, so dass es auch seine eigene ‚Datenbank‘ Art eines Moduls hat, wo ich Verbindung behandeln, Updates usw. Datenbank :: db_connect () Unterprogramm verwendet wird, um Datenbank zu verbinden, und AutoCommit auf 0 gesetzt ist.

Ich habe eine andere Perl-Anwendung (Standalone-Daemon), die in regelmäßigen Abständen Daten aus der Datenbank abruft, und führen verschiedene Aufgaben je nachdem, was Daten zurückgegeben werden. Ich bin auch database.pm Modul darin, also muss ich nicht neu schreiben / doppelte alles.

Problem ich erlebe ist:

Anwendung stellt eine Verbindung zur Datenbank beim Start, und dann für immer Loops, Daten aus der Datenbank alle X Sekunden zu holen. Wenn jedoch Daten in der Datenbank aktualisiert werden, wird meine Bewerbung noch zurückgegeben werden ‚alte‘ Daten, dass ich auf der erste Verbindung / Abfrage an die Datenbank bekommen.

Zum Beispiel - ich habe 3 Zeilen und Spalte „Name“ haben Werte ‚a‘, ‚b‘ und ‚c‘ - für jeden Datensatz. Wenn ich eine der Zeilen aktualisieren (mysql-Client von der Kommandozeile verwenden, zum Beispiel) und ändern Namen von ‚c‘ auf ‚x‘, Daemon meines Standalone nicht, dass die Daten erhalten - es wird nach wie vor mit a / b / c erhalten kehrt aus MySQL. Ich eroberte den db Verkehr mit tcpdump, und ich konnte auf jeden Fall sehen, dass MySQL war wirklich, dass die Daten zurück. Ich habe auch mit SQL_NO_CACHE mit SELECT versucht (da ich nicht sicher war, was los war), aber das hat nicht geholfen entweder.

Dann habe ich die DB-Verbindungszeichenfolge in meinem Standalone-Daemon geändert und Set AutoCommit auf 1 Plötzlich Anwendung gestartet korrekte Daten zu erhalten.

Ich bin verwirrt, weil ich dachte, AutoCommit betrifft nur INSERT / UPDATE Arten von Anweisungen, und hatte keine auf SELECT-Anweisung beeinflussen. Aber es scheinbar tut, und ich verstehe nicht, warum.

Wer weiß, warum SELECT-Anweisung wird nicht ‚aktualisiert‘ Zeilen aus der Datenbank zurück, wenn AutoCommit auf 0 gesetzt ist, und warum es aktualisierten Zeilen zurück, wenn AutoCommit auf 1 gesetzt?

Hier ist eine vereinfachtes (entnommen Fehlerprüfung, usw.) Code, dass ich im Stand-Alone-Daemon benutze und dass nicht wieder aktualisierten Zeilen.

#!/usr/bin/perl

use strict;
use warnings;
use DBI;
use Data::Dumper;
$|=1;

my $dsn = "dbi:mysql:database=mp;mysql_read_default_file=/etc/mysql/database.cnf";
my $dbh = DBI->connect($dsn, undef, undef, {RaiseError => 0, AutoCommit => 0});
$dbh->{mysql_enable_utf8} = 1;

while(1)
{
    my $sql = "SELECT * FROM queue";
    my $stb = $dbh->prepare($sql);
    my $ret_hashref = $dbh->selectall_hashref($sql, "ID");
    print Dumper($ret_hashref);
    sleep(30);
}

exit;

Ändern AutoCommit auf 1 behebt diese. Warum?

Danke:)

P. S:. Nicht sicher, ob es jemand Sorgen, aber DBI Version 1.613, DBD :: mysql ist 4,017, Perl ist 5.10.1 (auf Ubuntu 10.04)

War es hilfreich?

Lösung

Ich nehme an, Sie InnoDB-Tabellen verwenden und nicht MyISAM diejenigen. Wie in dem Transaktionsmodell InnoDB beschrieben , < em> alle Ihre Anfragen (einschließlich SELECT) statt innerhalb einer Transaktion.

Wenn AutoCommit eingeschaltet ist, wird eine Transaktion für jede Abfrage gestartet und wenn es erfolgreich ist, wird es implizit verpflichtet (wenn es fehlschlägt, kann das Verhalten unterschiedlich sein, aber die Transaktion zu Ende garantiert). Sie können die impliziten Commits in MySQL binlog sehen. Durch die Einstellung AutoCommit auf false, sind Sie verpflichtet, die Geschäfte auf eigene Faust zu verwalten.

Die Standardtransaktionsisolationsstufe ist WIEDERHOLBARE READ , was bedeutet, dass alle SELECT Abfragen die gleiche Momentaufnahme lesen (die eine etablierte, wenn die Transaktion gestartet wird).

Neben der Lösung in der anderen Antwort gegeben (ROLLBACK vor zu lesen beginnen) hier sind ein paar Lösungen:

Sie können eine andere Transaktionsisolationsstufe wählen, wie Committed lesen, die Ihre SELECT Abfragen macht einen neuen Snapshot jedes Mal lesen.

Sie können auch AutoCommit auf true (Standardeinstellung) verlassen und Ihre eigenen Transaktionen beginnen mit BEGIN WORK Ausgabe. Dadurch wird das Verhalten AutoCommit vorübergehend deaktivieren, bis Sie eine COMMIT oder ROLLBACK Erklärung abgeben, wonach jede Abfrage erneut eine eigene Transaktion wird (oder Sie starten eine andere mit BEGIN WORK).

Ich persönlich würde die letztere Methode wählen, wie es eleganter scheint.

Andere Tipps

Ich glaube, dass, wenn Sie Autocommit ausschalten, können Sie auch eine Transaktion starten. Und wenn Sie eine Transaktion starten, können Sie von anderen Menschen die Veränderungen geschützt werden, bis Sie es begehen, oder es wieder rollen. Also, wenn meine halb informierte Vermutung richtig ist, und da Sie nur die Daten abfragen, einen Rollback vor der Sleep-Funktion hinzufügen (keine Punktschlösser in halten, dass Sie nicht verwenden, etc.):

$dbh->rollback;
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top