GORM działa dobrze po wyjęciu z pudełka, o ile nie ma partii z więcej niż 10.000 obiektów. Bez optymalizacji napotkasz problemy OutOfMemory.Sesja hibernacji sesji w partiach
powszechnym rozwiązaniem jest przepłukać() i gładkie() sesję każdy N (EGN = 500) obiektów:
Session session = sessionFactory.currentSession
Transaction tx = session.beginTransaction();
def propertyInstanceMap = org.codehaus.groovy.grails.plugins.DomainClassGrailsPlugin.PROPERTY_INSTANCE_MAP
Date yesterday = new Date() - 1
Criteria c = session.createCriteria(Foo.class)
c.add(Restrictions.lt('lastUpdated',yesterday))
ScrollableResults rawObjects = c.scroll(ScrollMode.FORWARD_ONLY)
int count=0;
while (rawObjects.next()) {
def rawOject = rawObjects.get(0);
fooService.doSomething()
int batchSize = 500
if (++count % batchSize == 0) {
//flush a batch of updates and release memory:
try{
session.flush();
}catch(Exception e){
log.error(session)
log.error(" error: " + e.message)
throw e
}
session.clear();
propertyInstanceMap.get().clear()
}
}
session.flush()
session.clear()
tx.commit()
jednak pewne problemy nie mogę rozwiązać:
- Jeśli używam currentSession, to kontroler nie powiedzie się, ponieważ sesja jest pusta
- Jeśli używam sessionFactory.openSession(), to currentSession jest nadal używana w FooService. Z tego powodu mogę użyć zapisu session.save (object). Ale to oznacza, że muszę zmodyfikować fooService.doSomething() i zduplikować kod dla pojedynczej operacji (zwykła notacja grails taka jak fooObject.save()) i operacji wsadowej (session.save (fooObject()) .. notacja).
- Jeśli użyję Foo.withSession {session->} lub Foo.withNewSession {session->}, to obiekty klasy Foo zostaną wyczyszczone przez session.clear() zgodnie z oczekiwaniami. Wszystkie pozostałe obiekty nie są wyczyszczone(), co prowadzi do wycieku pamięci.
- Z tego powodu mogę użyć Evict (obiekt) do ręcznego wyczyszczenia sesji. Ale prawie niemożliwe jest uzyskanie wszystkich istotnych obiektów, z powodu autofetchowania zestawień.
Więc nie mam pojęcia, jak rozwiązać moje problemy, nie czyniąc FooService.doSomething() bardziej złożonym. Szukam czegoś takiego jak withSession {} dla wszystkich domen. Lub, aby zapisać sesję na początku (Sesja tmp = currentSession) i zrobić coś takiego jak sessionFactory.setCurrentSession (tmp). Oba nie istnieje!
Każdy pomysł jest mile widziany!
Wygląda to na pracę, którą należy wykonać w całości metodą serwisową. Jeśli w ramach metody serwisowej używasz 'currentSession', czy twój kontroler nadal działa? – doelleri
Zgadzam się z @doelleri. Usługi to miejsce wright, aby to zrobić. Pamiętaj też, że domyślnie są one transakcyjne, jeśli chcesz ręcznie obsłużyć status, użyj 'Domain.withTransaction' i ustaw' static transactional = false' lub pozwól, aby usługa zajmowała się zatwierdzaniem/wycofywaniem. –
Kod, który tam zamieściłem, znajduje się już w metodzie usługi. Tak, mógłbym użyć kontekstu transakcji metody usługi, ale to nie rozwiąże mojego problemu. @doelleri - Odpowiedź na twoje pytanie brzmi: kontroler jest hamowany, więc użytkownik nie może zrobić nic więcej w aplikacji, z wyjątkiem zamknięcia przeglądarki.(patrz problem 1) – Waldemar