3 Stimmen

Der in spring/resources.groovy konfigurierte Dienst verfügt nicht über eine Hibernate-Sitzung

Wir haben eine Anwendung mit einem Plugin, das einen Dienst enthält:

public class TaskService {

    public void doSomething( Task task ) {
        // do something with task
        task.save();
    }
}

Das funktioniert gut.


Für unseren "besonderen" Kunden mit seinen speziellen Anforderungen haben wir eine zweite Anwendung, die das Plugin aus der ersten Anwendung enthält und ein weiteres Plugin mit einem speziellen Dienst für diesen Kunden, der den ursprünglichen Dienst erweitert und einige Methoden überschreibt:

public class SpecialTaskService extends TaskService{

    @Override
    public void doSomething( Task task ) {
        // do something special with task
        task.save();
    }
}

An jeder Stelle in der zweiten Anwendung, wo taskService injiziert wird, wollen wir nun den SpecialTaskService haben (auch im Plugin der ersten Anwendung). Also haben wir den SpecialTaskService in der resources.groovy unter grails-app/conf/spring hinzugefügt:

beans = {
        taskService( SpecialTaskService )
}

Aber jetzt erhalten wir eine HibernateException, wenn wir "task.save()" in dem speziellen Dienst aufrufen: org.hibernate.HibernateException: Es ist keine Hibernate-Sitzung an einen Thread gebunden, und die Konfiguration erlaubt es nicht, hier eine nicht-transaktionale Sitzung zu erstellen

Wir wissen, dass wir eine SessionFactory in den SpecialService einfügen können, aber wenn wir sessionFactory.currentSession aufrufen, erhalten wir dieselbe Exception.

Die Ausnahme tritt auch auf, wenn wir einen Dienst in resources.groovy konfigurieren, der keinen anderen Dienst erweitert.

Gibt es eine Möglichkeit, den speziellen Dienst eine Art von "hibernateSessionAware" zu machen, so dass wir save() und merge() auf Domänenobjekte aufrufen können?

5voto

Burt Beckwith Punkte 74817

Der ursprüngliche Dienst ist transaktional, d.h. er hält eine Hibernate-Sitzung für die Dauer des Methodenaufrufs offen (es sei denn, es ist bereits eine aktiv und er hat sich dieser angeschlossen). Sie müssen also Ihren Dienst ebenfalls transaktional machen, da Sie Spring lediglich anweisen, eine einfache neue Instanz mit taskService(SpecialTaskService)

Am einfachsten ist es, die Klasse (oder einzelne Methoden, wenn Sie das wünschen) mit Anmerkungen zu versehen:

import org.springframework.transaction.annotation.Transactional

@Transactional
class SpecialTaskService extends TaskService {

   @Override
   void doSomething(Task task) {
      // do something special with task
      task.save()
   }
}

aber Sie können auch Codeblöcke oder ganze Methoden in withTransaction-Blöcke verpacken:

class SpecialTaskService extends TaskService {

   @Override
   void doSomething(Task task) {
      Task.withTransaction { status ->
         // do something special with task
         task.save()
      }
   }
}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X