2009-11-02 12 views
7

Actualmente estoy trabajando en un proyecto mío (bastante grande), una aplicación Swing que por su propia naturaleza necesita ser multiproceso. Casi todas las interacciones del usuario pueden obtener datos de algunos servidores remotos a través de Internet, ya que no controlo estos servidores ni el Internet en sí mismo, por lo tanto, los tiempos de respuesta largos son inevitables. Es obvio que una UI Swing no puede volver a pintarse mientras el EDT está ocupado, por lo que todas las llamadas a servidores remotos deben ser ejecutadas por hilos de fondo.Administración de sesiones usando Hibernate en una * aplicación multi-threaded * Swing

Mi problema:

datos captados por los hilos de fondo consigue 'enriquecidas' con datos de una base de datos local (en memoria) (servidor remoto devuelve IDS/referencias a los datos en la base de datos local). Posteriormente, estos datos se pasan al EDT donde se convierte en parte del modelo de vista. Algunas entidades no se inicializan por completo en este punto (habilitación diferida), por lo que el usuario puede activar la recuperación diferida, p. Ej. desplazándose en una JTable. Como la sesión de hibernación ya está cerrada, se activará una LazyInitializationException. No puedo saber cuándo el usuario podría desencadenar la recuperación diferida, por lo que no será necesario crear una sesión bajo demanda/adjuntar el objeto separado.

I 'resuelto' este problema por:

  • utilizando un único (sincronizado, ya que los casos de sesión no se thread-safe) Sesión para toda la aplicación
  • deshabilitar lazy-ir a buscar completamente

Mientras esto funciona, el rendimiento de la aplicación ha sufrido mucho (a veces casi inutilizable). La desaceleración es causada principalmente por la gran cantidad de objetos que cada consulta busca ahora.

Actualmente estoy pensando en cambiar el diseño de la aplicación a 'Sesión por hilo' y migrar todas las entidades recuperadas por hilos no EDT a la Sesión del hilo EDT (similar a this posting on the Hibernate forums).

Nota al margen: no se aplican los problemas relacionados con las actualizaciones de la base de datos, ya que todas las entidades de la base de datos son de solo lectura (datos de referencia).

¿Alguna otra idea sobre cómo utilizar Hibernate con lazy-loading en este escenario?

Respuesta

1

No exponga la sesión en sí misma en su API de datos. Todavía puedes hacerlo de forma perezosa, solo asegúrate de que la hidratación se realiza desde el hilo de 'datos' cada vez. Podría usar un bloque (ejecutable o algún tipo de clase de comando es probablemente el mejor que Java puede hacer por usted aquí desafortunadamente) que está envuelto por código que realiza la carga asincrónica desde la cadena de 'datos'. Cuando está en el campo de la UI, (en el hilo de la interfaz de usuario, por supuesto) campo algún tipo de 'datos está listo' evento que se publica por el servicio de datos. A continuación, puede obtener los datos del uso del evento en la interfaz de usuario.

+0

Quizás no entendí correctamente su respuesta (el inglés no es mi primer idioma) pero esto no desencadenaría una excepción LazyInitException cuando el modelo de vista (= EDT) intenta obtener datos de forma perezosa (¡ya que EDT! = ' hilo de datos)? De todos modos, su sugerencia funcionaría para mi aplicación si el análisis de la respuesta del servidor se llevara a cabo en el EDT y no por otro hilo como se está haciendo actualmente ... hmmmm ... Tengo que pensar en esto;) Gracias para tomarte tu tiempo! – JavaGuy

+0

Su respuesta supone que tiene una sola sesión en el hilo de datos que no cierra. Sin embargo, esto adolece del problema de la memoria caché L1 en constante crecimiento a menos que sea muy exigente con la separación de elementos de la sesión cuando ya no los necesite. – Jherico

+0

Soy consciente del problema de la "creciente sesión", pero actualmente esto está actualmente muy ponderado por el problema de la "recuperación de lazy perezoso";) ¿No necesitaría todavía dos sesiones para esto (uno para el hilo de datos, uno para el EDT) para que funcione la recolección diferida dentro de la vista? – JavaGuy

0

Hay dos problemas distintos, que deben quedar resueltos por separado:

  1. Manejo de Sesiones de hibernación en aplicaciones Swing. Permítanme recomendar un artículo propio, con respecto a este problema: http://blog.schauderhaft.de/2008/09/28/hibernate-sessions-in-two-tier-rich-client-applications/

La idea básica es tener una sesión para cada cuadro, con exclusión de los marcos modales que utilizan la sesión del marco de desove. No es fácil, pero funciona. Es decir, ya no recibirás ningún LLE.

  1. Cómo obtener su hilo de GUI separado del back-end.

Recomiendo mantener los objetos de hibernación estrictamente en el hilo de fondo desde el que se originan. Solo dele objetos de envoltura al ETD. Si a estos objetos de envoltura se les solicita un valor, crean una solicitud que se pasa al hilo de fondo, que eventualmente devolverá el valor.

Me imagino tres tipos de implementaciones contenedoras:

asíncrono: Solicita el valor, y recibe una notificación cuando el valor está disponible. Volvería inmediatamente con algún valor ficticio. En la notificación activará un evento PropertyChange i.O. Informar a la GUI sobre el valor 'cambiado' (cambiado de desconocido a un valor real).

Sincronización: solicita el valor y espera a que esté disponible.

Tiempo programado: una mezcla entre los dos, esperando un corto tiempo (0.01) segundos, antes de regresar. Esto evitaría muchos eventos de cambio, en comparación con la versión asincrónica.

Como base para estos envoltorios de un recomienda el ValueModel del JGoodies Encuadernación de biblioteca: http://www.jgoodies.com/downloads/libraries.html

Obviamente se necesita tener cuidado de que cualquier acción sólo se realiza en los valores cargados en realidad, pero ya que no planea haciendo actualizaciones esto no debería ser un gran problema.

Permítanme terminar con una advertencia: lo he pensado mucho, pero nunca lo he intentado, así que muévanse con cuidado.

+0

no funcionará para referencias compartidas, pero sí en referencias copiadas – andyczerwonka

+0

No estoy seguro de lo que quiere decir con referencias compartidas.Pero probablemente estoy de acuerdo :) Los objetos de Hibernate y sus sesiones deben limitarse a un ámbito bien definido, y el alcance de las dos sesiones no debe solaparse. Si necesita mover un objeto de un ámbito a otro, deberá volver a cargarlo en la sesión de destino. –

1

Puedes echar un vistazo a Ebean ORM. Es sin sesión y la carga lenta simplemente funciona. Esto no responde a tu pregunta, pero realmente propone una alternativa.

Sé que Ebean ha incorporado soporte para la ejecución de consultas asíncronas que también puede ser interesante para su escenario.

Quizás vale la pena echarle un vistazo.

  • Rob.
+0

Hola Rob, Gracias por el enlace, supongo que eres el desarrollador principal. ;-) De todos modos, suena prometedor ... Creo que lo probaré cuando tenga algo de tiempo de sobra. – JavaGuy

Cuestiones relacionadas