Sesiones en Hibernate Vs Sesiones en Spring

Embarcado en el desarrollo del servicio de workflow de OCAS y en su implementación con JBPM me he tropezado (de nuevo) con un iceberg: las sesiones de Hibernate y el cómodo/incómodo lazy loading. Existe en javahispano un estupendo artículo de Martín sobre las sesiones y las transacciones de Hibernate que recomiendo a todo el mundo; pero intentaré resumir aquí cuál es el problema (a ver si lo consigo).

El lazy loading o carga perezosa es un mecanismo que hibernate implementa para tratar algunas relaciones. Una entidad (POJO que se persiste en una tabla de la BD) puede tener múltiples relaciones con otras entidades (por ejemplo, un producto puede tener una Collection de los comerciales que lo venden). A veces cuando nos traemos datos de la BD no nos interesa cargar toda la información relacionada ya que sólo vamos a usar o mostrar una parte. Así que, siguiendo con el ejemplo, si queremos mostrar el número de referencia de un producto y su nombre en una interfaz de usuario, cargar los datos de los veinte comerciales que lo venden en memoria ocupa espacio innecesariamente.
Usando el lazy loading, si definimos una relación como lazy (poniendo el atributo de la relación lazy a true en los mappings de hibernate), Sólo se cargará la información de los vendedores CUANDO accedamos a la Collection vendedores. Así por ejemplo:

producto.getVendedores(2).getName();



lo que provocará es un nuevo acceso a la base de datos para cargar la información de los vendedores. Llamarlo carga perezosa obedece a que no hemos tenido que escribir las líneas de código para traerlo de la base de datos: hasta que no hagamos uso de esa relación no se cargará en memoria, y cuando hagamos uso de ella “automágicamente” se traerá la información desde la base de datos. Por tanto para el programador resulta un mecanismo muy cómodo que permite realizar aplicaciones que aprovechan muy bien la memoria, sin cargar datos innecesarios hasta el momento que son necesarios.


EL PRECIO DEL LAZY LOADING
Claro está que cuando he escrito automágicamente nadie habrá pensado en Gandalf trayendo nuestros datos. Lo que hace hibernate es crear una clase wrapper de nuestra Collection y asociarla al objeto (por ejemplo un Set de vendedores). Estas clases wrapper actúan como un proxy: son clases herederas de las correspondientes Collection cuyos métodos están sobreescritos por los chicos de hibernate y lo que hacen es traer de la base de datos la entidad correspondiente. Pero para traer algo de una base de datos en Hibernate ES NECESARIO que la misma sesión de Hibernate en la que te has cargado el objeto original esté abierta. Y no se te ocurra pedir a los de hibernate que se pueda hacer abriendo una nueva sesión (sino quieres que se mofen de ti) porque como explican aquí se cargarían el concepto de transacción.

Hibernate sólo puede asegurar que el objeto original existe dentro de la misma transacción/sesión, por lo que si abres una nueva sesión deberás volver a cargar el objeto original y luego su Collection de entidades relacionadas.
Y aquí es cuando empiezan los problemas ;-)


ERRORES DE NOVATO EN HIBERNATE
Hace un año, para un proyecto que me tocó decidí utilizar hibernate para matar dos pájaros de un tiro (el proyecto era pequeño y así yo aprendía a usar hibernate). Tranquilos, pagué mi audacia con muchas horas de lectura de manuales y artículos :-D


Todo ufano cree un montón de relaciones lazy porque así mi aplicación web iba a ser la leche en verso (sólo en memoria lo que necesitara). Cuando llegué a mi primer jsp en el que además de datos de un producto de un almacén debía mostrar el nombre de su encargado (relación lazy por supuesto, ya que el encargado igual llevaba 700 piezas) me saltó la bonita LazyLoadingException. Vale, oh que tonto soy, el nombre del encargado viene a través de una carga perezosa y yo he cerrado la sesión de Hibernate al traer el producto. Pero…. glups!, si el único sitio en el que hago producto.getEncargado().getNombre() es en la página JSP!! Y yo abro la sesión en mi DAO y allí debería cerrarla (como chico aplicado y cumplidor que soy ;-)). ¿Que hago? ¿Le paso a la página jsp la sesión para que la cierre en cuanto me traiga el nombre del encargado? ¿Me tiro en postura fetal y espero que Dios arregle mi código? :-D


