php.de

Zurück   php.de > Webentwicklung > Datenbanken

Datenbanken SQL und Co

Antwort
 
LinkBack Themen-Optionen Thema bewerten
Alt 09.02.2010, 00:21   #11 (permalink)
erc
Erfahrener Benutzer
 
Registriert seit: 02.01.2009
Beiträge: 469
erc befindet sich auf einem aufstrebenden Ast
erc eine Nachricht über ICQ schicken
Standard

Zitat:
Zitat von Samhayne Beitrag anzeigen
Nene... Datenbank öffnen, Table locken, drauf schreiben, Datenbank wieder schließen, lock aufheben.
und wieso schreibst du dann die Lösung schon in den Titel?

PHP-Code:
LOCK TABLES tabelle WRITE 
erc ist offline   Mit Zitat antworten
Sponsor Mitteilung
PHP Code Flüsterer

Registriert seit: 21.08.2005
Beiträge: 4682
PHP-Kenntnisse:
Fortgeschritten

Alt 09.02.2010, 00:44   #12 (permalink)
Erfahrener Benutzer
 
Registriert seit: 07.06.2008
Beiträge: 607
PHP-Kenntnisse:
Fortgeschritten
Frank ist zur Zeit noch ein unbeschriebenes Blatt
Frank eine Nachricht über ICQ schicken Frank eine Nachricht über MSN schicken Frank eine Nachricht über Yahoo! schicken
Standard

Wenn du dich über Transactions informiert hast, wirst du wissen, wie das funktioniert^^

Transaktionen sind ein in sich geschlossener Prozess.

Zum Beispiel:
Code:
START TRANSACTION
   UPDATE `Tabelle` SET `Feld` = NULL
COMMIT
Würde alle Felder namens Feld der Tabelle Tabelle auf Null setzen.
Da es eine Transaktion ist, kann zwischenzeitlich keine andere Abfrage "reinfummeln". Du brauchst also nicht mit locks zu arbeiten. Die Transaktion hat erst auf deine Datensätze eine Auswirkung, wenn sie komplett abgeschlossen ist, und dann auf alles gleichzeitig.

Angenommen folgende Situation:

Benutzer A macht ein Update und setzt alle Felder "Geld" auf 0, anschließend mach er ein weiteres Update und setzt alle Felder "Geld" auf 200. Dann fällt ihm auf, das das völliger Schwachsinn war, und macht alles Rückgängig.
Benutzer B kommt zwischendrin und liest das Geld aller Benutzer aus.

Was kann passieren (nach deiner Problemstellung):
Mysql überschreibt alles mit 0, dann mit 200. Mitten drin fragt Benutzer B ab und bekommt ein paar Datensätze die noch auf 0 stehen und ein paar die schon auf 200 stehen (weil er mitten drin abgefragt hat).


Benutzer A
Code:
START TRANSACTION
UPDATE Tabelle SET Geld = 0
UPDATE Tabelle SET Geld = 200
ROLLBACK
Benutzer B
Code:
SELECT Geld FROM Tabelle
Die Abfrage (Transaktion) von Benutzer A wird erst ausgeführt wenn ein COMMIT (Absenden) oder ROLLBACK (Abbrechen) gesendet wird. Und dann, werden alle Änderunge innerhalb der Transaktion "gleichzeitig" und "genau in diesem Moment übernommen". Das heißt Benutzer B kann entweder genau VOR oder genau NACH der Transaktion abfragen, und bekommt somit immer das von dir "richtige" gewünschte Ergebnis.
Es ist nicht möglich genau dann eine Abfrage zu senden, in der eines der Updates der Transaktion noch nicht fertig ist. Denn die Transaktion hat entweder gar keine Änderung gemacht, oder ist mit allem fertig. Vorher ist die änderung der einzelnen Datensätze sozusagen "nicht bekannt" für andere Abfragen.

Sendet ein Benutzer wirklich Millisekunden genau gleichzeitig eine Anfrage muss diese automatisch solange warten, bis mysql mit der Transaktion fertig ist. Erst dann wird Sie ausgeführt und liefert ein Ergebnis zurück.

