mvc example entitymanagerfactory java hibernate spring orm

java - entitymanagerfactory - spring orm example



Limpieza segura de la sesión de Hibernate en medio de una gran transacción (2)

¿Cuándo es un buen momento para despejar ()? ¿Tiene un gran costo de rendimiento?

A intervalos regulares, lo ideal sería que el tamaño del lote JDBC, después de haber lavado los cambios. La documentación describe expresiones comunes en el capítulo sobre procesamiento por lotes :

13.1. Inserciones de lotes

Al hacer objetos nuevos, limpie () y luego borre () la sesión regularmente para controlar el tamaño de la memoria caché de primer nivel.

Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); for ( int i=0; i<100000; i++ ) { Customer customer = new Customer(.....); session.save(customer); if ( i % 20 == 0 ) { //20, same as the JDBC batch size //flush a batch of inserts and release memory: session.flush(); session.clear(); } } tx.commit(); session.close();

Y esto no debería tener un costo de rendimiento, au contraire:

  • permite mantener baja la cantidad de objetos para rastrear la suciedad (por lo que el enjuague debe ser rápido),
  • debería permitir recuperar memoria.

¿Por qué no se lanzan automáticamente / GCD objetos como bar o baz? ¿Cuál es el sentido de mantenerlos en la sesión después de la confirmación (en el siguiente ciclo de iteración no son alcanzables de todos modos)?

Necesita clear() la sesión explícitamente si no desea mantener las entidades rastreadas, eso es todo, así es como funciona (es posible que desee comprometer una transacción sin "perder" las entidades).

Pero, por lo que puedo ver, las instancias bar y baz deben convertirse en candidatas a GC después del claro. Sería interesante analizar un volcado de memoria para ver exactamente qué está sucediendo.

¿es seguro / recomendable llamar a org.hibernate.Session # clear () directamente?

Siempre y cuando flush() los cambios pendientes para no perderlos (a menos que esto sea lo que quiere), no veo ningún problema con eso (su código actual perderá un bucle de cada 100, pero tal vez sea solo un pseudo código )

Si la respuesta a la pregunta anterior es verdadera, ¿qué sucederá con el objeto foo, suponiendo que se llama clear () dentro del ciclo? ¿Qué pasa si foo.foo () es un método de carga lenta?

Llamar a clear() desaloja todas las instancias cargadas de la Session , convirtiéndolas en entidades separadas. Si una invocación posterior requiere que una entidad se "adjunte", fallará.

Estoy usando Spring + Hibernate para una operación que requiere crear y actualizar literalmente cientos de miles de elementos. Algo como esto:

{ ... Foo foo = fooDAO.get(...); for (int i=0; i<500000; i++) { Bar bar = barDAO.load(i); if (bar.needsModification() && foo.foo()) { bar.setWhatever("new whatever"); barDAO.update(bar); // commit here Baz baz = new Baz(); bazDAO.create(baz); // if (i % 100 == 0), clear } } }

Para protegerme contra perder cambios en el medio, barDAO.update(bar) los cambios inmediatamente después de barDAO.update(bar) :

HibernateTransactionManager transactionManager = ...; // injected by Spring DefaultTransactionDefinition def = new DefaultTransactionDefinition(); def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED); TransactionStatus transactionStatus = transactionManager.getTransaction(def); transactionManager.commit(transactionStatus);

En este punto, tengo que decir que todo el proceso se está ejecutando en una transacción org.springframework.orm.hibernate3.support.ExtendedOpenSessionInViewFilter en org.springframework.orm.hibernate3.support.ExtendedOpenSessionInViewFilter (sí, esta es una aplicación web).

Todo esto funciona bien con una excepción: después de algunos miles de actualizaciones / confirmaciones, todo el proceso se vuelve realmente lento, muy probablemente debido a que la memoria se ve abotagada por la cantidad cada vez mayor de objetos mantenidos por Spring / Hibernate.

En el entorno solo de Hibernate esto se resolvería fácilmente llamando a org.hibernate.Session#clear() .

Ahora, las preguntas:

  • ¿Cuándo es un buen momento para clear() ? ¿Tiene un gran costo de rendimiento?
  • ¿Por qué no se lanzan automáticamente / GCD objetos como bar o baz ? ¿Cuál es el sentido de mantenerlos en la sesión después de la confirmación (en el siguiente ciclo de iteración no son alcanzables de todos modos)? No he hecho vuelco de memoria para probar esto, pero mi buena sensación es que todavía están allí hasta que se hayan cerrado por completo. Si la respuesta a esto es "Hibernate cache", ¿por qué no se vacía el caché cuando la memoria disponible está baja?
  • ¿es seguro / recomendable llamar a org.hibernate.Session#clear() directamente (teniendo en cuenta todo el contexto de Spring, cosas como la carga diferida, etc.)? ¿Hay envolturas / contrapartes Spring útiles para lograr lo mismo?
  • Si la respuesta a la pregunta anterior es verdadera, ¿qué sucederá con el objeto foo , suponiendo que se llama clear() dentro del ciclo? ¿Qué pasa si foo.foo() es un método de carga foo.foo() ?

Gracias por las respuestas.


Solo quería señalar que, después de borrar la sesión, si desea continuar utilizando algunos objetos que estaban en la sesión, deberá Session.refresh(obj) para continuar.

De lo contrario, obtendrá el siguiente error:

org.hibernate.NonUniqueObjectException