Frage

Ich habe eine stateless Bean so etwas wie:

@Stateless
public class MyStatelessBean implements MyStatelessLocal, MyStatelessRemote {
    @PersistenceContext(unitName="myPC")
    private EntityManager mgr;

    @TransationAttribute(TransactionAttributeType.SUPPORTED)
    public void processObjects(List<Object> objs) {
        // this method just processes the data; no need for a transaction
        for(Object obj : objs) {
            this.process(obj);
        }
    }

    @TransationAttribute(TransactionAttributeType.REQUIRES_NEW)
    public void process(Object obj) {
        // do some work with obj that must be in the scope of a transaction

        this.mgr.merge(obj);
        // ...
        this.mgr.merge(obj);
        // ...
        this.mgr.flush();
    }
}

Die typischerweise Nutzung ist dann der Client processObjects nennen würde (...), die eigentlich nicht mit dem Unternehmen Manager interagieren. Es tut, was es tun muss, und fordert Prozess (...) individuell für jedes Objekt zu verarbeiten. Die Dauer des Verfahrens (...) ist relativ kurz, aber processObjects (...) eine sehr lange Zeit in Anspruch nehmen könnte durch alles laufen. Deshalb will ich nicht, dass es eine offene Transaktion aufrecht zu erhalten. I Sie müssen den einzelnen Prozess (...), die in ihrem eigenen Geschäft zu betreiben. Dies sollte eine neue Transaktion für jeden Anruf sein. Ich würde Schließlich möchte die Möglichkeit offen halten für die Client-Prozess zu nennen (...) direkt an.

ich eine Reihe von unterschiedlichen Transaktionstypen ausprobiert habe. Nie, nicht unterstützt, unterstützt (auf processObjects) und erforderlich, neue erfordert (auf Prozess), aber ich TransactionRequiredException jedes Mal merge () aufgerufen wird,

Ich habe in der Lage gewesen, um es durch Aufspaltung der Verfahren in zwei verschiedene Bohnen funktioniert:

@Stateless
@TransationAttribute(TransactionAttributeType.NOT_SUPPORTED)
public class MyStatelessBean1 implements MyStatelessLocal1, MyStatelessRemote1 {
    @EJB
    private MyStatelessBean2 myBean2;

    public void processObjects(List<Object> objs) {
        // this method just processes the data; no need for a transaction
        for(Object obj : objs) {
            this.myBean2.process(obj);
        }
    }
}

@Stateless
public class MyStatelessBean2 implements MyStatelessLocal2, MyStatelessRemote2 {
    @PersistenceContext(unitName="myPC")
    private EntityManager mgr;

    @TransationAttribute(TransactionAttributeType.REQUIRES_NEW)
    public void process(Object obj) {
        // do some work with obj that must be in the scope of a transaction

        this.mgr.merge(obj);
        // ...
        this.mgr.merge(obj);
        // ...
        this.mgr.flush();
    }
}

, aber ich bin immer noch neugierig, ob es möglich ist, diese in einer Klasse zu erreichen. Es scheint mir, wie der Transaktionsmanager bei der Bean-Ebene funktioniert nur, auch wenn einzelne Methoden sind spezifischere Anmerkungen gegeben. Wenn ich also markieren ein Verfahren in einer Weise, die Transaktion von Start-Aufruf andere Methoden innerhalb derselben Instanz zu verhindern, wird auch eine Transaktion nicht schaffen, egal wie sie markiert sind?

Ich bin mit JBoss Application Server 4.2.1.GA, aber nicht-spezifische Antworten sind willkommen / bevorzugt.

War es hilfreich?

Lösung

Eine andere Möglichkeit, es zu tun, ist eigentlich auf der gleichen Bohne beide Methoden mit - und mit einer @EJB Referenz auf sich selbst! Etwas wie folgt aus:

// supposing processObjects defined on MyStatelessRemote1 and process defined on MyStatelessLocal1
@Stateless
@TransationAttribute(TransactionAttributeType.NOT_SUPPORTED)
public class MyStatelessBean1 implements MyStatelessLocal1, MyStatelessRemote1 {
    @EJB
    private MyStatelessLocal1 myBean2;

    public void processObjects(List<Object> objs) {
        // this method just processes the data; no need for a transaction
        for(Object obj : objs) {
            this.myBean2.process(obj);
        }
    }


    @TransationAttribute(TransactionAttributeType.REQUIRES_NEW)
    public void process(Object obj) {
        // do some work with obj that must be in the scope of a transaction

        this.mgr.merge(obj);
        // ...
        this.mgr.merge(obj);
        // ...
        this.mgr.flush();
    }
}

So kann man tatsächlich ‚Kraft‘ die process() Methode über den ejb Stapel von Proxies zugegriffen werden, damit die @TransactionAttribute in Wirksamwerden - und nach wie vor nur eine Klasse zu halten. Puh!

Andere Tipps

Matt, die Frage, die Sie fragen, ist ein ziemlich Klassiker, ich glaube, die Selbstreferenz Lösung von Herval / Pascal ordentlich ist. Es ist eine allgemeine Lösung hier nicht erwähnt.

Dies ist ein Fall für EJB „user“ Transaktionen. Da Sie in einem Session-Bean sind, können Sie die Benutzertransaktion aus dem Sitzungskontext erhalten. Hier ist, wie Sie Ihren Code mit Benutzertransaktionen aussehen:

// supposing processObjects defined on MyStatelessRemote1 and process defined on MyStatelessLocal1
@Stateless
@TransationAttribute(TransactionAttributeType.NOT_SUPPORTED)
public class MyStatelessBean1 implements MyStatelessLocal1, MyStatelessRemote1 {

    @Resource
    private SessionContext ctx;

    @EJB
    private MyStatelessLocal1 myBean2;

    public void processObjects(List<Object> objs) {
        // this method just processes the data; no need for a transaction
        for(Object obj : objs) {
            this.myBean2.process(obj);
        }
    }


    public void process(Object obj) {

        UserTransaction tx = ctx.getUserTransaction();

        tx.begin();

        // do some work with obj that must be in the scope of a transaction

        this.mgr.merge(obj);
        // ...
        this.mgr.merge(obj);
        // ...
        this.mgr.flush();

        tx.commit();
    }
}

Ich denke, die Sache jede Bohne ist in einem Proxy eingewickelt, die das Transaktionsverhalten steuert. Wenn Sie von einer Bohne zum anderen rufen, Sie gehen über diesen Proxy-Bean und das Transaktionsverhalten kann durch den Proxy geändert werden.

Aber wenn eine Bohne eine Methode für sich selbst mit einem anderen Transaktionsattribut ruft, wird der Anruf nicht über den Proxy gehen, so dass das Verhalten nicht ändert.

Matt, für das, was es wert ist, ich habe das gleiche Ergebnis wie Sie genau kommen.

TransactionAttributeTypes werden nur berücksichtigt, wenn Bean Grenzen überqueren. Wenn Methoden innerhalb derselben Bean TransactionAttributeTypes Aufruf haben keine Auswirkung, egal welche Typen auf die Methoden gesetzt werden.

Soweit ich sehen kann, gibt es nichts in der EJB-Persistenz Spec ist, der angibt, was das Verhalten unter diesen Umständen sein sollte.

Ich habe auch erlebt dies in Jboss. Ich werde es auch einen Versuch in Glassfish geben und lassen Sie die Ergebnisse.

Falls jemand kommt über diesen einen Tag:

zirkuläre Abhängigkeiten zu vermeiden (das eine Selbstbezug zum Beispiel) in JBoss verwenden, die Anmerkung ‚IgnoreDependency‘ Beispiel:

@IgnoreDependency @EJB MySelf myselfRef;

Ich habe es noch nicht ausprobiert (ich bin zu), aber eine Alternative eine Selbstreferenz über die @EJB Anmerkung zu injizieren ist die SessionContext.getBusinessObject() Methode. Dies wäre ein weiterer Weg, um die Möglichkeit einer zirkulären Verweis zu vermeiden, Dinge auf dich bläst -. Obwohl zumindest für staatenlos Bohnen zu arbeiten Injektion scheint

Ich arbeite an einem großen System, in dem beide Techniken eingesetzt werden (vermutlich von verschiedenen Entwicklern), aber ich bin nicht sicher, was der „richtige“ Weg, es zu tun.

Ich glaube, hat mit dem @TransationAttribute (TransactionAttributeType.Never) auf Verfahren processObjects zu tun.

TransactionAttributeType.Never

http://docs.sun.com / app / docs / doc / 819-3669 / 6n5sg7cm3? a = Ansicht

  

Wenn der Kunde innerhalb eines läuft   Transaktion und ruft die Unternehmen   bean-Verfahren, wobei der Behälter wirft ein   Remote. Ist der Kunde nicht   mit einer Transaktion verbunden ist, die   Behälter nicht startet eine neue   Transaktion, bevor die Methode ausgeführt wird.

Ich gehe davon aus, dass Sie Client die Methode sind processObjects aus dem Client-Code. Da wahrscheinlich Ihr Kunde nicht mit einer Transaktion den Methodenaufruf mit TransactionAttributeType.Never verbunden ist, ist glücklich in dem ersten Platz. Dann rufen Sie die Prozess Methode von processObjects , dass die TransactionAttributeType.Required altough mit Annotations nicht wird wurde ein Bean Methodenaufruf und die Transaktion Politik nicht erzwungen . Wenn Sie anrufen fusionieren Sie die Ausnahme, weil Sie noch nicht mit einer Transaktion verbunden sind.

Versuchen Sie es mit TransactionAttributeType.Required für beide Bean-Methoden, um zu sehen, ob es funktioniert der Trick.

Ich hatte diese zirkuläre Abhängigkeit Themen, die Kevin erwähnt. Allerdings ist die vorgeschlagene Anmerkung @IgnoreDependency ist eine Jboss spezifische Annotation und es gibt kein Gegenstück in z Glassfish.

Da es nicht mit Standard-EJB-Referenz nicht funktionieren, fühlte ich mich ein bisschen unangenehm mit dieser Lösung.

Deshalb habe ich bluecarbon Lösung eine Chance, so dass die innere Transaktion "von Hand" zu starten.

Daneben sehe ich keine Lösung, sondern den inneren Prozess () in einer anderen Bean zu implementieren, die auch hässlich ist, weil wir einfach unser Klassenmodell stören für solche technischen Details wollen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top