Sollte eigentlich genau das sein was du suchst.
__________________
Frank ist offline   Mit Zitat antworten
Alt 09.02.2010, 09:23   #13 (permalink)
Neuer Benutzer
 
Registriert seit: 22.01.2010
Beiträge: 25
PHP-Kenntnisse:
Fortgeschritten
Samhayne befindet sich auf einem aufstrebenden Ast
Standard

Zitat:
Zitat von erc Beitrag anzeigen
und wieso schreibst du dann die Lösung schon in den Titel?

PHP-Code:
LOCK TABLES tabelle WRITE 
Weil ich nicht weiß, wie ich die anderen User, die zugreifen wollen, derweil auf 'ne Wartebank setze... mit Lock.



@Frank: Danke für den Schnupperkurs!

Nur... nu' hat nikosch doch Recht... ich hätt's noch besser beschreiben müssen.

Der Ablauf ist für jeden User:

1) DB Query: SELECT.... Gibt's was zu tun?
2) Wenn ja, ...
2a) PHP: viel php code mit Berechnungen
2b) DB UPDATE: Schreib Ergebnisse zurück in Tabellen

Transactions scheitern hier glaube ich, so wie ich das überschau.
MySQL scheint wohl einen Serializable Modus für Transactions zu kennen,
der aber für PHP nicht funktionieren soll, weil Request / Response basiert.


Sind wir wieder beim Semaphor... um den auszulesen und zu setzen wäre eine Transaction aber wohl die Methode der Wahl, so wie es klingt.

Geändert von Samhayne (09.02.2010 um 11:28 Uhr).
Samhayne ist offline   Mit Zitat antworten
Alt 09.02.2010, 11:23   #14 (permalink)
Neuer Benutzer
 
Registriert seit: 22.01.2010
Beiträge: 25
PHP-Kenntnisse:
Fortgeschritten
Samhayne befindet sich auf einem aufstrebenden Ast
Standard

Oder auch nicht... grad mal bissl getestet.

Das scheint nicht zu stimmen:

Zitat:
Sendet ein Benutzer wirklich Millisekunden genau gleichzeitig eine Anfrage muss diese automatisch solange warten, bis mysql mit der Transaktion fertig ist. Erst dann wird Sie ausgeführt und liefert ein Ergebnis zurück.
Hab's mal mit autocommit = false getestet, was laut manual einer Transaction entspräche.
Gingst aber wahrscheinlich von einem Transactionquery in einem einzigen Block aus, an dessen Ende dann commited wird.


So verhält er sich jedoch wie man's von einem so benannten Modus erwarten würde.

Beide User bekommen Zugriff.... und sobald der erste user commited.... kriegt auch user 2 die neuen Daten. Davor kriegt er einfach die alten.


Ausgabe:

Code:
User 1 reads accesslock: open
User 1 queries autocommit status: 1
User 1 sets autocommit = false 
User 1 queries autocommit status: 0
User 1 sets Lock 
User 1 reads accesslock: locked
User 2 queries autocommit status: 1
User 2 reads accesslock: open
User 1 committed his changes. 
User 2 reads accesslock: locked
PHP-Code:
//set mysql connection vars manually
/*
define('DB_HOST', 'localhost');
define('DB_BENUTZER', 'username');
define('DB_PASSWORT', 'pass');
define('DB_NAME', 'db_name');
*/



$db1 mysqli_connect(DB_HOSTDB_BENUTZERDB_PASSWORTDB_NAME)
  or die (
"MySQL connect error" mysqli_error());

$db2 mysqli_connect(DB_HOSTDB_BENUTZERDB_PASSWORTDB_NAME)
  or die (
"MySQL connect error" mysqli_error());



function 
checkAutoCommitStatus($dbLink)
{
  
$sql "SELECT @@autocommit";
  
$result mysqli_query($dbLink$sql);
  
$row mysqli_fetch_row($result);
  
$bAC $row[0];

  return 
$bAC;
}


function 
setLock($dbLink$status)
{
  
$sql "UPDATE hayne_testtable
        SET accesslock = '$status'"
;

  
mysqli_query($dbLink$sql)
    or die (
"MySQL update error: " mysqli_error($dbLink));
}

