Wenn ich eine util-Klasse mit statischen Methoden habe, die Hibernate-Funktionen aufruft, um den grundlegenden Datenzugriff zu erreichen. Ich frage mich, ob die Herstellung der Methode synchronized
der richtige Ansatz ist, um die Gewindesicherheit zu gewährleisten.
Ich möchte, dass dies den Zugriff von Informationen auf dieselbe DB-Instanz verhindert. Ich bin mir jetzt jedoch sicher, ob der folgende Code verhindert, getObjectById
dass für alle Klassen aufgerufen wird, wenn er von einer bestimmten Klasse aufgerufen wird.
public class Utils {
public static synchronized Object getObjectById (Class objclass, Long id) {
// call hibernate class
Session session = new Configuration().configure().buildSessionFactory().openSession();
Object obj = session.load(objclass, id);
session.close();
return obj;
}
// other static methods
}
For a class (static) method, the monitor associated with the Class object for the method's class is used. For an instance method, the monitor associated with this (the object for which the method was invoked) is used.
Wenn also ein Thread eine statische Methode eintritt, dasselbe Objekt von zurück Objekt # getClass ist gesperrt. Andere Threads können weiterhin auf Instanzmethoden zugreifen.Class
Objekt, das von einem der Klassenladeprogramme für virtuelle Maschinen instanziiert wird. Wie alle Objekte ist auch diesem Objekt ein ObjektMonitor
zugeordnet. Und dieser Monitor wird gesperrt.Um die Frage allgemeiner zu beantworten ...
Beachten Sie, dass die Verwendung synchronisierter Methoden nur eine Abkürzung ist (vorausgesetzt, die Klasse ist SomeClass):
ist das gleiche wie
und
ist das gleiche wie
Sie können jedes Objekt als Sperre verwenden. Wenn Sie Teilmengen statischer Methoden sperren möchten, können Sie dies tun
(Bei nicht statischen Methoden möchten Sie, dass die Sperren nicht statische Felder sind.)
quelle
Statische Methoden verwenden die Klasse als Objekt zum Sperren. In Ihrem Beispiel ist dies Utils.class. Also ja, es ist OK.
quelle
static synchronized
bedeutet, dasClass
Objekt der Klasse zusynchronized
sperren, wobei das Objekt dieser Klasse selbst gesperrt bleibt. Das heißt, wenn Sie in einem Thread (der Ausführung) auf eine nicht statisch synchronisierte Methode zugreifen, können Sie weiterhin mit einem anderen Thread auf eine statisch synchronisierte Methode zugreifen.Daher ist es zu keinem Zeitpunkt mehr als einem Thread möglich, auf zwei gleiche Arten von Methoden (entweder zwei statische oder zwei nicht statische Methoden) zuzugreifen.
quelle
Warum möchten Sie erzwingen, dass jeweils nur ein Thread auf die Datenbank zugreifen kann?
Es ist die Aufgabe des Datenbanktreibers , alle erforderlichen Sperren zu implementieren, vorausgesetzt, a
Connection
wird jeweils nur von einem Thread verwendet!Höchstwahrscheinlich kann Ihre Datenbank mehrere parallele Zugriffe ausführen
quelle
Wenn dies mit den Daten in Ihrer Datenbank zu tun hat, können Sie die Sperre der Datenbankisolation verwenden, um dies zu erreichen.
quelle
Ja, um Ihre Frage zu beantworten: Ihre
synchronized
Methode kann nicht von mehr als einem Thread gleichzeitig ausgeführt werden.quelle
Wie das
synchronized
Java-Schlüsselwort funktioniertWenn Sie das
synchronized
Schlüsselwort zu einer statischen Methode hinzufügen , kann die Methode jeweils nur von einem einzelnen Thread aufgerufen werden.In Ihrem Fall wird jeder Methodenaufruf:
SessionFactory
Session
Dies waren jedoch Ihre Anforderungen:
getObjectById
dass für alle Klassen aufgerufen wird, wenn es von einer bestimmten Klasse aufgerufen wirdSelbst wenn die
getObjectById
Methode threadsicher ist, ist die Implementierung falsch.SessionFactory
empfohlene VorgehensweiseDas
SessionFactory
ist threadsicher und es ist ein sehr teures Objekt, das erstellt werden muss, da die Entitätsklassen analysiert und die interne Entitätsmetamodelldarstellung erstellt werden müssen.Sie sollten also nicht
SessionFactory
bei jedemgetObjectById
Methodenaufruf das erstellen .Stattdessen sollten Sie eine Singleton-Instanz dafür erstellen.
Das
Session
sollte immer geschlossen seinSie haben das
Session
in einemfinally
Block nicht geschlossen, und dies kann zu Datenbankressourcen führen, wenn beim Laden der Entität eine Ausnahme ausgelöst wird.Gemäß der
Session.load
Methode kann JavaDoc ein auslösen ,HibernateException
wenn die Entität nicht in der Datenbank gefunden werden kann.Aus diesem Grund müssen Sie einen
finally
Block verwenden, um das zu schließenSession
:Multithread-Zugriff verhindern
In Ihrem Fall wollten Sie sicherstellen, dass nur ein Thread Zugriff auf diese bestimmte Entität erhält.
Das
synchronized
Schlüsselwort verhindert jedoch nur, dass zwei ThreadsgetObjectById
gleichzeitig aufrufen . Wenn die beiden Threads diese Methode nacheinander aufrufen, haben Sie immer noch zwei Threads, die diese Entität verwenden.Wenn Sie also ein bestimmtes Datenbankobjekt sperren möchten, damit kein anderer Thread es ändern kann, müssen Sie Datenbanksperren verwenden.
Das
synchronized
Schlüsselwort funktioniert nur in einer einzelnen JVM. Wenn Sie mehrere Webknoten haben, wird dadurch der Multithread-Zugriff über mehrere JVMs nicht verhindert.Sie müssen die Änderungen wie folgt verwenden
LockModeType.PESSIMISTIC_READ
oderLockModeType.PESSIMISTIC_WRITE
anwenden:Also, das habe ich getan:
EntityTransaction
und eine neue Datenbanktransaktion gestartetPost
Entität geladen , während ich den zugehörigen Datenbankeintrag gesperrt habePost
Entität geändert und die Transaktion festgeschriebenException
Werfens habe ich die Transaktion zurückgesetztquelle