grails - samsung - ¿Alguna vez necesito enjuagar explícitamente GORM guardar llamadas en griales?
como grabar una llamada entrante en iphone (4)
¿Alguna vez necesito enjuagar explícitamente GORM guardar llamadas en griales?
En resumen, ¡ Sí !, Si quieres usar el objeto de inmediato como lo haces en tu código.
Me enfrenté al mismo problema, así que esta es la imagen que obtuve después de leer algunas referencias.
Este es un problema de sesión de hibernación .
La sesión de Hibernate se crea cuando se llama a la acción del controlador y finaliza cuando la acción regresa (o muere con error temprano). Si un código no está llamando a ningún código transaccional, la interacción db de Hibernate se puede representar así:
Supongamos que el nombre de la acción de entrada es actionName y la llamada a la acción se completa sin ningún error.
NB : la barra del medio (la memoria caché del segundo nivel está desactivada) porque no hay ningún código transaccional.
si el mismo código anterior tiene error:
Pero si su acción llama al método transaccional o está creando una transacción en línea con withTransaction (y asume que la llamada a la acción se completó sin ningún error).
Si el código anterior tiene un error:
Espero que ayude, pero si cometí un error o fallo al incluir un gran punto, comenten que actualizaré mis fotos.
Tengo una situación extraña que parece indicar un problema de caché GORM
//begin with all book.status''s as UNREAD
Book.list().each { book.status = Status.READ ; book.save() }
println (Book.findAllByStatus (Status.READ)) //will print an empty list
println (Book.list().findAll (it.status == Status.READ)) // will print all books
No puedo entender por qué las dos últimas consultas podrían arrojar resultados diferentes.
Sin embargo, si realizo la siguiente modificación de book.save (flush: true) . Ambas instrucciones impresas devolverán todos los libros.
Tenía la impresión de que esto no era necesario en una sola aplicación.
Para referencia, estoy usando
- DB: mysql
- Groovy: 1.7.10
- Grails: 1.3.7
@ Hoàng Long
Mi problema se demuestra a continuación, supongo que action1 / action2 se llaman muchas veces, en ningún patrón particular
def action1 = {
Foo foo = Foo.get(params.id)
//... modify foo
foo.save() //if I flush here, it will be inefficient if action1 is called in sequence
}
def action2 = {
//if I flush here, it will be inefficient if action2 is called in sequence
List<Foo> foos = Foo.findAllByBar (params.bar)
//... do something with foos
}
Una solución sería tener una bandera que es establecida por acción1 y utilizada por acción2 para enjuagar si es necesario. Mi problema es que esta es una solución demasiado compleja, que no es escalable a medida que aumenta la complejidad de las llamadas a bases de datos.
boolean isFlushed = true
def action1 = {
Foo foo = Foo.get(params.id)
//... modify foo
foo.save()
isFlushed = false
}
def action2 = {
if (!isFlushed) {
//flush hibernate session here
}
List<Foo> foos = Foo.findAllByBar (params.bar)
//... do something with foos
}
En su caso, la primera declaración devuelve una lista vacía porque lee datos de la base de datos, pero los datos aún no están allí.
Así es como funciona Hibernate: cuando llamas a save with (flush: true)
, vaciará la sesión de Hibernate, persistiendo todos los datos en sesión en la base de datos inmediatamente . Si no se usa (flush:true)
, los datos solo se graban en la sesión de Hibernate y solo se conservan en la base de datos cuando se vacía la sesión de Hibernate . El tiempo para purgar la sesión es determinado automáticamente por Hibernate para optimizar el rendimiento.
En general, debe dejar que Hibernate haga el trabajo por usted (para optimizarlo), a menos que desee que los datos se conserven de inmediato.
De acuerdo con Peter Ledbrook:
Deje que Hibernate lo haga y solo enjuague manualmente la sesión cuando sea necesario, o al menos solo al final de un lote de actualizaciones. Solo deberías usarlo realmente si no estás viendo los datos en la base de datos cuando deberían estar allí. Sé que es un poco flojo, pero las circunstancias en que tal acción es necesaria dependen de la implementación de la base de datos y de otros factores.
ACTUALIZAR: para tener claro cómo vaciar la sesión una vez después de que se haya guardado todo el objeto:
import org.hibernate.*
class SomeController {
SessionFactory sessionFactory
def save = {
assert sessionFactory != null
// loop and save your books here
def hibSession = sessionFactory.getCurrentSession()
assert hibSession != null
hibSession.flush()
}
}
Me pregunto cuál fue tu configuración de FlushMode.
Por defecto está configurado en " automático " y significa que la sesión se vacía antes de cada consulta que golpea directamente a DB (y probablemente en otros casos también). En ese caso, su Foo.findAllByBar debe purgar primero la sesión (¡posible problema de rendimiento!) Y leer el valor correcto del DB.
Hay otros dos valores para FlushMode y si configura uno de ellos, explicaría sus problemas. Primero, es " manual ", lo que significa que usted decide realizar una sesión de vaciado manual (p. Ej., Con guardar (vaciar: verdadero)). Si no haces eso, entonces Foo.findAllByBar lee el estado de DB desactualizado. El segundo es " commit ", lo que significa que la sesión se vacía con cada commit de transacción. Eso es bastante útil si usas la instrucción " withTransaction " en griales.
Recursos: http://schneide.wordpress.com/2011/03/08/the-grails-performance-switch-flush-modecommit/ http://docs.jboss.org/hibernate/entitymanager/3.5/reference/en/html/objectstate.html#d0e1215
Para información adicional, no puede usar flush o save (flush: true) en los eventos de clase de su dominio (afterUpdate, beforeUpdate, ect) Causará un error de desbordamiento de la pila. Sin embargo, puedes usar save () sin flush.