PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Richtig und Threadsicher eine ID als Pr.Key einfügen



darom
14-03-2005, 02:47
Hi,

habe folgendes Problem:
gegeben ist eine Tabelle mit diversen Feldern, wobei ID - Feld der PK ist(ansonsten keine Extras wie AUTO_INC oder so).
In diese Tabelle sollen nach Bedarf neue Datensätze eingefügt werden.

Wie mache ich das Einfügen ?
Ich dachte an folgendes Vorgehen:
Ich weiss wie lang die Tabelle werden kann, da der Datentyp vom PK(also ID) bekannt z.B. Integer;
solange die Tabelle nicht voll ist, frage ich mit SELECT ab welche ID bereits belegt sind(einfach),
dann nehme ich die kleinste ID und versuche einen Datensatz einzufügen. Kommt eine Ausnahme zu Stande, dann hat ein anderer Thread die ID in der zwischenzeit bereits belegt.
Also das ganze noch unter Beachtung dass die DB nicht voll ist, bis es geklappt hat.

Wie seht Ihr das , ist das Vorgehen ok ?

Axo: das ganze ist an ein Anmeldesysten in meiner FH gebunden. Es meldet sich jemand für eine z.B. Aufgabe an und für ihn soll eine Tabelleneintrag generiert werden mit einer ID(PK) und noch paar Daten wie Passwort usw. Dieses ganze soll von Servlets ausgeführt werden, die dann weil sie ja mehrfach zur selben Zeit aufgerufen werden können als einzelne Threads arbeiten und sich gegenseitig stören.

Bin für alle Vorschläge offen und bitte hier um Hilfe.

Gruß,
daom

marius
14-03-2005, 04:33
hi darom,

wie ich das sehe ist das ein klassisches shared memory problem.
wo immer von einander 'unabhaengige' routinen (threads, anwendungen) auf den selben speicherplatz zugreifen (egal was dieser nun sei) bedarf es einer synchronisation.
regeln kann man das z.b. mit hilfe einer semaphore.
ich moechte das hier aber nicht erklaeren weil:
1. ich dir nix falsches sagen will und es schon ne weile her ist dass ich in dieser materie war
2. verteilte systeme ein weitreichendes feld sind

such einfach mal nach dokumentation ueber java thread programming.. stichworte wie semaphore, mutex, shared memory, multithreading, etc. sollten dich schnell auf die richtige spur bringen.

hoffe das hilft irgendwie

gruss
marius

mwanaheri
14-03-2005, 09:40
Mir fallen dazu zwei Sachen ein:
die erste ist ein Lock der Tabelle bzw. der Zeile. Wenn die Datenbank das nicht kann, kannst du eine zentrale Instanz im Programm anlegen, in der die jeweilige PK abgelegt ist (z.B. in einem Array), die gerade bearbeitet werden soll. Soll nun ein thread in die Tabelle schreiben, schaut er in die Instanz und prüft, ob darauf bereits geschrieben werden soll, bevor er selbst sich für das Schreiben darauf anmeldet. Im Zweifelsfall muss er sich 'ne andere PK suchen.
Zweite (kombinierbare) Möglichkeit ist die Verwendung eines Nummernkreises. Das erfordert das Arbeiten mit Transaktionen.
Du legst eine kleine Tabelle an, die z.B. so aussieht:
tabelle | feld | nummer
In die trägst du ein, welches Feld welcher Tabelle welchen höchsten Wert hat.
Um einen neuen Eintrag zu machen, beginnst du eine Transaktion, holst dir die Nummer, zählst sie eins rauf, schreibst sie zurück und verwendest sie als PK in der entsprechenden Tabelle. Danach schließt du die Transaktion ab. die Nummernkreistabelle solltest du natürlich ebenfalls sperren, wenn du schreibst. Dieses Verfahren stellt eine Lückenlose Numerierung sicher, wie man es z.B. bei Rechnungen braucht.

