java - generic - Gestión de transacciones en Hibernate con el patrón de diseño DAO
hibernate java ejemplo (4)
No es necesario usar frameworks, el objeto CancelPolicy es el objeto principal y debe tener la función de hibernación (cascada) Verificar el enlace ( ciclo de vida en cascada )
Así que llenas el objeto CancelPolicy con todas las relaciones requeridas, y dices guardar, guardará todo el gráfico de los objetos relacionados.
Tengo muchas tablas, para cada tabla, tenemos la interfaz DAO y la clase DAOImplementation.
Ejemplo de interfaz DAO
public interface CancelPolicyDAO {
public CancelPolicy insertCancelPolicy(CancelPolicy cpdao)throws ChannelDispatcherException;
public CancelPolicy updateCancelPolicy(CancelPolicy cpdao)throws ChannelDispatcherException;
public void deleteCancelPolicy(CancelPolicy cpdao)throws ChannelDispatcherException;
public CancelPolicy findByCancelPolicyData(Integer id, Integer offSetUM, Integer nights, Float pOrAm, Byte isPercent)throws ChannelDispatcherException;
public CancelPolicy findByCancelPolicyId(Integer id)throws ChannelDispatcherException;
}
Ejemplo de clase DAOImplementation
public class CancelPolicyDAOImpl implements CancelPolicyDAO {
@Override
public CancelPolicy insertCancelPolicy(CancelPolicy bean) throws ChannelDispatcherException {
Session ses = null;
try {
ses = HibernateConnector.getInstance().getSession();
ses.save(bean);
ses.flush();
return bean;
} catch (Exception e) {
e.printStackTrace();
throw new ChannelDispatcherException(DbUtil.getStackTraceMessage(e));
} finally {
if (ses != null) {
try {
ses.close();
} catch (Exception er) {
er.printStackTrace();
}
}
}
}
@Override
public CancelPolicy updateCancelPolicy(CancelPolicy bean) throws ChannelDispatcherException {
Session sess = null;
try {
sess = HibernateConnector.getInstance().getSession();
sess.update(bean);
sess.flush();
return bean;
} catch (Exception e) {
e.printStackTrace();
throw new ChannelDispatcherException(DbUtil.getStackTraceMessage(e));
}
}
@Override
public void deleteCancelPolicy(CancelPolicy bean) throws ChannelDispatcherException {
Session sess = null;
try {
sess = HibernateConnector.getInstance().getSession();
sess.delete(bean);
sess.flush();
} catch (Exception e) {
e.printStackTrace();
throw new ChannelDispatcherException(DbUtil.getStackTraceMessage(e));
}
}
@Override
public CancelPolicy findByCancelPolicyData(Integer id, Integer offSetUM, Integer nights, Float pOrAm, Byte isPercent) throws ChannelDispatcherException {
Session ses = null;
try {
ses = HibernateConnector.getInstance().getSession();
Query query = ses.createQuery("from CancelPolicy a where "
+ " a.cancelPolicyTypeId =:cancelPolicyTypeId "
+ " and a.offsetUnitMultiplier =:offsetUnitMultiplier "
+ " and a.nights =:nights "
+ " and a.percentOramount =:percentOramount "
+ " and a.isPercent =:isPercent");
query.setParameter("cancelPolicyTypeId", id);
query.setParameter("offsetUnitMultiplier", (offSetUM));
query.setParameter("nights", (nights));
query.setParameter("percentOramount", pOrAm);
query.setParameter("isPercent", isPercent);
List queryList = query.list();
if (queryList != null && queryList.isEmpty()) {
return null;
} else {
return (CancelPolicy) queryList.get(0);
}
} catch (Exception e) {
e.printStackTrace();
throw new ChannelDispatcherException(DbUtil.getStackTraceMessage(e));
} finally {
if (ses != null) {
try {
ses.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
public CancelPolicy findByCancelPolicyId(Integer id) throws ChannelDispatcherException {
Session ses = null;
try {
ses = HibernateConnector.getInstance().getSession();
Query query = ses.createQuery("from CancelPolicy a where "
+ " a.id =:id ");
query.setParameter("id", id);
List queryList = query.list();
if (queryList != null && queryList.isEmpty()) {
return null;
} else {
return (CancelPolicy) queryList.get(0);
}
} catch ( Exception e) {
e.printStackTrace();
throw new ChannelDispatcherException(DbUtil.getStackTraceMessage(e));
} finally {
if (ses != null) {
try {
ses.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
Ejemplo de método principal
public static void main(String[] args) {
// How to handel Transaction in Hibernate ?
CancelPolicyDAO cancelPolicyDAO = HibernateDAOFactory.getInstance().getCancelPolicyDAO();
CancelPolicy insertCancelPolicy = cancelPolicyDAO.findByCancelPolicyData(2, 76, 25, 25.36f, 3);
if(insertCancelPolicy==null){
CancelPolicy cancelPolicy = new CancelPolicy();
cancelPolicy.setCancelPolicyTypeId(1);
cancelPolicy.setNights(2);
insertCancelPolicy = cancelPolicyDAO.insertCancelPolicy(cancelPolicy);
}
Integer autoIncrementId = insertCancelPolicy.getId();
AvailabilityDAO availabilityDAO = HibernateDAOFactory.getInstance().getAvailabilityDAO();
Availability availability = new Availability();
// using CancelPolicy autoIncrementId
availability.setId(autoIncrementId);
availability.setCount(2);
availability.setMaxLos(5);
availabilityDAO.insertAvailability(availability);
.
.
.
.
.
}
Ahora mi pregunta es ¿cómo manejo la transacción en DAOImpl''s? ¿Debo pasar Session Object como parámetro para cada DAOImpl o hay algún mejor enfoque?
Recomiendo encarecidamente no reinventar la rueda; use un código existente, robusto y probado.
Los comentarios ya mencionaron AOP y el marco Spring . Este es el camino a seguir. El framework Spring incluso tiene un subproyecto llamado Spring Data que le permite definir sus métodos de búsqueda (como findByCancelPolicyData
) de manera declarativa.
Esto te ahorrará mucho trabajo.
Si por alguna razón no quiere / no puede utilizar Spring, aún puede leer la increíblemente buena documentación del marco base y los Spring Data mencionados con el fin de obtener muchas ideas excelentes, con respecto al código de transacción (a través de AOP) reutilización (a través de DAO genéricos) o diseño de API. No te pierdas esta lectura.
Si bien usar Spring es probablemente la mejor manera de agregar administración de transacciones, aún puede resolverlo incluso sin volver a factorizar todo su código base.
Lo que debe hacer es establecer la siguiente configuración:
hibernate.current_session_context_class=thread
Sus DAO deben acceder a la Sesión a través de:
[SessionFactory.getCurrentSession()][1];
Aún necesita declarar límites de transacción en su capa de servicio:
Session sess = factory.openSession();
Transaction tx = null;
try {
tx = sess.beginTransaction();
dao1.find();
dao2.save(entity);
tx.commit();
}
catch (RuntimeException e) {
if (tx != null) tx.rollback();
throw e;
}
finally {
sess.close();
}
Tanto el dao1 como el dao2 usarán la misma sesión de Hibernate y la misma transacción.
Para evitar este detallado manejo de código de gestión de transacciones, puede escribir una sencilla utilidad de TransactionManager como:
pubic static abstract class TransactionCallable<T> {
public abstract T execute();
}
public class TransactionManager {
pubic static <T> T doInTransaction(TransactionCallable<T> callable) {
T result = null;
Session session = null;
Transaction txn = null;
try {
session = sf.openSession();
txn = session.beginTransaction();
result = callable.execute();
txn.commit();
} catch (RuntimeException e) {
if ( txn != null && txn.isActive() ) txn.rollback();
throw e;
} finally {
if (session != null) {
session.close();
}
}
return result;
}
}
Y así es como se verá un servicio:
TransactionManager.doInTransaction(new TransactionCallable<Void>() {
@Override
public Void execute() {
dao1.find();
dao2.save(entity);
}
});
Si tiene una aplicación web y no está utilizando la primavera en su proyecto para session mgmt , le sugiero que use el interceptor para separar la lógica de manejo de la sesión fuera de su DAO. Puede consultar el artículo mencionado a continuación para el mismo. Tenga en cuenta que hay ciertos CON asociados con este enfoque, pero hemos encontrado que es la forma más conveniente en nuestro caso.
Sesión abierta en el patrón de vista
A continuación se muestra el ejemplo de cómo estamos usando la sesión abierta en el patrón Vista con genéricos, para su clase que podemos tener,
public class CancelPolicyDAOImpl extends GenericDAOImpl<CancelPolicy, Long> implements CancelPolicyDAO {
@Override
public CancelPolicy insertCancelPolicy(CancelPolicy bean) throws ChannelDispatcherException {
try {
// save method is implemented in GenericDAOImpl described below.
return save(bean);
} catch (Exception e) {
e.printStackTrace();
}
}
//remaining methods
}
En el ejemplo anterior se usa el método de guardar código que se implementa en GenericHibernateDAOImpl como se muestra a continuación. Puede buscar en Google la clase GenericHibernateDAOImpl y tomarla, que tiene una cantidad de métodos adicionales para las operaciones básicas.
public abstract class GenericDAOImpl<T, ID extends Serializable> {
private Session session;
public T save(final T entity) {
Transaction trans = null;
try {
trans = session.beginTransaction();
session.saveOrUpdate(entity);
session.flush();
trans.commit();
} catch (Exception ex) {
rollBackTransaction(trans);
// you might require to throw error again here
}
return entity;
}
//in case any complex operations required you can get core session object from this method
protected Session getSession() {
return sessionFactory.getCurrentSession();
}
}
Ahora volvamos a su pregunta sobre dónde obtener la sesión, como se muestra arriba. La sesión GenericHibernateDAOImpl se recupera de singleton sessionFactory a través del método getCurrentSession. Tenga en cuenta que deberá ejecutar una transacción activa antes de obtener la sesión actual, que puede poner a disposición en su interceptor (enlace proporcionado al comienzo de esta publicación).
Por favor hagamelo saber.