2010-03-15 38 views
7

Corrígeme si algo está mal.DAO, Spring e Hibernate

Ahora cuando usamos Spring DAO para plantillas ORM, cuando usamos el atributo @Transactional, , no tenemos control sobre la transacción y/o sesión cuando el método se llama externamente, no dentro del método.

La carga diferida ahorra recursos, menos consultas al db, menos memoria para mantener todas las colecciones recuperadas en la memoria de la aplicación.

Por lo tanto, si lazy = false, todo se recupera, todas las colecciones asociadas, eso no es efectivo, si hay 10,000 registros en un conjunto vinculado.

Ahora, tengo un método en una clase DAO que se supone que me devuelve un objeto User. Tiene colecciones que representan tablas vinculadas de la base de datos. Necesito obtener un objeto por identificación y luego consultar sus colecciones.

La excepción Hibernate "no se pudo inicializar lazmente una colección" se produce cuando intento acceder a la colección vinculada que devuelve este método DAO.

Explique por favor, ¿qué es una solución aquí?

Actualización: Bien, déjame preguntarte esto. DAO es una capa abstracta, por lo que se supone que un método "getUserById (Id. De enteros)" devuelve un Objeto.

¿Qué pasa si en algunos casos necesito estas colecciones vinculadas del objeto Usuario y en otra situación necesito esas colecciones.

hay sólo dos maneras: 1) la carga diferida = false 2) crear diferentes métodos: getUserByIdWithTheseCollections(),() getUserByIdWithOtherCollections y dentro de esos métodos utilizar su enfoque?

Quiero decir, ¿hay solo 2 formas y nada mejor?

Actualización 2: Explique por favor, ¿qué me daría el uso explícito de SESSIONFACTORY? ¿Cómo se ve en la práctica? Creamos una instancia de objeto DAO, y luego lo inyectamos con la fábrica de sesiones y esto significa que dos llamadas consecuentes al método a DAO se ejecutarán dentro de la misma transacción. Me parece que, de todos modos, ¡DAO está separado de las clases que lo usan!

La lógica y las transacciones están encapsuladas dentro de DAO, ¿verdad?

Respuesta

6

Usted puede obtener la colección vinculado en la transacción para cargarla mientras está todavía dentro de la transacción:

User user = sessionFactory.getCurrentSession().get(User.class, userId); 
user.getLinkedCollection().size(); 
return user; 

Como BalusC ha señalado, se puede utilizar en lugar de Hibernate.initialize()size(). Eso es mucho más limpio.

Luego, cuando devuelve dicha entidad, el campo diferido ya está inicializado.

Respondiendo a su PS: ¿es factible usar transacciones a nivel de servicio (en lugar de DAO)? Parece ser así, ya que hacer cada llamada DAO en una transacción por separado parece ser un desperdicio (y puede ser incorrecto).

+0

@Konrad Garus Por favor, vea mi posdata de la pregunta, aquí el texto es menos legible, así que le pregunto allí. – EugeneP

+0

@EugeneP Ver respuesta actualizada. –

5

Me parece que es mejor poner @Transactional en la capa de servicio, en lugar de la capa DAO. De lo contrario, todas sus llamadas DAO estarán en sesiones separadas de hibernación; todo lo relacionado con la igualdad de objetos no funcionará.

+1

Esta es una buena forma de manejarlo cuando se trabaja con SpringDAO. –

1

En mi opinión, la mejor manera de resolver este problema será diseñar la aplicación en un modelo de sesión por solicitud. Entonces, si incluso tiene un objeto extraído de DAO, hasta que funcione su patrón OSIV, puede usar el objeto de forma segura en cualquier lugar de la aplicación, incluso en las vistas sin molestarse en este aspecto. Esta es probablemente una mejor solución que los propuestos porque:

  1. Hibernate.initialize() o el tamaño es una solución muy artificial - ¿y si usted quiere tener usuarios con diferentes colección inicializado, escribirías otro método para obtener usuario?
  2. Servicio capa del modelo transaccional está bien, pero el mismo problema viene cuando se quiere obtener el objeto extraído de la capa de servicio para usarlo en el controlador o ver
1

Se podría hacer algo como lo siguiente:

public User getByUserId(Long id, String ... fetch) { 
    Criteria criteria = createCriteria(); 

    if (fetch != null) { 
     for (String fieldName : fetch) { 
      criteria.setFetchMode(fieldName, FetchMode.JOIN); // fetch these fields eagerly 
     } 
    } 
    return criteria.add(Restrictions.eq("id", id)).list(); 
} 
Cuestiones relacionadas