Fonctionnement du synchronized
mot-clé Java
Lorsque vous ajoutez le synchronized
mot - clé à une méthode statique, la méthode ne peut être appelée que par un seul thread à la fois.
Dans votre cas, chaque appel de méthode:
- créer un nouveau
SessionFactory
- créer un nouveau
Session
- chercher l'entité
- renvoyer l'entité à l'appelant
Cependant, voici vos exigences:
- Je veux que cela empêche l'accès aux informations de la même instance de base de données.
- éviter d'
getObjectById
être appelé pour toutes les classes lorsqu'il est appelé par une classe particulière
Ainsi, même si la getObjectById
méthode est thread-safe, l'implémentation est incorrecte.
SessionFactory
les meilleures pratiques
Le SessionFactory
est thread-safe, et c'est un objet très coûteux à créer car il doit analyser les classes d'entité et construire la représentation du métamodèle d'entité interne.
Donc, vous ne devriez pas créer le SessionFactory
à chaque getObjectById
appel de méthode.
Au lieu de cela, vous devez créer une instance singleton pour elle.
private static final SessionFactory sessionFactory = new Configuration()
.configure()
.buildSessionFactory();
Le Session
devrait toujours être fermé
Vous n'avez pas fermé le Session
dans un finally
bloc, ce qui peut entraîner une fuite des ressources de la base de données si une exception est levée lors du chargement de l'entité.
Selon la Session.load
méthode, JavaDoc peut lancer un HibernateException
si l'entité est introuvable dans la base de données.
Vous ne devez pas utiliser cette méthode pour déterminer si une instance existe (utilisez à la get()
place). Utilisez ceci uniquement pour récupérer une instance dont vous supposez qu'elle existe, où la non-existence serait une erreur réelle.
C'est pourquoi vous devez utiliser un finally
bloc pour fermer le Session
, comme ceci:
public static synchronized Object getObjectById (Class objclass, Long id) {
Session session = null;
try {
session = sessionFactory.openSession();
return session.load(objclass, id);
} finally {
if(session != null) {
session.close();
}
}
}
Empêcher l'accès multi-thread
Dans votre cas, vous vouliez vous assurer qu'un seul thread ait accès à cette entité particulière.
Mais le synchronized
mot - clé empêche seulement deux threads d'appeler getObjectById
simultanément. Si les deux threads appellent cette méthode l'un après l'autre, vous aurez toujours deux threads utilisant cette entité.
Ainsi, si vous souhaitez verrouiller un objet de base de données donné afin qu'aucun autre thread ne puisse le modifier, vous devez utiliser des verrous de base de données.
Le synchronized
mot-clé ne fonctionne que dans une seule JVM. Si vous disposez de plusieurs nœuds Web, cela n'empêchera pas l'accès multi-thread sur plusieurs JVM.
Ce que vous devez faire est d'utiliser LockModeType.PESSIMISTIC_READ
ouLockModeType.PESSIMISTIC_WRITE
lors de l'application des modifications à la base de données, comme ceci:
Session session = null;
EntityTransaction tx = null;
try {
session = sessionFactory.openSession();
tx = session.getTransaction();
tx.begin();
Post post = session.find(
Post.class,
id,
LockModeType.LockModeType.PESSIMISTIC_READ
);
post.setTitle("High-Performance Java Perisstence");
tx.commit();
} catch(Exception e) {
LOGGER.error("Post entity could not be changed", e);
if(tx != null) {
tx.rollback();
}
} finally {
if(session != null) {
session.close();
}
}
Alors, voici ce que j'ai fait:
- J'ai créé une nouvelle
EntityTransaction
et commencé une nouvelle transaction de base de données
- J'ai chargé l'
Post
entité tout en maintenant un verrou sur l'enregistrement de base de données associé
- J'ai changé d'
Post
entité et commis la transaction
- Dans le cas d'un
Exception
rejet, j'ai annulé la transaction
Pour plus de détails sur les transactions ACID et de base de données, consultez également cet article .