2011-05-30 11 views
7

Estoy mejorando una vieja aplicación Spring/Hibernate y estoy atascado. Tengo un método que lee un archivo de más de 3000 líneas, cada línea tiene un registro que debe compararse con algo de la base de datos y luego debe agregarse un registro a la base de datos (una tabla de muchos a muchos).Hibernate se cuelga o arroja la inicialización perezosa sin sesión o se cerró la sesión

Las tablas y las relaciones son

Branch tienen muchas Producto, Producto se encuentran en muchas ramas .

productos tener muchos productos, y una Categoría tiene muchos productos

y hay más mesas que estaban allí y trabajan bien.

Los nuevos tablas/objetos que he creado son Branch, Producto, BranchToProduct.

los productos tienen un conjunto de BranchToProduct objetos, que tienen 3 campos

tengo que añadir objetos BranchToProduct al conjunto de productos, con los 3 campos llenos de información que recibo de cada línea del archivo.

I añadir una línea simple y la aplicación tiros:

producto = productDAO.findByModel (stringModel);

no se puede inicializar con pereza una colección de papel: com.bamboo.catW3.domain.Product.products, ninguna sesión o sesión se cerró

si voy a hibernar mapeo (archivo HBM) y establecer la relación product_to_products lazy = false, la línea funciona bien sola, pero si intento ponerla en el ciclo del archivo, la aplicación se cuelga siempre en la línea 18 procesada, no importa qué archivo use o el orden de el contenido, la consola deja de funcionar, tiene que cerrar java matando el proceso.

De cualquier manera, en la depuración, obtengo una gran cantidad de HQL para un hallazgo simple, 13 líneas de HQL hasta que obtengo mi error cuando lazy = true, y MUCHAS líneas cuando uso lazy = false y lo pongo el ciclo.

Creo que debería intentar solucionar el problema con lazy = true.

Esta situación me hace pregunto:

1.- Cuando perezoso = true. ¿Cómo es que no puedo ejecutar una sola línea de este comando con este método, pero funciona bien con otros métodos de la clase?

por cierto, esto es una clase llamada CatalogFacade que implementa los métodos de otro clasess: (CategoryFacade, ContainerFacade, ProductFacade, ProductOptionFacade, ProductStatusFacade, UserFacade, EmailFacade, FileFacade, BranchOfficeFacade)

Este es el código para el
productDao.find():

