Cómo funciona la synchronizedpalabra clave Java
Cuando agrega la synchronizedpalabra 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
getObjectByIdse llame para todas las clases cuando una clase particular lo llama
Entonces, incluso si el getObjectByIdmétodo es seguro para subprocesos, la implementación es incorrecta.
SessionFactory mejores prácticas
El SessionFactoryes 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 SessionFactorya cada getObjectByIdmétodo.
En su lugar, debe crear una instancia singleton para ello.
private static final SessionFactory sessionFactory = new Configuration()
.configure()
.buildSessionFactory();
El Sessionsiempre debe estar cerrado
No cerró el Sessionen un finallybloque, y esto puede filtrar recursos de la base de datos si se produce una excepción al cargar la entidad.
Según el Session.loadmétodo, JavaDoc podría arrojar un HibernateExceptionsi 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 finallybloque 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 synchronizedpalabra clave solo evita que dos hilos llamen al getObjectByIdmismo 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 synchronizedpalabra 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_READoLockModeType.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
EntityTransactiony comencé una nueva transacción de base de datos
- Cargué la
Postentidad mientras mantenía un bloqueo en el registro de la base de datos asociada
- Cambié la
Postentidad y comprometí la transacción.
- En caso de
Exceptionser 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 .