Hibernar diseño de aplicaciones de carga lenta


Tiendo a usar Hibernaren combinación con Spring framework y sus capacidades de demarcación de transacciones declarativas (por ejemplo, @Transactional).

Como todos sabemos, hibernate intenta ser lo más no invasivo y lo más transparente posible, sin embargo esto demuestra un poco más desafiante al emplear lazy-loaded relaciones.


Veo una serie de alternativas de diseño con diferentes niveles de transparencia.

  1. Hacer relaciones no perezosas (por ejemplo, fetchType=FetchType.EAGER)
    • Este vioalites la idea entera de la carga perezosa ..
  2. Inicializar colecciones usando Hibernate.initialize(proxyObj);
    • Esto implica un acoplamiento relativamente alto al DAO
    • Aunque podemos definir una interfaz con initialize, no se garantiza que otras implementaciones proporcionen cualquier equivalente.
  3. Agregar comportamiento de transacción a los objetos persistentes Model (usando proxy dinámico o @Transactional)
    • No he probado el enfoque de proxy dinámico, aunque nunca me pareció conseguir @Transactional trabajando en los propios objetos persistentes. Probablemente debido a que hibernar es la operación en un proxy para bein con.
    • Pérdida de control cuando se realizan efectivamente operaciones
  4. Proporciona API perezosa / no perezosa, por ejemplo, loadData() y loadDataWithDeps()
    • Obliga a la aplicación a saber cuándo emplear qué rutina, de nuevo acoplamiento apretado
    • Method overflow, loadDataWithA(),...., loadDataWithX()
  5. Forzar la búsqueda de dependencias, por ejemplo, proporcionando solo operaciones byId()
    • Requiere una gran cantidad de rutinas no orientadas a objetos, por ejemplo, findZzzById(zid), y luego getYyyIds(zid) en lugar de z.getY()
    • Puede ser útil obtener cada objeto de una colección uno por uno si hay una gran sobrecarga de procesamiento entre las transacciones.
  6. Hacer parte de la aplicación @Transaccional en lugar de solo el DAO
    • Posibles consideraciones de las transacciones anidadas
    • Requiere rutinas adaptadas para la gestión de transacciones (por ejemplo, suficientemente pequeñas)
    • Pequeño impacto programático, aunque podría dar lugar a grandes transacciones
  7. Proporcione al DAO perfiles dinámicos fetch , por ejemplo, loadData(id, fetchProfile);
    • Las aplicaciones deben saber qué perfil usar cuando
  8. Tipo de transacciones AoP, por ejemplo, interceptar operaciones y realizar transacciones cuando sea necesario
    • Requiere manipulación de código de bytes o uso de proxy
    • Pérdida de control cuando se realizan operaciones
    • Magia negra, como siempre:)

¿Me perdí alguna opción?


¿Cuál es su enfoque preferido cuando intenta minimizar el impacto de las relaciones lazy-loaded en el diseño de su aplicación?

(Oh, y lo siento por WoT )

Author: Johan Sjöberg, 2011-02-17

3 answers

Como todos sabemos, hibernate intenta ser lo más no invasivo y lo más transparente posible

Yo diría que la suposición inicial es errónea. La persistencia transaparente es un mito, ya que la aplicación siempre debe hacerse cargo del ciclo de vida de la entidad y del tamaño del gráfico del objeto que se está cargando.

Tenga en cuenta que Hibernar no puede leer pensamientos, por lo tanto, si sabe que necesita un conjunto particular de dependencias para una operación en particular, debe expresar sus intenciones para: Hibernar de alguna manera.

Desde este punto de vista, las soluciones que expresan estas intenciones explícitamente (es decir, 2, 4 y 7) parecen razonables y no sufren la falta de transparencia.

 26
Author: axtavt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-02-17 09:44:45

No estoy seguro de qué problema (causado por la vaguedad) estás insinuando, pero para mí el mayor dolor es evitar perder el contexto de la sesión en mis propios cachés de aplicaciones. Caso típico:

  • el objeto foo se carga y se coloca en un mapa;
  • otro hilo toma este objeto del mapa y llama foo.getBar() (algo que nunca se llamó antes y se evalúa perezosamente);
  • boom!

Así que, para abordar esto tenemos una serie de reglas:

  • ajustar las sesiones como de la forma más transparente posible (por ejemplo, OpenSessionInViewFilter para aplicaciones web);
  • tienen una API común para subprocesos/grupos de subprocesos donde la sesión de la base de datos se enlaza / desenlaza en algún lugar alto de la jerarquía (envuelto en try/finally) para que las subclases no tengan que pensar en ello;
  • al pasar objetos entre subprocesos, pase ID en lugar de los objetos mismos. El hilo receptor puede cargar el objeto si es necesario;
  • cuando almacene objetos en caché, nunca almacene objetos sino sus identificadores. Tenga un método abstracto en su clase DAO o manager para cargue el objeto desde la caché de Hibernación de 2do nivel cuando conozca el ID. El costo de recuperar objetos de la caché de Hibernación de nivel 2 sigue siendo mucho más barato que ir a la base de datos.

Esto, como se puede ver, de hecho no está cerca de no invasivo y transparente. Pero el costo sigue siendo soportable, en comparación con el precio que tendría que pagar por la carga ansiosa. El problema con este último es que a veces conduce al efecto mariposa al cargar un solo objeto referenciado, y mucho menos un colección de entidades. El consumo de memoria, el uso de CPU y la latencia, por mencionar lo menos, también son mucho peores, así que supongo que puedo vivir con ello.

 7
Author: mindas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-02-17 14:45:57

Un patrón muy común es usar OpenEntityManagerInViewFilter si está creando una aplicación web.

Si está construyendo un servicio, abriría el TX en el método público del servicio, en lugar de en el DAOs, ya que muy a menudo un método requiere obtener o actualizar varias entidades.

Esto resolverá cualquier "excepción de carga perezosa". Si necesita algo más avanzado para ajustar el rendimiento, creo que fetch profiles es el camino a seguir.

 3
Author: Augusto,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-02-17 09:28:36