MySQL - Phänomen mit WRITE-LOCK

Mik3e

Erfahrenes Mitglied
Nochmals schönen Abend (schöne Nacht)!

Bin auf ein Phänomen beim WRITE Lock von Tabellen gestoßen.
Ich führe folgende Abfrage aus, bei der das SELECT Statement aufgrund der WRITE Sperre nicht funktioniert:

PHP:
// TABELLEN LOCKEN
		$sql = ' LOCK TABLE tbl_bezahlart_join_sysuser WRITE ';
		$this->_db->query($sql);

		
		$sql = ' SELECT '
			 . ' t1.`fk_bezahlart_id` AS `fk_bezahlart_id`, '
			 . ' t1.`fk_sysuser_id` AS `fk_sysuser_id` '
			 . ' FROM `tbl_bezahlart_join_sysuser` AS t1 '
			 . ' INNER JOIN `tbl_sysuser` AS t2 ON t1.`fk_sysuser_id`=t2.`pk_sysuser_id` '
			 . ' WHERE t1.`fk_bezahlart_id`=\''.$bezahlart_id.'\' '
			 . ' AND t2.`fk_veranstalter_id`=\''.$container_sysuser[1]['fk_veranstalter_id'].'\' ';
		$result =$this->_db->query($sql);
		while($row = $result->fetchRow(DB_FETCHMODE_ASSOC)):
			$sql = ' DELETE FROM '
				 . ' `tbl_bezahlart_join_sysuser` '
				 . ' WHERE '
				 . ' `fk_bezahlart_id`=\''.$bezahlart_id.'\' '
				 . ' AND `fk_sysuser_id`=\''.$row['fk_sysuser_id'].'\' ';
				$this->_db->query($sql);
		endwhile;
		
		// ANLEGEN DER WERTE IN DER ASSOZIATIVEN TABELLE (SYSTEM-BENUTZER)
		foreach ($sysuser_freischaltung as $key => $value) {
			echo $key .': '.$value.'<br>';
			$sql = ' INSERT INTO '
			 . ' `tbl_bezahlart_join_sysuser` '
			 . ' (`fk_bezahlart_id`,`fk_sysuser_id`) '
			 . ' VALUES '
			 . ' (\''.$bezahlart_id.'\',\''.$value.'\') ';
			$this->_db->query($sql);
			
		// TABELLEN FREIGEBEN
		$sql = ' UNLOCK TABLES ';
		$this->_db->query($sql);

Demzufolge sperre ich die assoziative Tabelle "tbl_bezahlart_join_sysuser" auf WRITE, was für diese Operation ja auch korrekt ist (wenn ich die MySQL Doku korrekt verstanden habe).

In der Doku steht wörtlich:
Wenn ein Thread eine READ-Sperre auf eine Tabelle erlangt, kann dieser Thread (und alle anderen Threads) nur aus der Tabelle lesen. Wenn ein Thread eine WRITE-Sperre auf eine Tabelle erlangt, kann nur der Thread, der die Sperre veranlasst hat, READ oder WRITE (Anm: Das interpretiere ich als: SELECT ist dann erlaubt) auf der Tabelle durchführen. Andere Threads werden blockiert.

Wäre es ein READ-Lock und er lässt das schreiben nicht zu, wäre es mir klar. Da es sich aber um einen WRITE Lock handelt, und er mir das erste SELECT Statement blockt, verstehe ich die Welt nicht mehr wirklich.

Ich komme um den Lock aber nicht herum (Datenkonsitenz)...

Kennt jemand von Euch dieses Phänomen? An einer falschen Behandlung der Threads kann es nicht liegen, da ich das Locking auch in anderen Methoden verwende (dort allerdings nur bei UPDATE, INSERT und DELETE Statements).

Vielleicht hat jemand einen Tipp,
Danke & LG
Mike

P.S.: Es liegt 100% am locking, denn wenn ich es entferne, arbeitet die Methode problemlos...
 
Vielleicht liegt es daran?
http://dev.mysql.com/doc/mysql/de/lock-tables.html hat gesagt.:
Wenn Sie LOCK TABLES benutzen, müssen Sie alle Tabellen sperren, die Sie benutzen werden, und Sie müssen denselben Alias benutzen, den Sie in Ihren Anfragen benutzen werden! Wenn Sie eine Tabelle in einer Anfrage mehrfach (mit Aliasen) benutzen, müssen Sie für jeden Alias eine Sperre machen!

Gruß hpvw
 
hmhmhm.. das habe ich auch gelesen...
Theoretisch sollte das dann so aussehen:

PHP:
$sql = ' LOCK TABLE t1 WRITE, t2 WRITE ';

Oder liege ich da falsch?
 
Du verwendest auch noch `tbl_bezahlart_join_sysuser` ohne Alias. Die Tabelle solltest Du vermutlich auch noch sperren.
 
Hi!

Es lag tatsächlich an den Alias...
Wenn ich t1 WRITE, t2 WRITE nutze, gibt es jedenfalls keine Fehlermeldung...

Dazu noch eine Frage:
Kann ich irgendwie prüfen, ob der LOCK funtkioniert? Denn offensichtlich liefert mir der Lock keine Errormessage, wenn etwas nicht stimmt (einzig der PHP Compiler schreit nach dem Select, da der Record leer ist der übergeben wird)...

Danke für die Tipps & LG
Mike
 
Ich habe jetzt eine Weile überlegt, aber trotzdem ist es nur mein erster Gedanke, der mir einfällt:
Überlege Dir zwei Abfragen, die miteinander kollidieren, schreibe sie in zwei Skripte. In dem ersten Skript machst Du nach dem LOCK eine Pause ([phpf]sleep[/phpf]) und dann versuchst Du diese Skripte möglichst zeitgleich auszuführen.
Wenn Du dann in der DB Fehler feststellst, geht der LOCK nicht, ansonsten kannst Du leider keine genaue Aussage treffen. Es könnte ja auch Zufall sein, dass es klappt.

Gruß hpvw
 
Hm.. sowas hatte ich befürchtet...
Was Du vorschlägst ist schon richtig, für den Gebrauch im Echtbetrieb aber leider nicht wirklich geeignet.

Ich dachte mehr an ein LOG File, in dem der Prozess mitgeschrieben wird. Aber sowas dürfte es nicht geben.

Danke trotzdem für die Hilfe :o),
LG
Mike
 
Zurück