Tras secar el sudor frío de mi frente, me agencié “Hibernate in Action” el libro escrito por los desarrolladores de Hibernate y me puse a indagar cómo solucionaban ellos este problema.

Patrones, anti-patrones y opiniones
Vale, pues en Hibernate 2.1 (luego hablamos de la 3 que esto va para largo) explican claramente los distintos patrones que hay (y que Martín explica excelentemente en su artículo, leedlo!), recomendando el patrón session-per-request: por cada petición del cliente se abre una sesión, se trae de la BD lo que se tenga que traer y se cierra la sesión.


El tema está en ¿cómo lo implementamos en una aplicación web? Bueno pues en Hibernate 2.1 proponen una clase (HibernateUtil) que usando variables ThreadLocal (explicación de las poco conocidas variables ThreadLocal ) consiguen la magia, haciendo que cada petición (que en una aplicación web genera un thread) tenga a su disposición la creación de sesiones. Un pequeño resumen de la clase a continuación:

public class HibernateUtil {
    private static Configuration configuration;
    private static SessionFactory sessionFactory;
    private static final ThreadLocal threadSession = new ThreadLocal();
    private static final ThreadLocal threadTransaction = new ThreadLocal();
    private static final ThreadLocal threadInterceptor = new ThreadLocal();
    (...)

    /**
     * Retrieves the current Session local to the thread.
     *
     * If no Session is open, opens a new Session for the running thread.
     *
     * @return Session
     */
   public static Session getSession() throws InfrastructureException {
        Session s = (Session) threadSession.get();
        try {
            if (s == null) {
                if (getInterceptor() != null) {
                    s = getSessionFactory().openSession(getInterceptor());
                } else {
                    s = getSessionFactory().openSession();

                }
                threadSession.set(s);
            }
        } catch (HibernateException ex) {
            throw new InfrastructureException(ex);
        }
        return s;
    }

    /**
     * Closes the Session local to the thread.
     */
    public static void closeSession()throws InfrastructureException {
        try {
            Session s = (Session) threadSession.get();
            threadSession.set(null);
            if (s != null && s.isOpen()) {
                s.close();
            }
        } catch (HibernateException ex) {
            throw new InfrastructureException(ex);
        }
    }

(...)
/**
     * Register a Hibernate interceptor with the current thread.
     *
     * Every Session opened is opened with this interceptor after
     * registration. Has no effect if the current Session of the
     * thread is already open, effective on next close()/getSession().
     */
    public static void registerInterceptor(Interceptor interceptor) {

        threadInterceptor.set(interceptor);
    }

    private static Interceptor getInterceptor() {
        Interceptor interceptor = (Interceptor) threadInterceptor.get();
        return interceptor;
    }


No he posteado la creación de la SessionFactory (se crea en un bloque de código estático), pero creo que el código se explica sólo ;-) Con este código es posible definir un Interceptor en Hibernate, que será llamado al abrir o cerrar una sesión, para hacer lo que queramos en esos eventos.


Y un pequeño ejemplo de código donde se usa (por ejemplo dentro de un DAO):

HibernateUtil.beginTransaction()
Query query = HibernateUtil.getSession().getNamedQuery("query1");
result = query.setEntity("usuario", usuario).list();
return result;


Uopss!! ¿Y donde has dejado el closeTransaction y el closeSession? Pues como decía antes, NO puedo cerrar la sesión en el DAO porque eso me quitaría la posibilidad de acceder a las relaciones lazy desde mi página jsp. Según el patrón sesion-per-request, la sesión se cerrará cuando toda la información se haya enviado y dibujado en la interfaz del usuario. Y en una aplicación web el sitio para hacerlo es un filtro de Servlet, que se ejecuta cuando la página jsp ya ha terminado de dibujar la pantalla. Como muestra un botón:

