Ich erstelle eine einfache Tomcat-Webanwendung, die Spring Data und Hibernate verwendet. Es gibt ein Endpunkt, der viel Arbeit macht, daher möchte ich die Arbeit in einen Hintergrund-Thread verlagern, so dass die Web-Anfrage nicht länger als 10 Minuten hängen bleibt, während die Arbeit erledigt wird. Also schrieb ich einen neuen Dienst in einem Bauteil-scan'd Paket:Wie führe ich einen Hintergrund-Thread korrekt aus, wenn Spring Data und Hibernate verwendet werden?
@Service
public class BackgroundJobService {
@Autowired
private ThreadPoolTaskExecutor threadPoolTaskExecutor;
public void startJob(Runnable runnable) {
threadPoolTaskExecutor.execute(runnable);
}
}
Dann haben die ThreadPoolTaskExecutor
konfiguriert im Frühjahr:
<bean id="threadPoolTaskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<property name="corePoolSize" value="5" />
<property name="maxPoolSize" value="10" />
<property name="queueCapacity" value="25" />
</bean>
Das ist alles das Arbeiten groß. Das Problem kommt jedoch von Hibernate. Innerhalb meiner Runable, Abfragen nur die Hälfte arbeiten. Ich kann tun:
MyObject myObject = myObjectRepository.findOne()
myObject.setSomething("something");
myObjectRepository.save(myObject);
Aber wenn ich faul geladene Felder haben, ist es nicht:
MyObject myObject = myObjectRepository.findOne()
List<Lazy> lazies = myObject.getLazies();
for(Lazy lazy : lazies) { // Exception
...
}
Ich erhalte die folgende Fehlermeldung:
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.stackoverflow.MyObject.lazies, could not initialize proxy - no Session
So sieht es aus wie mir (Hibernate Neuling), dass der neue Thread keine Sitzung mit diesen selbst erstellten Threads hat, aber Spring Data automatisch neue Sitzungen für HTTP-Anforderungs-Threads erstellt.
- Gibt es eine Möglichkeit, eine neue Sitzung manuell innerhalb der Sitzung zu starten?
- Oder eine Möglichkeit, den Thread-Pool zu sagen, es für mich zu tun?
- Was ist die Standard-Praxis für diese Art von Arbeit?
Ich habe in der Lage gewesen, um es an der Arbeit ein wenig von allem zu tun, aus dem Innern einer @Transactional
Methode, aber ich lerne schnell, das ist nicht eine sehr gute Lösung, da dies nicht ich Methoden nicht verwenden lassen, die funktionieren Gut für Web-Anfragen.
Danke.
Ein Teil des Problems ist, ich möchte in der Lage sein, den Status des Jobs zu aktualisieren, während es ausgeführt wird. Wenn ich also alles in eine einzige Transaktion einpacke, wird der Status erst aktualisiert, wenn die äußerste Commit-Anweisung abgeschlossen ist. Es sei denn, ich vermisse etwas hier ... was völlig möglich ist :) – Joel
Könnten Sie Ihre Runnable-Implementierungsklasse und vielleicht Ihr ObjectRepository zeigen? Ich bin auch ein bisschen neugierig, wie und wo Sie Statusupdates veröffentlichen möchten. Es ist nicht so offensichtlich mit http-basierten Web-Anwendungen. – alobodzk
Speziell für die Aktualisierung des Prozessstatus: Verwenden Sie eine verschachtelte Transaktion. Stellen Sie sicher, dass Ihr JPA-Anbieter sie unterstützt. – Virmundi