function 
readLock($dbLink)
{
  
$sql "SELECT accesslock
        FROM hayne_testtable"
;

  
$result mysqli_query($dbLink$sql)
    or die (
"MySQL insert error: " mysqli_error($dbLink));
  
$daten mysqli_fetch_array($result);
  
$accesslock $daten["accesslock"];

  return 
$accesslock;
}


function 
buildTesttable()
{
  global 
$db;

  
//***** build testtable ******
  
$sql "
      CREATE TABLE IF NOT EXISTS `hayne_testtable` (
        `accesslock` varchar(20) NOT NULL DEFAULT 'open'
      ) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=3889 ;
      "
;

  
mysqli_query($db$sql)
      or die (
"MySQL connect error" mysqli_error());


  
$sql "INSERT INTO hayne_testtable (accesslock) VALUES ('open')";
  
mysqli_query($db$sql)
      or die (
"MySQL insert error" mysqli_error($db));
}






echo 
"========================================= <br />";

buildTesttable();



///////////////// ****** USER 1 ***** //////////////
echo "User 1 reads accesslock: " . (readLock($db1)) . "<br />";

echo 
"User 1 queries autocommit status: " . (checkAutoCommitStatus($db1)) . "<br />";

echo 
"User 1 sets autocommit = false <br />";
mysqli_autocommit($db1false);

echo 
"User 1 queries autocommit status: " . (checkAutoCommitStatus($db1)) . "<br />";

echo 
"User 1 sets Lock <br />";
setLock($db1'locked');

echo 
"User 1 reads accesslock: " . (readLock($db1)) . "<br />";

///////////////// ****** USER 2 ***** //////////////
echo "User 2 queries autocommit status: " . (checkAutoCommitStatus($db2)) . "<br />";

echo 
"User 2 reads accesslock: " . (readLock($db2)) . "<br />";

/////////////// ******* USER 1 commits ********//////////////
mysqli_commit($db1);
echo 
"User 1 committed his changes. <br />";

////// **** USER 2 reads accesslock **** /////
echo "User 2 reads accesslock: " . (readLock($db2)) . "<br />";





// clean up
mysqli_autocommit($db1true); 

$sql "DROP TABLE hayne_testtable";
mysqli_query($db1$sql)    
     or die (
"MySQL drop error: " mysqli_error($db1)); 

Geändert von Samhayne (09.02.2010 um 11:57 Uhr).
Samhayne ist offline   Mit Zitat antworten
Alt 09.02.2010, 11:55   #15 (permalink)
thomas_w
Gast
 
Beiträge: n/a
Standard

ich bin mir nicht sicher, ob das Autocommit mit "SELECT @@autocommit"; deaktiviert wird.

Schau die mal

PHP: mysqli::autocommit - Manual

PHP-Code:
<?php
mysqli_autocommit
($linkFALSE); // turn OFF auto
-some query 1;
-
some query 2;
mysqli_commit($link); // process ALL queries so far
-some query 3;
-
some query 4;
mysqli_autocommit($linkTRUE); // turn ON auto
?>
Ansonsten hast Du hier ein sehr schönes Testbeispiel zusammen gestellt!

EDIT:
Sorry nehme alles zurück und behaupte das Gegenteil. Vermutlich muss Du auf $db1 und $db2 mit Autocommit FALSE arbeiten.



Grüße
Thomas

Geändert von thomas_w (09.02.2010 um 12:20 Uhr). Grund: EDIT: Korrektur
  Mit Zitat antworten
Alt 09.02.2010, 12:21   #16 (permalink)
Neuer Benutzer
 
Registriert seit: 22.01.2010
Beiträge: 25
PHP-Kenntnisse:
Fortgeschritten
Samhayne befindet sich auf einem aufstrebenden Ast
Standard

Zitat:
Zitat von thomas_w Beitrag anzeigen
ich bin mir nicht sicher, ob das Autocommit mit "SELECT @@autocommit"; deaktiviert wird.
Nene... auch wenn ich den Select mehrfach ausführe, ändert sich nix.