public class HibernateFilter implements Filter {


    private static Log log = LogFactory.getLog(HibernateFilter.class);

    public void init(FilterConfig filterConfig) throws ServletException {
        log.info("Servlet filter init, now opening/closing a Session for each request.");
    }


    public void doFilter(ServletRequest request,
                         ServletResponse response,
                         FilterChain chain)
            throws IOException, ServletException {


        // There is actually no explicit "opening" of a Session, the
        // first call to HibernateUtil.beginTransaction() in control
        // logic (e.g. use case controller/event handler) will get

        // a fresh Session.
        try {
            chain.doFilter(request, response);

            // Commit any pending database transaction.

            HibernateUtil.commitTransaction();

        } finally {

            // No matter what happens, close the Session.
            HibernateUtil.closeSession();


        }
    }


De esta forma cuando se haya dibujado la página jsp, se realizará un commit de todos los cambios a la base de datos y se cerraran la sesión que haya abierto el cliente (una sesión por petición).
Existe otra variante que en lugar de cerrar sesiones, las conecta y las desconecta (de la conexión JDBC subyacente).

Esta forma de trabajo, en la que abrimos sesiones en un lado y las cerramos en otro no acabó de convencer a todo el mundo, ni a mí, ya que hace a tu aplicación dependiente de Hibernate, no sólo en los DAO’s sino incluso en la capa de la aplicación web. Con Hibernate 3 el modelo cambió.

HIBERNATE 3: Donde dije Diego..

Como aparece aquí , todo ha cambiado en Hibernate 3, en el que han ampliado la clase SessionFactory con el método getCurrentSession(). Así que ahora podemos tener:

try {
    factory.getCurrentSession().beginTransaction();

    // Do some work
    factory.getCurrentSession().load(...);

    factory.getCurrentSession().persist(...);

    factory.getCurrentSession().getTransaction().commit();
}
catch (RuntimeException e) {
    factory.getCurrentSession().getTransaction().rollback();

    throw e; // or display error message
}



No he mirado el código (el tiempo, ese escaso bien) pero “huele” bastante a que la implementación de ese método usará ThreadLocal internamente como el HibernateUtil.

Para librarnos de abrir y cerrar transacciones, de nuevo el filtro de servlet. Al ejemplo puesto antes ahora lo llaman patrón Open Session in View (¿verdad que es chulo llamar patrón de diseño a toda solución? ;-)) y está descrito aquí . La discusión de porque no crea una “dependencia real” (sic) con Hibernate aquilicuá . Que cada uno saque sus conclusiones, pero ya os aviso del tono de los Hibernate Boys: “si no estás de acuerdo conmigo es porque no tienes ni pajolera idea”. Aunque a veces resulta divertido escuchar a un prepotente, a la larga cansa :-D


En Hibernate 3, y como cada vez se acercan más al estándar EJB 3.0 (¿porqué será? ;-)), también existe la posibilidad de marcar las transacciones no sólo con el filtro de servlet, sino también con JTA. Así definiremos en un descriptor de despliegue (EJB2) o con annotations (EJB3) que determinados métodos que llamamos, requieren el inicio de una transacción, así nuestro código quedará más “bonito”:

 // Do some work
factory.getCurrentSession().load(...);
factory.getCurrentSession().persist(...);


Y tendremos una sesión por transacción (tal y como recomiendan en el patrón sesion-per-request).

Recapitulando:
- O usamos JTA, en un entorno EJB
- O usamos el open session in View, con un filtro de servlet que nos abra transacciones.

Y en eso que llega la “primavera” y a todos la sangre altera ;-)