peschmae
14-03-2005, 17:52
Ich dachte an folgendes Vorgehen:
Ich weiss wie lang die Tabelle werden kann, da der Datentyp vom PK(also ID) bekannt z.B. Integer;
solange die Tabelle nicht voll ist, frage ich mit SELECT ab welche ID bereits belegt sind(einfach),
dann nehme ich die kleinste ID und versuche einen Datensatz einzufügen. Kommt eine Ausnahme zu Stande, dann hat ein anderer Thread die ID in der zwischenzeit bereits belegt.
Also das ganze noch unter Beachtung dass die DB nicht voll ist, bis es geklappt hat.


Sollte es da nicht reichen wenn du die Methode die das suchen wo und Eintragen macht als "synchronized" Deklarierst?

Halt möglichst gucken dass nicht all zu viel dort drin ist da Synchronized Methoden generell langsamer laufen als "normale" (k.A. wieso dem so ist)

MfG Peschmä

darom
14-03-2005, 22:28
Sollte es da nicht reichen wenn du die Methode die das suchen wo und Eintragen macht als "synchronized" Deklarierst?

Halt möglichst gucken dass nicht all zu viel dort drin ist da Synchronized Methoden generell langsamer laufen als "normale" (k.A. wieso dem so ist)

MfG Peschmä

Synchronized heisst ich muss ein Object auf die Datenbankverbindung haben. Diese Lösung kommt glaube ich nicht in Frage weil mit jedem Aufruf eines Servlets man davon ausgehen muss dass eine neue Verbindung (also auch ein neues Object) aufgebaut wird. Daher kommt das Blockieren des Verbindungsobjects (also der Verbindung) nicht in Frage. Denn jeder Aufruf vom Servlet hat dann ein eigenes Object auf die Datenbank. So blockiert jedes Servlet eigene Verbindung und das ganze hat keinen Sinn.
Die Datenbank (Hinweis vorhin) ist nicht zu blocken , zumindest kenne ich sowas nicht, denn sie läuft eigenständig wo auch immer - ich bekomme die Verbindungsdaten über eine Property Datei.
Vielleicht verstehe ich ja nicht ganz die Servlets - bin offen für alles.


Gruß,
darom

mwanaheri
14-03-2005, 23:30
Wenn du die Datenbank nicht tabellenweise blocken kannst (ist eine Eigenschaft der Datenbank, sie läuft derweil weiter), nimm einfach eine Sperrtabelle.
Lege eine Tabelle an mit den Feldern
tabname | PK | <weitere Infos, die du brauchen kannst>
In der Tabelle bilden tabname und PK den Primärschlüssel.

Soll nun ein Applet in die Anmeldetabelle schreiben, so versucht es erst, in die Sperrtabelle
anmeldetabelle | pk | <...>
einzutragen. Gelingt das, kann es in die Anmeldetabelle schreiben.
Schlägt es fehl, so ist der entsprechende Datensatz PK in der Tabelle tabname offenbar schon gesperrt. (Dafür die Sache mit dem kombinierten Primärschlüssel). Das Applet kann dann eine andere Nummer suchen oder die Aktion abbrechen. Soll ein Datensatz in der Anmeldetabelle wieder freigegeben werden, so lösche einfach den Eintrag aus der Sperrtabelle.

peschmae
15-03-2005, 07:59
Synchronized heisst ich muss ein Object auf die Datenbankverbindung haben. Diese Lösung kommt glaube ich nicht in Frage weil mit jedem Aufruf eines Servlets man davon ausgehen muss dass eine neue Verbindung (also auch ein neues Object) aufgebaut wird.

Stimmt, hatte nicht so weit gelesen bis ich gesehen hätte dass es da mehere hat...

MfG Peschmä

gaansch
15-03-2005, 13:21
Was ist denn, wenn du das Objekt zum Datenbankzugriff als Singleton implementierst. Dann hast du für jeden Thread immer das selbe Objekt und kannst somit einzelne Methoden als synchronized deklarieren. Das klappt allerdings nur, wenn alle Servlets in der selben VM laufen.