Code:
User 1 queries autocommit status: 1
User 1 queries autocommit status: 1
User 1 queries autocommit status: 1
User 1 sets autocommit = false 
User 1 queries autocommit status: 0
User 1 queries autocommit status: 0
User 1 queries autocommit status: 0

Zitat:
Schau die mal

PHP: mysqli::autocommit - Manual
Natürlich schon reingeguckt.




Momentan bin ich wieder zurück bei der Idee, das Lock so zu lösen:

UPDATE: wenn 'open' setz meine User ID rein,
ansonsten lass es so, wie es ist.

PHP-Code:
function setLockV2($dbLink$user)
{
    
$sql "UPDATE hayne_testtable
                  SET accesslock = (CASE accesslock
                                       WHEN 'open' THEN 'locked by user $user'
                                       ELSE accesslock
                                    END)
            "
;


    
mysqli_query($dbLink$sql)
        or die (
"MySQL UPDATE error: " mysqli_error($dbLink));



Anschließend nochmal SELECT Abfrage, ob meine User ID gesetzt ist,
wenn ja... fang an zu arbeiten,
wenn nicht... 'ne halbe Sekunde Pause und nochmal.

Dazu dann eben noch ein 60 Sekunden Timeout, der das Lock mit Gewalt "aufreisst" bzw. noch zusätzlich ein Timestamp in der Tabelle.

Hmhm... 'n bißchen frickelig.
Aber funktionieren tut's.


Ausgabe:

Code:
====================================== 
User 1 tries to access... 
====================================== 
successfully locked by user 1. Doing work...

====================================== 
User 2 tries to access... 
====================================== 
No access! locked by user 1

PHP-Code:
function buildTesttable()
{
  global 
$db;

  
//***** build testtable ******
  
$sql "
      CREATE TABLE IF NOT EXISTS `hayne_testtable` (
        `accesslock` varchar(20) NOT NULL DEFAULT 'open'
      ) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=3889 ;
      "
;

  
mysqli_query($db$sql)
      or die (
"MySQL connect error" mysqli_error());


  
$sql "INSERT INTO hayne_testtable (accesslock) VALUES ('open')";
  
mysqli_query($db$sql)
      or die (
"MySQL insert error" mysqli_error($db));
}




function 
setLockV2($dbLink$user)
{
    
$sql "UPDATE hayne_testtable
                  SET accesslock = (CASE accesslock
                                       WHEN 'open' THEN 'locked by user $user'
                                       ELSE accesslock
                                    END)
            "
;


    
mysqli_query($dbLink$sql)
        or die (
"MySQL UPDATE error: " mysqli_error($dbLink));

}


echo 
"====================================== <br />";



buildTesttable();

$user 1;
echo 
"====================================== <br />";
echo 
"User $user tries to access... <br />";
echo 
"====================================== <br />";

setLockV2($db1$user);



$lock readLock($db1);

if (
$lock == "locked by user $user")
{
    echo 
"successfully locked by user $user. Doing work...<br />";
    
//do stuff
    //[...]

    //setLock($db1, "open"); echo "Lock opened. <br />";
}
else echo 
"No access! $lock <br />";



$user 2;
echo 
"====================================== <br />";
echo 
"User $user tries to access... <br />";
echo 
"====================================== <br />";


setLockV2($db1$user);

$lock readLock($db2);

if (
$lock == "locked by user $user")
{
    echo 
"successfully locked by user $user. Doing work...<br />";
    
//do stuff
    //[...]

    
setLock($db1"open"); echo "Lock opened. <br />";
}
else echo 
"No access! $lock <br />";





// clean up
$sql "DROP TABLE hayne_testtable";
mysqli_query($db$sql)    or die ("MySQL drop error: " mysqli_error($db)); 
Samhayne ist offline   Mit Zitat antworten
Alt 09.02.2010, 13:05   #17 (permalink)
thomas_w
Gast
 
Beiträge: n/a
Standard

Vielleicht testet Du Deine Beispiel noch mit den verschiedenen Isolation Levels

MySQL :: MySQL 5.1 Referenzhandbuch :: 14.2.10.3 InnoDB und TRANSACTION ISOLATION LEVEL

Code:
TRANSACTION-Anweisung einstellen, die folgende Syntax hat: 

SET [SESSION | GLOBAL] TRANSACTION ISOLATION LEVEL
                       {READ UNCOMMITTED | READ COMMITTED
                        | REPEATABLE READ | SERIALIZABLE}
Beachten Sie, dass in den Namen der Ebenen in der --transaction-isolation-Option Bindestriche verwendet werden, aber nicht in der SET TRANSACTION-Anweisung.
Mir ist es mal passiert, dass ich meine Tabellen zwar mit ENGINE=InnoDB erzeugt habe, aber die MySQL nur mit MyISAM gelaufen ist. Den Fehler habe ich dann länger gesucht....

Leider habe ich hier keine MySQL am Laufen... kann es also erst heute Abend testen.

Grüße
Thomas
  Mit Zitat antworten
Alt 09.02.2010, 13:43   #18 (permalink)
Neuer Benutzer
 
Registriert seit: 22.01.2010
Beiträge: 25
PHP-Kenntnisse:
Fortgeschritten
Samhayne befindet sich auf einem aufstrebenden Ast
Standard

Hm. *überfordert*

Hab ja nur Autocommit abgeschaltet und danach wieder an.

Mit einer Transaction Anweisung an sich könnt ich (glaub ich?) gar nichts anfangen.

Wegen Anforderung...

Zitat:
1) DB Query: SELECT.... Gibt's was zu tun?
2) Wenn ja, ...
2a) PHP: viel php code mit Berechnungen
2b) DB UPDATE: Schreib Ergebnisse zurück in Tabellen
Transactions umfassen ja nur immer eine Abfrage / einen Abfrageblock, soweit ich das verstanden hab,
an dessen Ende dann ein COMMIT oder ROLLBACK steht. (zumindest bei PHP).