public Product find(Integer id) throws DataAccessException { 

     Product product= (Product) super.find(Product.class, id); 


     if(product!=null){ 
      product.setProductAttributes(new TreeSet<ProductAttribute>(product.getProductAttributes())); 

      for (Product ptp : product.getProducts()){ 
       ptp.setProductAttributes(new TreeSet<ProductAttribute>(ptp.getProductAttributes())); 

      } 

     } 

la excepción se ha tirado a la derecha en esta línea, en el último para:

pptp.setProductAttributes(new TreeSet<ProductAttribute>(ptp.getProductAttributes())) 

en depurador de Intelij, puedo ver el objeto formado indebidamente de la consulta:

product.getProducts() = {[email protected]}unable para evaluar el método de expresión arrojó org.hibernate' Excepción .LazyInitializationException '.

Como todos los demás atributos están bien. Este producto ni siquiera tiene otros productos en la base de datos.

ACTUALIZACIÓN

PROFUNDIZAR sobre la situación, dentro de la

product.find (int)

En la línea antes de que consiga la excepción, podemos ver en la depuración de que la matriz product.products tiene un error, en lugar del valor, puede ver la excepción lazyInitialitationException. Como sea, si lo llamo desde otro método, la matriz es find. Entonces no puede estar dentro de él AUN aunque el método solo recibe un Entero.

Además, encontramos que esto ha sucedido a lo largo de todo el ciclo de vida de la aplicación, algunas veces el personal ha replicado un método como este pero lo ha cambiado estableciendo nula esta matriz corrupta. Así que estoy 100% seguro de que esta aplicación está consumiendo más recursos de lo que debería.

Tiene vistas en Flex, y vistas posteriores en JSTL donde se crearon, y dependiendo de quién llame a los métodos, las excepciones se lanzan de diferentes maneras para los mismos métodos.

Agregando más información. Esta es la forma en produt.find se implementa en el AbstractDAOImpl:

public final Object find(Class clazz, Integer id) throws DataAccessException{ 

     return getHibernateTemplate().get(clazz,id); 
} 

y esta es mi configuración del gestor de transacciones, el método de anotación se describe en la primera respuesta de impulso que no funcionó:

<bean id="catalogFacade" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> 
    <property name="transactionManager"> 
     <ref local="transactionManager"/> 
    </property> 
    <property name="target"> 
     <ref local="catalogFacadeTarget"/> 
    </property> 
    <property name="transactionAttributes"> 
     <props> 
      <prop key="add*">PROPAGATION_REQUIRED</prop> 
      <prop key="save*">PROPAGATION_REQUIRED</prop> 
      <prop key="update*">PROPAGATION_REQUIRED</prop> 
      <prop key="delete*">PROPAGATION_REQUIRED</prop> 
      <prop key="remove*">PROPAGATION_REQUIRED</prop> 
      <prop key="get*">PROPAGATION_SUPPORTS,readOnly</prop> 
      <prop key="find*">PROPAGATION_SUPPORTS,readOnly</prop> 
      <prop key="contains*">PROPAGATION_SUPPORTS,readOnly</prop> 
      <prop key="login*">PROPAGATION_SUPPORTS,readOnly</prop> 
     </props> 
    </property> 
</bean> 

Respuesta

0

He tenido el mismo problema anteriormente y lo solucioné utilizando diferentes métodos de hibernación. Yo uso

getHibernateTemplate().loadAll(class) 

para conseguir todas algo, y

getHibernateTemplate().get(class, id) 

a encontrar una sola cosa.Los dos que uso sin problemas. Encontré que .find() me da que la sesión fue un error cerrado.

Realmente no he investigado por qué esto es así.

La única otra opción que se me ocurre aparte de utilizar otro método es abrir y cerrar sesiones usted mismo, pero supongo que prefiere no hacer eso.

+0

En realidad, así es como el programa ya lo está haciendo, vea el código de actualización – Ernest

19

Obtiene una excepción de inicialización diferida porque su sesión se cierra antes de acceder a las variables de miembro del Producto. Cuando se ejecuta la siguiente línea:

Product product= (Product) super.find(Product.class, id) 

Hibernate se abre a las sesiones, recupera lo que estás buscando, entonces se cierra entonces la sesión. Cualquier campo que tenga lazy = true es no recuperado en este momento; en su lugar, estos campos están llenos de proxies. Cuando intente recuperar el valor real del objeto procesado, intentará volver a la base de datos utilizando la sesión activa para recuperar los datos. Si no se puede encontrar ninguna sesión, obtiene la excepción que está viendo. La configuración de lazy = true tiene ventajas porque evita que todo el gráfico de objetos se cargue inmediatamente; los objetos anidados se dejan solos hasta que específicamente los pidas.

Existen dos técnicas comunes para resolver su problema. El primero que ya ha identificado, que es establecer lazy = false. Esto está bien si un producto siempre tiene atributos de producto, y normalmente usa un producto y sus atributos juntos. Si a menudo solo necesita el objeto Producto sin sus atributos, está creando una carga de base de datos innecesaria.

La segunda técnica es marcar un método como transaccional utilizando las anotaciones de Spring.

@Transactional 
public Product find(Integer id) throws DataAccessException { 

} 

Unas pocas notas:

  1. Usted necesita una configuración adicional para las transacciones a trabajo (la anotación @Transactional no es suficiente). Ver here para más información.
  2. Las mejores prácticas dictan que anote métodos en su capa de servicio, en lugar de su capa de acceso a datos.
+0

Hola, Fillip, probé los 2 métodos que mencionas.El primero cuelga la aplicación después de la llamada número 18 a la base de datos, la anotación no funcionó, y todavía es muy extraño porque el método funciona para diferentes llamadas en otros métodos de la misma clase que llama a este método ahora. Voy a agregar mi configuración de aspecto y ver si me ayuda. ¿Qué más podría verificar? – Ernest

+0

¿Qué quiere decir con "cuelga" después de la llamada número 18? Además, ¿se le llama ciclismo a través de los atributos del producto en su CatalogFacade, o en el DAO? – Fil

+0

En cuanto a sus comentarios en la pregunta en sí, inspeccionar un campo cargado flojo a través del depurador activará una inicialización lenta de la misma manera que la aplicación; el intento de recuperación se está realizando fuera de una acción de transición. ¿Funcionó para usted la configuración de lazy = false en los atributos del producto? – Fil

0

Reemplazar el método de carga con el método get ..

descubrí después de hacer más investigación que el método de carga en realidad no cargar el objeto a partir de la base de datos. En cambio, devuelve automáticamente un objeto proxy. Load asume que el objeto ya ha sido "getten get" de la base de datos y está en la caché.

Simplemente use get en lugar de load si quiere asegurarse de acceder a la base de datos, y asegúrese de conocer la diferencia entre estos 2 métodos.

Fuente: this spring forum comment

Yo personalmente he probar esto y es correcto, el método de carga no recuperar todos los datos deseados de la base de datos. Usando arreglar mi problema.

Cuestiones relacionadas