Guten Morgen, ich hab immer noch große Verständnisprobleme mit MySQL und Nebenläufigkeit. Abstrahiert ist mein Problem folgendes: Angenommen ich hab eine Tabelle, die ganz simpel einfach so aussieht: id (primary, int), value1 (int), value2 (int) und ich hab User, die über ein Java Servlet Einträge in der DB hinterlassen können. Hierbei soll es - vereinfacht - mehrere Regeln geben: - value1 < value2 (das ist immer gegeben und muss nicht gesondern berücksichtigt werden) - Es dürfen keine Überschneidungen von Intervallen [val1;val2] in der Datenbank existieren. Beispiel: Wenn zwei User folgendes Eintragen: val1 = 10, val2 = 100, dann ist das quasi ein Interval [10;100], dann darf kein User z.B. [5;50] eintragen, aber er dürfte [5;9] eintragen. Soweit ist das hoffentlich klar. In der Realität handelt es sich um konvexe Polygone, die sich nicht überschneiden dürfen, aber ich denke, für die Erklärung ist das verständlich. Wichtig ist - glaub ich zumindest - dass es von MySQL keine Möglichkeit gibt, das beim Insert zu überprüfen. Das Problem hierbei ist jetzt, dass ich im Grunde erstmal nachschauen muss, ob das Intervall, das eingetragen werden soll, in der Datenbank existiert und wenn nicht, dann wird es eingetragen. Die Servlets können aber im Grunde parallel und sogar auf verschiedenen Rechnern gleichzeitig ausgeführt werden und da gibts dann die bekannten Probleme, wofür man normalerweise Mutex verwendet. Es gibt hierzu mehrere Ideen, wie man das Problem lösen kann: - Die Servlets mit einem Mutex locken - ist aber Gift für die Skalierbarkeit und funktioniert nicht in z.B. einer Cloud. - Die Tabelle mit einem MySQL-Lock locken, da besteht aber das Problem, dass ich zu 99% unnötig die Tabelle locke und andere User, die Intervalle eintragen wollen, die nicht im Konflikt sind, unnötig abbremsen würde. Hat da jemand eine Ahnung, wie sowas funktionieren könnte? Wäre dankbar für Hilfe ... Das Problem verwirrt mich jetzt schon seit ein paar Wochen und da muss es doch eine einfache und effiziente Lösung geben ... Grüße, Markus
Du könntest einen Trigger auf Insert/Updates setzen und die entsprechende Aktion ggf. zurückweisen.
Mit Triggern hab ich bisher noch nichts gemacht, aber auf den ersten Blick sehen die Möglichkeiten interessant aus. Was ich bisher gelesen habe, müsste ich aber dann im Trigger die Überprüfung der Intervalls, bzw in der echten Anwendung eines Polygons machen, was wahrscheinlich nicht möglich ist. In der echten Applikation ist es so, dass ich zusätzlich zum Polygon auch das Umgebende Rechteck gespeichert habe und so schnell mögliche Kandidaten finden kann, die man genauer untersuchen muss. Ich bezweifle, dass es hierfür eine effiziente ähnliche Möglichkeit in MySQL-Syntax als Trigger gibt ...
Lock wäre sicherlich das einfachste für eine erste Lösung, wenn es Probleme mit der Skalierbarkeit gibt würde ich auch versuchen die Überprüfung in einem Trigger zu machen.
Ist MySQL unverzichtbar? PostgreSQL hat ein exclusion constraint, das möglicherweise in der Lage ist, solche inhaltlichen Beziehungen der rows untereinander abzubilden. http://www.postgresql.org/docs/9.0/interactive/sql-createtable.html#SQL-CREATETABLE-EXCLUDE
Andreas Schwarz schrieb: > Genau dafür wurden Transaktionen erfunden. Es wäre nett, wenn du das etwas ausführlicher erläutern könntest. Ich nehm Transaktionen her, um zu gewährleisten, dass meine DB konsistent bleibt im Fehlerfall, weil ich dann einen Rollback machen kann. Ein Zeilen-Lock, wie bei "SELECT ... FOR UPDATE" oder sowas, trifft hier ja nicht zu, weil eine neue Zeile eingefügt wird, die von allen anderen Zeilen im Prinzip abhängt. Wüsste also nicht, wie ich da um einen Table-Lock herumkommen sollte oder wie das mit Transaktionen gehen soll.
Andreas Schwarz schrieb: > Lock wäre sicherlich das einfachste für eine erste Lösung, wenn es > Probleme mit der Skalierbarkeit gibt würde ich auch versuchen die > Überprüfung in einem Trigger zu machen. Okay, das ist eine gute Aussage. Dann behalte ich das mal im Hinterkopf und versuchs mit Table Locks. @A.K. > Ist MySQL unverzichtbar? PostgreSQL hat ein exclusion constraint, das > möglicherweise in der Lage ist, solche inhaltlichen Beziehungen der rows > untereinander abzubilden. Interessant, mit PostgreSQL hab ich noch nichts gemacht. Nein, ich bin nicht an MySQL gebunden - es hatte bisher einfach das gemacht was es soll. Ich schau mir die Möglichkeiten von PostgreSQL an und auch wieviel Arbeit es wäre, mein bestehendes Projekt umzustellen, für den Fall, PostgreSQL kann wirklich das, was ich brauche. Danke! Grüße, Markus
NB: PostgreSQL kennt sogar geometrische Daten wie Polygone als Datentyp: http://www.postgresql.org/docs/9.0/interactive/datatype-geometric.html
mit Transaktionen gehts prinzipiell so (nicht MySQL-Syntax):
1 | SET TRANSACTION ISOLATION LEVEL SERIALIZABLE |
2 | |
3 | IF NOT EXISTS (SELECT * FROM tabelle WHERE value1 < @value2 OR value2 > @value1) |
4 | INSERT tabelle @id, @value1, @value2 |
5 | ELSE RAISERROR 'Gips schon...' |
ist aber deadlock-verdächtig und läuft evtl. während des Insert auch auf einen Table-Lock hinaus...
A. K. schrieb: > NB: PostgreSQL kennt sogar geometrische Daten wie Polygone als Datentyp: > http://www.postgresql.org/docs/9.0/interactive/dat... Sehr interessant! PostgreSQL hat auch Geometrische Funktionen, mit denen man direkt testen kann, ob sich z.B. Polygone schneiden. Dann könnte man wirklich Trigger bauen, die erst die Polygon-Kandidaten bestimmen und dann nochmal genau schauen, ob sich da was schneidet. Danke für die Hinweise! Grüße, Markus
MySQL kann das auch: http://dev.mysql.com/doc/refman/5.1/en/functions-that-test-spatial-relationships-between-geometries.html
Mittlerweile hab ich meine DB nach PostgreSQL migriert und das war ein Haufen Arbeit. Scheint keine guten automatischen Tools zu geben, die die Constraings für Fremdschlüssel, die Sequenzgeneratoren für Primärschlüssel oder die Indizes mitübernehmen. Oder sie kosten was ;) Dann musste ich feststellen, dass der org.postgres.PGpolygon datentyp zwar von datanucleus supported wird, das aber in einem nutzlosen bytea in der DB landet und damit nutzlos wird. Mit PostGIS funktionierts jetzt, aber dann hätte ich auch OpenGIS mit mysql verwenden können, was Andreas schon angemerkt hat. Naja, Hat ein paar Tage gekostet, aber es macht jetzt das, was es soll. Eine letzte Frage vlt ... Wenn ich einen On-Insert Trigger baue, muss ich innerhalb des Triggers irgendwas locken? Oder werden die Trigger ausschließlich seriell ausgeführt? Grüße, Markus
muahahaha it's alive!!!! ;)
1 | CREATE OR REPLACE FUNCTION dsstand_insert_gispolygon() RETURNS TRIGGER AS |
2 | $body$ |
3 | DECLARE |
4 | myrec RECORD; |
5 | BEGIN |
6 | SELECT "ID" INTO myrec FROM "DSSTAND" WHERE Intersects( "GISPOLYGON", NEW."GISPOLYGON") AND "ID" != NEW."ID" LIMIT 1; |
7 | IF FOUND THEN |
8 | RAISE EXCEPTION 'POLYGON INTERSECTING!'; |
9 | ELSE |
10 | RETURN NEW; |
11 | END IF; |
12 | END; |
13 | $body$ LANGUAGE plpgsql; |
Muss ich da noch Table-Locks reinbauen, oder werden die Trigger sequenziell abgearbeitet?
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.