SPRING/HIBERNATE
Los desarrolladores de Spring en su afan de hacer la vida más fácil a los programadores proporcionaban desde Hibernate 2 unas clases de apoyo para integrar Hibernate en una filosofía IoC. EL SessionFactory de Hibernate se define como un bean en el contexto de la aplicación. Usando XML el bean se define así:


  
  
    

    
    

  
  
    

    
      
        product.hbm.xml
      

    
    
      
        net.sf.hibernate.dialect.MySQLDialect

      
    
  


Y para que nuestros DAO’s tengan acceso a ese SessionFactory:



    
  

Así, el código quedaría:

public class ProductDaoImpl implements ProductDao {
    private SessionFactory sessionFactory;
    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }


Primera gran diferencia: NO necesitamos HibernateUtil. Es más en el manual de referencia lo indican:

We strongly recommend such an instance-based setup over the old-school static HibernateUtil class from Hibernate’s CaveatEmptor sample application! (In general, do not keep any resources in static variables unless absolutely necessary!)


Toma torpedo a la línea de flotación de Gavin King. Y claro luego veremos como se toma las cosas el Gavin ;-D
Para acceder a las sesiones (y por tanto empezar a usar las posibilidades de hibernate) ofrecen varias alternativas:
- Usar la clase HibernateTemplate, que además de tener implementados ciertos métodos útiles (find, load, saveOrUpdate, o delete) permite “callback implementation” (una forma de realizar los punteros a funciones en Java, info ):

public Collection loadProductsByCategory(final String category) throws DataAccessException {
    HibernateTemplate ht = new HibernateTemplate(this.sessionFactory);
    return (Collection) ht.execute(new HibernateCallback() {
        public Object doInHibernate(Session session) throws HibernateException {
            Query query = session.createQuery("from test.Product product where product.category=?");
            query.setString(0, category);
            return query.list();
        }
    });
}


- Usar como base de tus DAO’s la clase HibernateDAOSupport, y dentro de esta usar el HibernateTemplate, o la API de Hibernate directamente:

public class ProductDaoImpl extends HibernateDaoSupport implements ProductDao {
    public Collection loadProductsByCategory(String category) throws DataAccessException {
        return getHibernateTemplate().find(
            "from test.Product product where product.category=?", category);

    }
}

public class ProductDaoImpl extends HibernateDaoSupport implements ProductDao {
    public Collection loadProductsByCategory(String category)
            throws DataAccessException, MyException {

        Session session = getSession(getSessionFactory(), false);
        try {
            List result = session.find(
                "from test.Product product where product.category=?",

                category, Hibernate.STRING);
            if (result == null) {

                throw new MyException("invalid search result");
            }

            return result;
        }
        catch (HibernateException ex) {
            throw convertHibernateAccessException(ex);
        }

    }
}


- Usar la API de HIbernate 3 para obtener las sesiones:

public class ProductDaoImpl implements ProductDao {

    private SessionFactory sessionFactory;
    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }
    public Collection loadProductsByCategory(String category) {

        return this.sessionFactory.getCurrentSession()
                .createQuery("from test.Product product where product.category=?")
            .setParameter(0, category)
            .list();

  }
}


En los dos primeros casos la ventaja de usarlos en Hibernate 2 es clara: no nos tenemos que ocupar de abrir o cerrar sesiones, lo hace el HibernateTemplate por nosotros, además de hacer que nuestras sesiones entren a formar parte de una transacción (de Spring, de la que luego hablaré).
Claro está que para solucionar el tema del LazyLoading con el que empezé este ladrillo la solución es semejante a la de Hibernate, usar un filtro o un interceptor . Lo bueno es que es el HibernateTemplate el que comprueba si tenemos una sesión asociada al thread o no y cierra la sesión si no existe este filtro (Alguno podría decir que eso también se puede implementar en un HibernateUtil: pues sí, pero con Spring “viene de fábrica” ;-)

En la tercera alternativa el código es el mismo que el que usaríamos en Hibernate (salvo que obtenemos el SessionFactory por IoC), con la salvedad de que ahora podemos usarlo sin necesidad de definir transacciones con JTA, sino con los mecanismos de Spring. Y aquí es donde empiezan las leches entre las divas del bel canto ;-D

