Cómo funciona la synchronized
palabra clave Java
Cuando agrega la synchronized
palabra clave a un método estático, el método solo puede ser llamado por un solo hilo a la vez.
En su caso, cada llamada al método:
- crear un nuevo
SessionFactory
- crear un nuevo
Session
- buscar la entidad
- devolver la entidad a la persona que llama
Sin embargo, estos fueron sus requisitos:
- Quiero que esto evite el acceso a la información a la misma instancia de DB.
- evitar que
getObjectById
se llame para todas las clases cuando una clase particular lo llama
Entonces, incluso si el getObjectById
método es seguro para subprocesos, la implementación es incorrecta.
SessionFactory
mejores prácticas
El SessionFactory
es seguro para subprocesos, y es un objeto muy costoso crear, ya que necesita para analizar las clases de entidad y construir la representación interna entidad metamodelo.
Por lo tanto, no debe crear la llamada SessionFactory
a cada getObjectById
método.
En su lugar, debe crear una instancia singleton para ello.
private static final SessionFactory sessionFactory = new Configuration()
.configure()
.buildSessionFactory();
El Session
siempre debe estar cerrado
No cerró el Session
en un finally
bloque, y esto puede filtrar recursos de la base de datos si se produce una excepción al cargar la entidad.
Según el Session.load
método, JavaDoc podría arrojar un HibernateException
si la entidad no se puede encontrar en la base de datos.
No debe usar este método para determinar si existe una instancia (use get()
en su lugar). Use esto solo para recuperar una instancia que usted supone que existe, donde la inexistencia sería un error real.
Es por eso que necesita usar un finally
bloque para cerrar Session
, como este:
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();
}
}
}
Prevención de acceso multihilo
En su caso, quería asegurarse de que solo un hilo tenga acceso a esa entidad en particular.
Pero la synchronized
palabra clave solo evita que dos hilos llamen al getObjectById
mismo tiempo. Si los dos hilos llaman a este método uno después del otro, aún tendrá dos hilos usando esta entidad.
Entonces, si desea bloquear un objeto de base de datos dado para que ningún otro hilo pueda modificarlo, entonces necesita usar bloqueos de base de datos.
La synchronized
palabra clave solo funciona en una sola JVM. Si tiene varios nodos web, esto no impedirá el acceso de subprocesos múltiples en varias JVM.
Lo que debe hacer es usar LockModeType.PESSIMISTIC_READ
oLockModeType.PESSIMISTIC_WRITE
aplicar los cambios a la base de datos, de esta manera:
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();
}
}
Entonces, esto es lo que hice:
- Creé una nueva
EntityTransaction
y comencé una nueva transacción de base de datos
- Cargué la
Post
entidad mientras mantenía un bloqueo en el registro de la base de datos asociada
- Cambié la
Post
entidad y comprometí la transacción.
- En caso de
Exception
ser arrojado, revertí la transacción
Para obtener más detalles sobre ACID y las transacciones de la base de datos, consulte también este artículo .