Sowatt wie...

PHP-Code:
$sql "START TRANSACTION
          SELECT eintrag1, eintrag2 FROM tabelle...
          ..."
;

$result mysqli_query($db$sql)

// rechne mit result wild herum...

$sql "UPDATE tabelle
          ....
          COMMIT"
;

mysqli_query($db$sql); 
...scheint ja nicht zu gehen, soweit ich das verstanden hab.

Geändert von Samhayne (09.02.2010 um 13:49 Uhr).
Samhayne ist offline   Mit Zitat antworten
Alt 09.02.2010, 13:58   #19 (permalink)
moderatives Dielektrikum
 
Benutzerbild von nikosch
 
Registriert seit: 21.05.2008
Beiträge: 26.138
PHP-Kenntnisse:
Fortgeschritten
nikosch kann auf vieles stolz seinnikosch kann auf vieles stolz seinnikosch kann auf vieles stolz seinnikosch kann auf vieles stolz seinnikosch kann auf vieles stolz seinnikosch kann auf vieles stolz seinnikosch kann auf vieles stolz seinnikosch kann auf vieles stolz sein
Standard

Zitat:
1) DB Query: SELECT.... Gibt's was zu tun?
2) Wenn ja, ...
2a) PHP: viel php code mit Berechnungen
2b) DB UPDATE: Schreib Ergebnisse zurück in Tabellen
Irgendwie ist mir das alles zu allgemein. Aber machs doch so:
1) wie gehabt. Beachte dabei nachfolgendes
2) Suche Dir eine ID, die Du bearbeiten willst. Setze auf diese ID (DB Update) einen Zeitstempel, der mindestens so weit in der Zukunft liegt, wie die Berechnung dauert. Datensätze mit nicht abgelaufenen Zeitstempeln werden vom Select in 1) ignoriert
3) wie gehabt.
4) wie gehabt. Lösche den Zeitstempel, bei Bedarf.
__________________
--
„Eins ist Fakt: Gescannt wird nackt!“

Privatsphäre 2.0 - Nacktscanner mit Eyetracking.
Unser Flugzeug darf kein geschlechtsfreier Raum sein.
--
nikosch ist offline   Mit Zitat antworten
Alt 09.02.2010, 14:00   #20 (permalink)
thomas_w
Gast
 
Beiträge: n/a
Standard

Noch ein paar Fragen für mein Verständnis:

a) Was soll mit den "wartenden" Usern in der Zeit passieren, solange der "LOCK" User die Daten ändert?

=> 1) die Skripte der "wartenden" User bleiben hängen und warten bis der LOCK gelöst ist => eventuelles TIMEOUT Problem
=> 2) die Skripte der "wartenden" User laufen weiter und lesen "alte" Daten

b) Wird vom dem "LOCK" User die gesamte Tabelle gesperrt oder nur einzelne Datensätze, -bereiche (von bis Postleitzeit z.B.)

c) Wie lange dauert der Update des "LOCK" Users?

=> 1) wenige (Milli)-Sekunden
=> 2) mehr als 5 Sekunden

d) Wie häufig erfolgt so ein Update des "LOCK" Users?

=> 1) einmal pro Stunde
=> 2) sehr häufig
=> 3) sehr selten


Soweit mal ein paar Fragen meinerseits...

Ich denke schon, dass es eine Lösung gibt!


Grüße
Thomas
  Mit Zitat antworten
Sponsor Mitteilung
PHP Code Flüsterer

Registriert seit: 21.08.2005
Beiträge: 4682
PHP-Kenntnisse:
Fortgeschritten

Antwort


Themen-Optionen
Thema bewerten
Thema bewerten:

Forumregeln
Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are an
Gehe zu

Ähnliche Themen
Thema Autor Forum Antworten Letzter Beitrag
[Erledigt] mysql_insert_id () und LOCK TABLES Senifor PHP Einsteiger 2 29.10.2009 15:40
[Erledigt] breadcrumb 2 Tables mit Subcategories fulltilt PHP Einsteiger 6 19.09.2009 07:57
Kann LOCK TABLES zu Absturz der MySQL Datenbank führen? kat_2403 Datenbanken 2 03.09.2009 15:22
mysqlabfrage mit 2 tables (COUNT?) mqs PHP Einsteiger 6 17.06.2009 12:49
Welche Tables muss ich erstellen? She-Sign.de Datenbanken 2 12.05.2009 19:54
[Erledigt] LOCK TABLES - Thread statt Table??? Curanai Datenbanken 1 04.04.2009 01:33
[Erledigt] Problem bei delete über 2 tables fulltilt PHP Einsteiger 3 24.02.2009 22:29
Impossible WHERE noticed after reading const tables Gumfuzi Datenbanken 6 03.01.2009 10:53
Extrahieren aus 2 Tables mit einem bekannten Wert ssm Datenbanken 12 23.03.2006 20:29
Tables Schubi PHP Tipps 2005-2 0 05.08.2005 15:09
Tables Schubi PHP Tipps 2005-2 0 05.08.2005 15:08
Tables PHP Tipps 2005-2 0 05.08.2005 13:39
LOCK TABLES / LAST_INSERT_ID AliceD Datenbanken 3 20.07.2005 13:45
Suche zufalls(bild)script das in tables läuft... Beitragsarchiv 0 05.07.2005 12:18
SHOW PROCESSLIST und TEMPORARY TABLES tapferesschneiderlein Datenbanken 2 05.03.2005 11:40

Besucher kamen über folgende Suchanfragen bei Google auf diese Seite
query status locked updating mysql, db2 table lock which table, db2 tabellen locks, db2 drop table if exists, table was not locked with lock tables, mysql table lock aufheben, db2 lock table, php mysql myisam lock tables, php \or die\ locked tables, mysql alle locks aufheben, lock tables, mysql myisam how recognize if table is locked forum, \lock tables\ mehrere tabellen, php lock table beispiel, php warten bis mysql fertig ist, db2 autocommit, mysqli_connect gleichzeitig auf zwei datenbanken, wie mache ich /lock bei msn rückgängig, php table lock, not locked with lock tables

Alle Zeitangaben in WEZ +2. Es ist jetzt 18:24 Uhr.




Powered by vBulletin® Version 3.7.2 (Deutsch)
Copyright ©2000 - 2010, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO 3.2.0
Aprilia-Forum, Aquaristik-Forum, Liebeskummer-Forum, Zierfisch-Forum, Geizkragen-Forum