DEPRECA LO QUE ME APETECE, INSUSTANCIAL!
Más o menos es lo que parece querer Gavin King respecto a Spring. A raíz de que de la página de hibernate “desaparecieran” las referencias a Spring la polémica estalló, y cómo no, en un blog


Más o menos, Gavin King viene a decir que HibernateTemplate es una bazofia poco elegante y que los admiradores de Hibernate no deberían usarla ya que en Hibernate 3 está tirado obtener sesiones y el manejo de transacciones (con JTA). Y que la “deprequéis” chavalillos de Spring. A lo que los de Spring responden: es mi código y hago lo que quierto con él, sino quieres usar HibernateTemplate NO LO USES, pero no molestes :-D


Vale, pero es una bazofia tan poco elegante como HibernateUtil propuesto en Hibernate 2 (yo diría que menos). Vamos que ha sido una bazofia que ha habido que usar bastante con Hibernate 2.

Por otro lado, se le “olvida” comentar un pequeñísimo detalle, que es la madre del cordero del asunto: con Hibernate si quieres usar getCurrentSession() TIENES que usar transacciones JTA (vamos programadores a pasar por la tabla de EJB3, no os preocupéis de los tiburones que veis ahí abajo!), si usas Spring puedes usarlo usando los mecanismos de transacciones de Spring (que puede usar JTA o no). Osea que si quieres esa comodidad en Hibernate 3 a usar un servidor de aplicaciones (¿te he dicho ya que hibernate pertenece al stack de aplicaciones de Jboss, y que Spring rechazó la oferta de pertenecer a ella?), en cambio Spring te deja la libertad de usarlo dentro o fuera de un servidor de aplicaciones.
Ahora que cada uno tenga su opinión, que yo ya he escrito demasiado ladrillo. En un post siguiente mis problemas con aquellas librerías que usan Hibernate por debajo, y si lo consigo ;-) cómo lo soluciono.

Salu2

14 Respuestas a “Sesiones en Hibernate Vs Sesiones en Spring”


  1. 1 Enrique Rodriguez Lasterra

    Osea, q todo el follon viene porque desde las JSP quieres cargar las tablas relacionadas dentro de la misma transación.

    Desconozco totalmente hibernate, pero esta transación es la transacción de toda la vida del start/commit/rollback?

    Si es asi, cual es el peligro de hacer un select fuera de la transación??

  2. 2 Juan

    Bueno, pues no te cuento nada cuando lo useis en aplicaciones de escritorio. Es problema se multiplica. Por lo menos en las aplicaciones web queda claro donde iniciar y finalizar la transacción (en un filtro). Utilizando Spring, te libera de la necesidad de crear sesiones y transacciones. Pero como decía cuando se trata de una aplicación Swing, no puedes dejar la sesión abierta la vida del componente que presenta la información. Esto obliga muchas veces a recuperar información en la capa de servicios. Por cierto, en el desarrollo que estamos llevando a cabo, tener un modelo de negocio con 100 entidades relacionadas, es un infierno. Cuando cargas cualquier entidad, se tira un buen rato iniciando las asociaciones, aunque estén con la carga perezosa, nuestro “amigo” hibernate, carga todos los identificadores. Bueno ya os he dado un poco el coñazo. Resumiendo. Hibernate tiene cosas buenas, pero tiene otras que te hacen la vida imposible.

  3. 3 martin

    Gracias por las referencias Ibon.

    Lo cierto es que yo he huido siempre de las lazy collections “transparentes” de Hibernate. La verdad es que me parecieron siempre muy problemáticas, y de hecho yo también he sufrido el usarlas en aplicaciones de escritorio. Vamos, para escapar de ellas.

  4. 4 ibon

    Yo te diría que la idea es al revés ;-): si quieres cargar info “lazily” tienes que hacerlo dentro de la misma sesión, que en el caso del patrón de diseño session por request, coincide en su duración con la transacción ;-)
    Y sí, el concepto de transacción es el de toda la vida, lo que pasa es que también existe el concepto de sesión Hibernate: hibernate hace su “magia” (cargar objetos de forma transparente, tener una caché de primer nivel para no tener que acceder a la base de datos, prevenir la concurrencia) dentro de la sesión.
    En el artículo de Martin (referencia +3 ;-)) está explicado de cine los distintos patrones existentes: sesión global (una sesión para toda la aplicación), sesión por usuario (una sesión para cada usuario), sesión por petición (una sesión por petición) y sesión por transacción de aplicación (una sesión para cada transacción que nosotros definamos como de aplicación).
    El problema es que si no tienes las cosas claras respecto a donde empieza y acaba una sesión y donde empieza y acaba una transacción, habrá muchas cosas de hibernate que no funcionen (por ejemplo, las LAzyInitializationException) o que te obliguen a “guarradas”: volver a traerte un objeto de la BD cuando ya lo tienes en memoria para poder acceder a sus relaciones lazy (caso que me está pasando en OCAS)
    SAlu2

  5. 5 ibon

    Pues sí, lo que hace es crear unas clases proxy con los identificadores para saber a que entidad tiene que acceder si debe hacer un lazy load. Lo que yo no había probado es que tardase tanto. Creo que en esos casos lo mejor es hacer caso de los consejos de Martin y jugar con la caché de segundo nivel para determinados datos.
    Salu2

  6. 6 ibon

    No, gracias a tí por tu artículo :-)
    Respecto al lazy, he encontrado en el wiki de hibernate la siguiente aseveración:

    “The solution for this issue is of course proper unit of work demarcation and design, supported by possibly an interception technique as shown in the pattern here, and/or the correct fetch technique so that all required information for a particular unit of work can be retrieved with minimum impact, best performance, and scalability.”

    Creo que les han dado bastante la chapa con el lazy y ahora aconsejan utilizar la técnica adecuada a cada problema para traer datos desde la BD. A eso me refería al principio con técnica cómoda/incómoda
    Salu2

  7. 7 lasterra

    Pos chicos, por lo que contaias prefiero perder la cache de hibernate y quedarme con la cache de la base de datos que tampoco son tan lentas!!

  8. 8 ssergio

    Genial, me ha parecido tan bueno tu articulo que acabo de agregarte a ‘mis favoritos’
    Yo acabo de empezar un proyecto ‘pequeño’ y he apostado por Hibernate 3 con Spring… por ahora ‘bien’.

    Salu2

  9. 9 greeneyed

    citaEsta forma de trabajo, en la que abrimos sesiones en un lado y las cerramos en otro no acabó de convencer a todo el mundo, ni a mícita
    Ole, ole, ahí salgo yo ;-).
    Muy bueno el recorrido secuencial del problema, las posibles soluciones y los saltos y encontronazos del camino. Lo peor de todo son las actitudes de algunos de los implicados, no hacen falta nombres, por que el resto es un problema general de usar caches y lazy loading: Cuando quieres recuperar los datos lazy tienes que tener “conectividad” para poder hacerlo.
    Otra solución es asegurarte desde el modelo que le envías a la vista todos los datos que necesita para pintarse y no hacer que ésta tenga que “pedirlos” (push vs pull) que es lo que se hacía antes con los Data Transfer Objects, pero ahora “no se pueden usar por que son un antipatrón”. En fin. Yo de la forma que uso Hibernate no tengo ese problema, abro y cierro las transacciones en el modelo, pero cuando más uso Hibernate, más quiero a mi perro.. digo… a EJB2.1, donde al menos las limitaciones las tenias especificadas y no te las vendía un jeta “por que yo lo valgo”. Siempre nos queda la esperanza de EJB3, a ver como sale…
    Un saludo
    PD: Cambia el título a otro color o cambia la foto, que no se lee nada :-)

  10. 10 ibon

    Epa ge, por fin te vemos por aquí ;-)
    Respecto a lo de que DTO son un “antipatrón”, pues resulta que ahora ya no está tan claro :-P Yo es que aveces me parto de la risa con las horas de discusión que tenemos los programadores. Me reservo esto para otro post al blog pero un sitio para ver esa discusión en hibernate (DTO’s sí ;-)) es http://www.hibernate.org/124.html
    Respecto a EJB3, los chicos de hibernate están haciendo verdaderos esfuerzos por convencer a la comunidad de que vale la pena pasarse ya. No soy adivino pero en breve veremos comentarios en el jira de hibernate del pelo de “esa funcionalidad no se va a desarrollar, pásate a EJB3 zoquete!”
    Salu2
    PD: Pasaré tus recomendaciones al boss, que no te pase nada ;-D

  11. 11 greeneyed

    Jejeje. Por eso mismo yo lo de los patrones/antipatrones/loquestademoda/loqueno no me lo tomo muy en serio, que luego cambian de opinión y se quedan más anchos que largos, ellos siguen vendiendo sus libros sin dar palo al agua, algunos, y tu eres el que se queda con cara de gili.

    Respecto a EJB3… de boca de un vendedor de servidores de aplicaciones que YA implementa los drafts y demas… “en confianza, mejor no probarlo en nada que tenga que durar por que el final puede que no se parezca mucho a lo que hay especificado hasta ahora”. Así que yo de momento lo tengo claro, jorobado por tener que seguir sufriendo al amiguete Hibernate, pero claro.

    Saludotes!

  12. 12 wilman

    Este articulo es muy interesante ya que a todos los desarrolladores ya seamos novatos o de un conocimiento superior en hibernate la hemos visto a la famosa exception lanzada por trabajar con lazy y sobre todo aun mas en aplicaciones J2EE, no es que estemos mal haciendo las cosas pero muchos nos agrada acelerar el trabajo que nos proporciona las relaciones con lazy pero si es un poco complejo entender las sesiones, transacciones y proxy en hibernate. Como dije al inicio es muy bueno este articulo ya que nos da unas pautas en utilizar patrones y anitpatrones y sobre todo a mi personalmente me ayudo a decidirme a trabajar tambien mis aplicaciones con Spring, aunque ya lo habia escuchado antes, como una manera elegante de solucionar este problemas y los nuevos problemas que van apareciendo con Hibernate. GRACIAS

  13. 13 Fernando

    En primer lugar, felicidades por este post. Me he visto reflejado y se agradece lo bien que está explicado.

    Ya hace tiempo de este artículo, pero como ayer se rerenciaba (http://weblog.linkingpaths.com/index.php?/archives/102-La-carga-perezosa-hibernate-vs-jdo.html), pues me ha surgido una duda con la que estoy trabajando, y es como realizar escrituras en la base de datos, ya que por defecto no se puede hacer, aparece el mensaje “Write operations are not allowed in read-only mode (FlushMode.NEVER/MANUAL): Turn your Session into FlushMode.COMMIT/AUTO or remove ‘readOnly’ marker from transaction definition.”

    Un solución que estoy haciendo es que los métodos de mis Dao que guardan o eliminan, hagan un getSession().setFlushMode(FlushMode.AUTO);

    ¿Qué opináis de esta solución?

    Bueno, solo es un comentario, repito mis felicitaciones por el post.

  14. 14 Geremora

    Buenas, estuve leyendo el articulo y los comentarios. Justamente estoy con algo de dudas sobre como implementar mi aplicacion WEB. Utilizo Flex3 (con cairgorm), blazeDS, java6-hibernate3.
    Planteo un modelo de objetos JAVA con un facade con los metodos que invoca el cliente (ahi abro y cierro la sesion al terminar de mandar los DTO). Para comunicacion java-flex flex-java uso DTO.
    En esto de la comunicacion tengo dudas de como es la mejor forma de manejarlo. Por ahora tenia un solo DTO por objeto del modelo..

    Tienen alguna idea o link donde se pueda ver una arquitectura modelo para implementar lo que necesito.
    Gracias.
    Muy interesante las discusiones.

Añade un Comentario





Close
E-mail It