Entity Objekt nicht gefunden -> Webhook empfangen in der gleichen Methode (Transaktion)

internet

Top Contributor
Hallo,

ich habe folgendes Szenario:

Ich habe erstelle in einer Methode ein Objekt und sende in der gleichen Methode dann später einen Webhook.
Die Methode läuft in einem EJB Container....
Wenn ich den Webhook empfange, finde ich das erstellte Objekt in der Datenbank aber nicht?
Meine Vermutung ist, dass das Objekt noch nicht commited wurde?

Java:
@Stateless
public MyClass() {
public void doSomething(){
    
    // Create Object in database
    MyObject myObject = new Object();
    myObject.setId(1);
    myServiceBean.createObject(myObject);
    
    // Send Webhook
    sendWebhook();
}
}

public void receiveWebhook(){
    
    // Suche MyObject in der Datenbank mit ID 1
    MyObject myObject = myServiceBean.search(1);
    
    // PROBLEM: myObject ist hier NULL
}

Kennt jemand das Problem und kann helfen?
 

internet

Top Contributor
Nein, keine der Methoden ist anotiert und nutzt demnach den Default Wert (required)..
Ist das das Problem? Wenn ja, wie müsste ich es ändern?
 

thecain

Top Contributor
Die Frage ist, wo deine Transaktionsgrenze liegt, wann du den Aufruf machst und was danach noch alles passiert bis die Transaktion abgeschlossen wird.
 

internet

Top Contributor
Prinzipiell soll alles in der Methode eine Transaktion sein… aber ich bekomme den Webhook eventuell schon bevor die Transaktion abgeschlossen ist / währenddessen…

Das ganze ist:
  • User in meiner App erstellen
  • User Id an einen Zahlungsprovider senden (dort passiert dann eben etwas)
  • Zahlungsprovider sendet mir einen Webhook zurück

Wie könnte ich das lösen?
 

internet

Top Contributor
Ja, aber wenn dann beim externen API Call etwas schief geht, mache ich kein Rollback für meinen Entrag in der Datenbank?
Der Eintrag ist dann unter Umständen in der DB, was er aber gar nicht soll?
 

KonradN

Super-Moderator
Mitarbeiter
Also das würde ich nicht als eine Transaktion sehen sondern ein Prozess der durchläuft. Das ist ja ein Vorgang der diverse Stati hat, die dieser durchläuft.

Das würde ich auch beibehalten und nicht löschen. So hast du die Details des Vorgangs in der Datenbank. Das kann teilweise auch sinnvoll sein.
 

internet

Top Contributor
Also das würde ich nicht als eine Transaktion sehen sondern ein Prozess der durchläuft. Das ist ja ein Vorgang der diverse Stati hat, die dieser durchläuft.

Das würde ich auch beibehalten und nicht löschen. So hast du die Details des Vorgangs in der Datenbank. Das kann teilweise auch sinnvoll sein.
Ok, das heißt dann für dich?
Soll:
  • User Id an einen Zahlungsprovider senden (dort passiert dann eben etwas)
In einer eigenen Transaktion laufen?
Falls ja, wie müsste ich dann die Methode annotieren? Wäre das „required_new“?

Habe mir noch überlegt, wenn ich den Webhook bekomme einfach nochmal 20 Sekunden zu warten (Thread.sleep), aber ist sicherlich auch nicht die eleganteste Lösung
 

thecain

Top Contributor
In einer eigenen Transaktion laufen?
Falls ja, wie müsste ich dann die Methode annotieren? Wäre das „required_new“?
Ja, wäre es. Wenn man aber Zahlungen abeickelt, macht es mMn auch Sinn sich vertieft mit der Technik auseinanderzusetzen, die man einsetzt. Es geht schliesslich um das Geld deiner Kunden.
Betreffend fehlgeschlagenen Calls könnte ein TX Outbox Pattern weiterhelfen. https://microservices.io/patterns/data/transactional-outbox.html
 

LimDul

Top Contributor
Ansonsten generell mal einen Schritt zurücktreten und überlegen, was passiert wie aufgrund von welchem Trigger. Und welche Informationen brauche ich im Erfolgsfall und - noch wichtiger - welche Informationen brauche ich im Fehlerfall um das dennoch nachverarbeiten zu können.

Muss es synchron sein? Man muss ja nicht gleich zur Batch-Tagesverarbeitung aus der Host Welt zurück. Es gibt ja viele Mechanismen seien es Queues, seien es Events, die es erlauben etwas asynchron zu verarbeiten, aber trotzdem aus zeitlicher Sicht synchron.

Ist es nicht vielleicht sinnvoller eingehende Aufrufe erstmal einfach nur entgegen zu nehmen und zu speichern und danach zu verarbeiten? So kann man im Fehlerfall eine erneute Verarbeitung problemlos anstoßen. Oder wie wir ggf. Pre-Conditions einbauen, damit etwas verarbeitet werden kann.

Mal ein Beispiel aus der Praxis bei uns. Wir sind ein Enterprise (JEE) System, was Daten ("Verträge") verwaltet. Darauf kann man Bearbeitungen machen. Nach einer Bearbeitung müssen wir mehrere andere Systeme informieren (Zahlungen und Druck mal als Beispiel). Das haben wir wie folgt gelöst:

Die Bearbeitung selber schreibt nur in einer Trigger-Tabelle System X muss informiert werden.
Wir nutzen dann JBoss-Events https://docs.oracle.com/javaee/6/tutorial/doc/gkhic.html um automatisch nach Abschluss unserer Transaktion dann die anderen Systeme zu informieren. Entweder es ist erfolgreich oder fehlerhaft - das wird in der Trigger-Tabelle protokolliert.
Weiterhin gibt es eine Scheduled Bean, die alle 10 Minuten prüft, ob es nicht verarbeitete Benachrichtigungen gibt, die älter als 5 Minuten sind. Wenn ja, werden die erneut versucht zu verarbeiten (es wird einfach das Event noch mal gefeuert).
Zusätzlich gibt es Monitoring, was Alarm schlägt, wenn zu viele unverarbeitete Events sich stauen.

Ergebnis: Wenn z.B. mal ein System down ist (z.B. das Drucksystem nicht erreichbar ist) geht unsere Bearbeitung trotzdem durch. Nur die Information an Druck geht auf Fehler (da es ein Event mit eigener Transaktion ist, beeinflusst es nix anderes). Alle 10 Minuten wird es wieder probiert. Sobald das System dann wieder erreichbar ist, werden die Aufrufe nachverarbeitet.

Sowas ähnliches kann man sich auch eingehend überlegen. Insbesondere bei Zahlungen sehe ich es als Fatal an, wenn aufgrund eines Fehlers Daten verloren gehen und nur Log-Einträge zurückbleiben. Ich möchte nach der Fehlerkorrektur die gelieferten Daten sauber nachverarbeiten können.

Das mal nur als Ideen-Anstoß. Diese Events gibt es analog auch im Spring-Boot Context.
 

mihe7

Top Contributor
Wie könnte ich das lösen?
Eine Möglichkeit wären CDI-Events. Du erstellst ein Event z. B. MyObjectEvent, das Du feuerst und einen Qualifier Created. Die Observer-Methode lässt sich benachrichtigen, wenn die Transaktion erfolgreich abgeschlossen wurde:
Java:
public void afterMyObjectCreated(@Observes(during=AFTER_SUCCESS) @Created MyObjectEvent event) {
    sendWebhook();
}
 

internet

Top Contributor
Eine Möglichkeit wären CDI-Events. Du erstellst ein Event z. B. MyObjectEvent, das Du feuerst und einen Qualifier Created. Die Observer-Methode lässt sich benachrichtigen, wenn die Transaktion erfolgreich abgeschlossen wurde:
Java:
public void afterMyObjectCreated(@Observes(during=AFTER_SUCCESS) @Created MyObjectEvent event) {
    sendWebhook();
}
Ok, danke..
Habe noch nie mit diesen CDI Events gearbeitet…
Ist das alles an Code, was ich benötige?
 

mihe7

Top Contributor
Ok, danke..
Habe noch nie mit diesen CDI Events gearbeitet…
Ist das alles an Code, was ich benötige?
Nein, Du musst das Event natürlich feuern. In Deiner MyClass hättest Du also noch etwas wie
Java:
@Inject @Created
private Event<MyObjectEvent> created;

public void doSomething(){
   
    // Create Object in database
    MyObject myObject = new Object();
    myObject.setId(1);
    myServiceBean.createObject(myObject);
   
    MyObjectEvent event = new MyOjbectEvent(myObject); // falls von Interesse, gebe ich mal das erzeugte Objekt mit
    created.fire(event);
}
Und natürlich musst Du den Spaß auf Deinen Fall anpassen.
 

internet

Top Contributor
Ok, danke…
Aber so ganz verstehe ich dann doch nicht wie ich das mit den CDI Events auf mein Problem adaptieren kann, wenn alles in einer „Transaktion“ laufen soll….

Aktuell würde ich eher die sendWebhook() als neue Transaktion in einer Methode laufen lassen.
Dann könnte man sich noch überlegen, ob man wie oben vorgeschlagen eine Tabelle „Events“ hat, die dann den Zustand speichert.
Zusätzlich dann einen Scheduler, der alle 5 min fehlgeschlagen Events sucht und diese bei Bedarf neu anstartet.
 

thecain

Top Contributor
Aktuell würde ich eher die sendWebhook() als neue Transaktion in einer Methode laufen lassen.
Warum sendWebhook? Das schreiben in die DB muss ja vorher erledigt sein.

Aber: Schau dir das Pattern an, dass ich geschickt habe. @LimDul s Antwort ist eine mögliche Implementierung davon. Du willst bei solchen Dingen eventual consistency. D.h. verteilte Transaktionen oder eben eine Lösung wie die Vorgeschlagene. Aber das kann man hier nicht so schnell schnell mit 3 Zeilen Code teigen. Damit musst DU ich auseinandersetzen und das entsprechend auf deine Anforderungen implementieren.

Inkonstistenzen in der Zahlungsabwicklung will man nun echt nicht
 

internet

Top Contributor
Ok, ich versuche das nun mal mit CDI Events...

Aber woher kommen: "AFTER_SUCCESS" und @Created?

Edit:
AFTER_SUCCESS kommt von
javax.enterprise.event.TransactionPhase;


1668412908231.png


Bei dem Besipiel aus dem Link sehe ich auch nur:
The qualifiers, @Credit and @Debit, are defined in the payment package along with PaymentBean.

Wie muss denn @Created aussehen? Oder ist das auch eine Annotation aus einem bestehenden Package?
Ist das etwas, was ich selbst erstellen muss?

Java:
@Qualifier
@Target({ METHOD, FIELD, PARAMETER, TYPE })
@Retention(RUNTIME)
public @interface Created {

}
 
Zuletzt bearbeitet:

mihe7

Top Contributor
Wie muss denn @Created aussehen? Oder ist das auch eine Annotation aus einem bestehenden Package?
Ist das etwas, was ich selbst erstellen muss?
So wie Du der Code, den Du gepostet hast. Nein. Ja.

Du kannst auch erstmal ohne den Qualifier arbeiten, der dient ja letztlich nur dazu, verschiedenartige Ereignisse unterscheiden zu können.
 

internet

Top Contributor
Ok, ich habe das ganze mal erstellt (siehe Code)
Nun habe ich aber ein Problem, dass es mir keine Datenbankverbindung in der Klasse "EventHandler" herstellt?
In der EventHandler mache ich nochmal eine Datenbankabfrage (Methode: findApiUrl)

Jedenfalls erhalte ich von der Datenbank keine Objekte zurück, die es aber 100%ig finden muss. (Ich habe mir auch mal noch eine Liste ausgeben lassen aller Objekte von diesem Datenbankabruf und hier erhalte ich eine leere Liste??)
D.h. bei diesem Aufruf bekomme ich nichts zurück, sodass ich dann später eine NPE Exception bekomme..

Code:
myDoaBean2.findApiUrl();

Java:
public class EventObject {

    // Objekt
    private HashMap<String, Object> entityObjectMap = new HashMap<String, Object>();

    // Eindeutiger Name, um die entsprechende Aktion dann zu starten
    private String actionType;

    /////////////////////
    /// Getter + Setter
    /////////////////////

    public String getActionType() {
        return actionType;
    }

    public HashMap<String, Object> getEntityObjectMap() {
        return entityObjectMap;
    }

    public void setEntityObjectMap(HashMap<String, Object> entityObjectMap) {
        this.entityObjectMap = entityObjectMap;
    }

    public void setActionType(String actionType) {
        this.actionType = actionType;
    }

    public EventObject() {
        super();
    }
}

Java:
@Stateless
public class RegistrationServiceBean {
 
@Inject
@Created
private Event<EventObject> created;
 
public void registration(){

// ....

            EventObject event = new EventObject();
            event.setActionType("test_webservice");
            HashMap<String, Object> hashMap = new HashMap<String, Object>();
            event.setEntityObjectMap(hashMap);
            hashMap.put("object1", irgendeinObjekt);
            hashMap.put("object2", irgendeinObjekt);

            // Feuer das Event
            created.fire(event);
     
}

Java:
@ApplicationScoped
public class EventHandler {

    @Inject
    //  @EJB habe ich auch probiert, bringt aber auch nichts.
    private MyDoaBean myDoaBean;
 
    /**
     * After Object is created
     *
     * @param event
     */
    public void afterMyObjectCreated(@Observes(during=TransactionPhase.AFTER_SUCCESS) @Created EventObject event) {
 
        //
        if(event.getActionType().equals("test_webservice")) {
     
            HashMap<String, Object> entityObjectMap = event.getEntityObjectMap();
            Object object1 = (IrgendEinObject) entityObjectMap.get("irgendeinObjekt");
            Object object2 = (IrgendEinObject) entityObjectMap.get("irgendeinObjekt");
         
           // Nur ein Test, die Liste muss Einträge aus der DB enthalten, ist aber leer... hier ist der Fehler...
           List<Object> list = myDoaBean.findAllObjects();

            // BillingOrder und Contract erstellen
            myDoaBean.createBillingOrderAndContract(object1, object2);
     
        }
    }
 
}

Java:
@Stateless
public class MyDoaBean {
 
    @EJB
    private MyDoaBean myDoaBean2;

    public Response createBillingOrderAndContract(Object object, Object object2) {
 
        String s = myDoaBean2.findApiUrl();
        // Hier ist der Fehler....
    }

}

Beim Debuggen sehe ich nun, dass ich diese Meldung bekomme:
javax.persistence.PersistenceException: org.hibernate.exception.GenericJDBCException: Unable to acquire JDBC Connection

Was mache ich falsch?
 
Zuletzt bearbeitet:

internet

Top Contributor
Ich habe nun in der EventHandler Klasse so ein DB Zugriff probiert, ohne jegliche Injection etc.
Auch hier bekomme ich keine DB Verbindung her...


Java:
@ApplicationScoped
public class EventHandler {

    @PersistenceContext
    private EntityManager entityManager;
   
    /**
     * After Object is created
     *
     * @param event
     */
    public void afterMyObjectCreated(@Observes(during = TransactionPhase.AFTER_SUCCESS) @Created EventObject event) {

        //
        if (event.getActionType().equals("test_webservice")) {

            MyEntity myEntity = find(Long.valueOf(2));
             // Execption...
        }

    }
       
    public MyEntity find(Long id){
        return entityManager.find(MyEntity.class, id);
    }

}

12:19:46,993 ERROR [org.hibernate.engine.jdbc.spi.SqlExceptionHelper] (default task-1) javax.resource.ResourceException: IJ000457: Unchecked throwable in managedConnectionReconnected() cl=org.jboss.jca.core.connectionmanager.listener.TxConnectionListener@65fec2e6[state=DESTROYED managed connection=org.jboss.jca.adapters.jdbc.local.LocalManagedConnection@24aa17ce connection handles=0 lastReturned=1668424786975 lastValidated=1668424679293 lastCheckedOut=1668424779192 trackByTx=false pool=org.jboss.jca.core.connectionmanager.pool.strategy.OnePool@2661133 mcp=SemaphoreConcurrentLinkedQueueManagedConnectionPool@cca91d9[pool=myapp] xaResource=LocalXAResourceImpl@55b84cf[connectionListener=65fec2e6 connectionManager=3265e321 warned=false currentXid=null productName=MySQL productVersion=8.0.16 jndiName=java:jboss/datasources/myapp] txSync=null]
12:19:49,608 ERROR [org.jboss.weld.Event] (default task-1) WELD-000401: Failure while notifying an observer [BackedAnnotatedMethod] public dEventHandler.afterMyObjectCreated(@Observes @Created EventObject) of event null.
org.hibernate.exception.GenericJDBCException: Unable to acquire JDBC Connection
 

mihe7

Top Contributor
Ich habe ein Problem, Dir zu folgen. Dein ursprüngliches Problem, wie ich es verstanden habe, war dergestalt, dass Du in Deiner Methode einen HTTP-Request absetzt (sendWebhook()), der an anderer Stelle im Programm empfangen und in einer neuen Transaktion behandelt wird (receiveWebhook()), bevor die alte Transkation abgeschlossen war. Das führt logischerweise dazu, dass die neue Transaktion die Änderungen der noch bestehenden Transaktion nicht sieht.

Das CDI-Event hier ersetzt nicht den HTTP-Request, sondern dient einfach dazu, sicherzustellen, dass der Request erst ausgelöst wird, wenn die Transaktion abgeschlossen ist, damit beim Empfang des Requests in der neuen Transaktion die Änderungen sichtbar sind.

Ein CDI-Event wird auch nicht asynchron behandelt. Für asynchrone Verarbeitung gibts andere Möglichkeiten (@Asynchronous oder Message Queues).

Das mal dazu. Wenn Du sowieso im gleichen Atemzug die Änderung durchführst, dann wüsste ich nicht, warum Du auf das Ende der Transaktion warten solltest.

Was die Observer-Methode betrifft: die wird ja aktuell nach dem Abschluss der Transaktion ausgeführt, annotier die Methode mal mit @TransactionAttribute(REQUIRES_NEW). Ansonsten, wenn es in der gleichen Transaktion ausgeführt werden soll - und keine zusätzlichen Transaktionen gestartet werden - kannst Du during auch einfach weglassen.
 

LimDul

Top Contributor
Aus meiner Sicht ist das Problem, dass wir hier versuchen ein technisches Problem zu lösen, ohne das zugrunde liegende fachlich Problem zu kennen. Das ist unglaublich schwierig. Ist auch auch kein Vorwurf @internet - es ist oft schwierig bis unmöglich das Problem so zu beschreiben, dass "Random Person on the Internet" es versteht. Insbesondere wenn man dann ggf. Details geben muss, die man nicht nach außen geben darf oder will.

Mir ist nicht ganz klar wer welchen Webhook/Request wann sendet und empfängt und wie die zusammenhängen.

Deswegen bewege ich mal wieder auf Allgemeinplätzen ala Hilfe zur Selbsthilfe. Vielleicht hilft hier ein UML-Sequenz-Diagramm: https://de.wikipedia.org/wiki/Sequenzdiagramm

Da kann man dann mal sehen, wer kommuniziert man mit wem und wo gibt es die Probleme, wo ziehe ich meine Transaktionsgrenzen ein.
 

internet

Top Contributor
Sorry für die Verwirrung...

Was die Observer-Methode betrifft: die wird ja aktuell nach dem Abschluss der Transaktion ausgeführt, annotier die Methode mal mit @TransactionAttribute(REQUIRES_NEW). Ansonsten, wenn es in der gleichen Transaktion ausgeführt werden soll - und keine zusätzlichen Transaktionen gestartet werden - kannst Du during auch einfach weglassen.

Habe ich probiert, aber ich bekomme weiterhin die Exception, dass keine JDBC Verbindung hergestellt werden kann....
Hier habe ich aktuell überhaupt keine Idee... Selbst wenn ich das Problem nun anderweitig lösen sollte (anderer Prozess etc.), würde mich trotzdem hier eine Lösung interessieren warum ich hier mit CDI keine Datenbankabfrage durchführen kann?
(Unable to acquire JDBC Connection)

Hier mal der Prozess:
- In rot das dargestellte Problem...:
Ich erhalte den Webhook zurück und möchte nach einem Objekt in der DB suchen, das aber noch nicht commited wurde...

Bis "Start API call to create BillingOrder / Contract etc." ist es ein Prozess... (siehe grüner Hintergrund)
Der nächste Prozess seitens "MyApp" startet dann wieder mit "Receive Webhook, search for created UserBilling object" (siehe lilaner Hintergrund)

"UserBilling" ist nur eine Mapping Tabelle, die mir die UserId von "MyApp" speichert und die ID des Kunden von "PaymentProvider"....
1668435236680.png
 
Zuletzt bearbeitet:

thecain

Top Contributor
myServiceBean.createObject(myObject)
Ich glaube das dein Problem grundsätzlich gelöst wäre, wenn du die Methode createObject mit REQUIRES_NEW annotieren würdest. Du hast dann mMn aber kein stabiles System gebaut, weil andere Aufrufe fehlschlagen könnten und dann "halbe" Requests in dee DB sind, die quch nicht irgendwie retried werden können.
 

internet

Top Contributor
Ich glaube das dein Problem grundsätzlich gelöst wäre, wenn du die Methode createObject mit REQUIRES_NEW annotieren würdest. Du hast dann mMn aber kein stabiles System gebaut, weil andere Aufrufe fehlschlagen könnten und dann "halbe" Requests in dee DB sind, die quch nicht irgendwie retried werden können.
Das hatte ich probiert. Das hat aber nicht funktioniert...

Ich tue mir auch etwas schwer die Frage zu beantworten, wie man die Abhängigkeit zum anderen System implementiert.
a) Will man, dass sich ein User registrieren kann, auch wenn irgendwas beim PaymentProvider schief geht?
-> Prinzipiell würde ich sagen ja, denn ich will das ja mitbekommen
b) Was passiert im Fehlerfall vom PaymentProvider?
Prinzipiell könnte man das ja so aufbauen, wie oben aufgezeigt, dass man "Events" hat.

Also ein Event für:
1. Create Customer (beim Payment Provider)
2. Create Order / Contract (beim Payment Provider)

Das Ganze hat dann einen
  • Status
  • JSON String (Im JSON String kann man dann die Objekte / Infos ablegen, die man nochmal bei einem späteren Aufruf der Methode benötigt?)

Falls ein Event fehlschlägt, könnte man diesen später eben nochmal ausführen.
Die Parameter für den Aufruf der Methode sind dann eben im JSON String...
 

mihe7

Top Contributor
a) Will man, dass sich ein User registrieren kann, auch wenn irgendwas beim PaymentProvider schief geht?
Das sind natürlich fachliche Entscheidungen, aber generell verliert man in verteilten Systemen nun einmal ACID-Eigenschaften.

b) Was passiert im Fehlerfall vom PaymentProvider?
Falls ein Event fehlschlägt, könnte man diesen später eben nochmal ausführen.
Genau.
 

internet

Top Contributor
Was hat nicht funktioniert? So wird am Ende der Methode ein Commit gemacht und alles müsste korrekt in der DB sein. Voraussetzung natürlich die Methode ist public und der Aufruf via injectetes Bean.

Es funktioniert nicht, dass ich beim Empfangen des Webhooks den Eintrag aus der DB erhalte...
Sprich der Commit hat wohl noch nicht stattgefunden...
registration() ist nicht annotiert, demnnach nutzt es den default

Java:
public void registration(){
  
    createObject();
   
    createContract();
    // Danach empfange ich den Webhook
}

@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public void createObject() {
  // do something
}
 

thecain

Top Contributor
Das ist aber jetzt anderer Code als bei #1. createObject muss via Proxy aufgerufen werden, nicht direkt, sonst geht das logischerweise nicht...
 

Matt

Aktives Mitglied
Hier ein einfaches Beispiel für @Transactional

Hier eine einfache Ressource (JAX RS Endpoint).

Java:
@Path("/hello")
public class GreetingResource {
    @Inject
    EntityManager em;

    @Inject
    StrangeService strangeService;

    @GET
    @Path("/strange")
    @Produces(MediaType.APPLICATION_JSON)
    public List<MyEntity> strange() {
        strangeService.doSomething();
        return em.createQuery("Select m from MyEntity m", MyEntity.class).getResultList();
    }
}

Hier ein einfacher Services mit einer Methode mit der Annotation @Transactional

Java:
@ApplicationScoped
public class StrangeService {
    @Inject
    EntityManager em;

    @Inject
    Event<MyEntity> event;

    @Transactional
    public void doSomething() {
        MyEntity entity1 = new MyEntity();
        entity1.setField("field-1");
        em.persist(entity1);
        event.fire(entity1);
    }

    public void onMyEntity(@Observes MyEntity entity) {
        MyEntity entity1 = new MyEntity();
        entity1.setField(entity.getField() +  "-1");
        em.persist(entity1);
    }
}

  • Setze ich einen Breakpoint bevor der @Transactional-Scope verlassen wird, z.B. in der "onMyEntity" Methode, so ist die Änderung noch nicht in der Datenbank vorhanden. Änderungen befinde sich in der Transaktion bis diese mit "commit" bestätigt und übertragen werden. Das Passiert automatisch sobald die Methode "doSomething" abgeschlossen ist.
  • Setze ich einen Breakpoint in meiner Resource "nach" dem Aufruf der Service Methode "strangeService.doSomething()", so befindet sich nun in der Datenbank 2 neue Einträge für "MyEntity".
Wenn die Änderungen innerhalb einer Transaktion nicht reichen (weil Thread/Process/System übergreifend), so können Transaktionen vorrangig durch einen Scope eingeschränkt werden. Hier wird die Transaktion auf die Methode "doSomething" eingeschränkt.
Denkbare wäre folgendes

Java:
@ApplicationScoped
public class Service {
    public void business() {
        createData();
        notifyOtherParty();
    }

    @Transactional
    public void createData() {}
   
    public void notifyOtherParty() {}
}

Alternativ lässt du dir den TranactionManager geben und committest selber. Denke jedoch auch an die Fehlerprüfung für Rollbacks.
 

thecain

Top Contributor
@Matt Sorry, aber nein. Da ist vieles falsch/ungenau.

1. Methoden müssen über den Proxy aufgerufen werden. D.h. via dem Injecteten Bean. Bei lokalen Methoden ist das verhalten nicht spezifiziert.

2. Default von @Transactional ist REQUIRED würde hier also im konkreten Fall nichts bringen da eine Transaktion vorhanden ist.

3. Selber die Transaktion zu managen macht in 99.9% der Fällen keinen Sinn und führt zu noch mehr Fehlern.

wie meinst du das mit "via Proxy aufgerufen werden" ?
Hast du hier ein Code Beispiel?
Die Methode, welche annotiert ist muss via injectetem Bean aufgerufen werden. Also myBean.createObject() nicht einfach die lokale Methode. Das Transactionhandling wird via Proxy hinzugefügt, wenn du die Methode direkt aufrufst, kann das nicht gemacht werden.
 

internet

Top Contributor
@Matt Sorry, aber nein. Da ist vieles falsch/ungenau.

1. Methoden müssen über den Proxy aufgerufen werden. D.h. via dem Injecteten Bean. Bei lokalen Methoden ist das verhalten nicht spezifiziert.

2. Default von @Transactional ist REQUIRED würde hier also im konkreten Fall nichts bringen da eine Transaktion vorhanden ist.

3. Selber die Transaktion zu managen macht in 99.9% der Fällen keinen Sinn und führt zu noch mehr Fehlern.


Die Methode, welche annotiert ist muss via injectetem Bean aufgerufen werden. Also myBean.createObject() nicht einfach die lokale Methode. Das Transactionhandling wird via Proxy hinzugefügt, wenn du die Methode direkt aufrufst, kann das nicht gemacht werden.
verstehe ich jetzt nicht so ganz...
Wie soll das Transactionhandling dann funktionieren, wenn die beiden Methoden innerhalb einer Klasse / Bean sind?
(Ist jetzt bei mir nicht der Fall, aber könnte ja auch generell sein)

Die Methode habe ich verschachtelt, sodass ich bei meiner Methode für den eigentlichen Datenbank persist nicht die TransactionAttributeType.REQUIRES_NEW habe (denn die Methode kann ja auch noch wo anders bei mir aufgerufen werden, bei der ich das das nicht brauche...).... Oder ist das ein Problem?

Java:
public MyBean {

   @EJB
   private BeanBean2 meanBean2;
    
   public void registration(){
 
    createObject();
  
    createContract();
    // Danach empfange ich den Webhook
  }

  @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
  public void createObject() {
     // do something
      meanBean2.createObject();
  }
}

public MyBean2 {
 
  // Hier dann bewusst OHNE TransactionAttributeType.REQUIRES_NEW
  public void createObject() {
     // Datenbank persist...
  }
}
 

internet

Top Contributor
Was hat nicht funktioniert? So wird am Ende der Methode ein Commit gemacht und alles müsste korrekt in der DB sein. Voraussetzung natürlich die Methode ist public und der Aufruf via injectetes Bean.
du hattest Recht.. Vielen Dank... 😍

Das Problem war, dass ich die Methode nur so aufgerufen habe, aber ich muss sich nochmal per Inject aufrufen (auch wenn es innerhalb der gleichen Bean läuft)... vielen Dank... Das war mir absolut neu, dass das so geht.

Im Webhook funktioniert es nun....
Nun muss ich mir mal noch Gedanken machen, wie ich das logge etc. wenn etwas beim API call / Webhook schief geht...
 

Matt

Aktives Mitglied
Habe es gestern zu Sicherheit runter getippt und getestet. Hat sauber wie erwartet funktioniert. Naja Hauptsache es läuft nun bei dir 👍
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
I @Entity Klassen, Service Beans etc. aus einem Share Projekt beziehen? Java Basics - Anfänger-Themen 26
I API - zurückgegebener JSON String lesen und in Entity konvertieren Java Basics - Anfänger-Themen 2
I Entity erstellen, die für API gedacht ist Java Basics - Anfänger-Themen 33
M Java entity und wertklassen Java Basics - Anfänger-Themen 2
B Methode für jede beliebe Entity erstellen Java Basics - Anfänger-Themen 7
G Java Object value und entity? Java Basics - Anfänger-Themen 2
F Entity vs value Java Basics - Anfänger-Themen 3
B Datenbank: Entity mit vielen Referenzen? Ansatz so ok? Java Basics - Anfänger-Themen 8
M JPA Entity Manager Java Basics - Anfänger-Themen 1
P Class<? extends Entity> Array Java Basics - Anfänger-Themen 9
Binary.Coder Java Beans - Entity erstellen Java Basics - Anfänger-Themen 6
S Methoden in der Entity Java Basics - Anfänger-Themen 5
M Ausgabe einer ArrayList ensteht nur als Hashcode, nicht als Objekt Java Basics - Anfänger-Themen 16
Rxiiz Objekt aus ComboBox entfernen Java Basics - Anfänger-Themen 4
I JSON in Objekt umwandeln Java Basics - Anfänger-Themen 3
P Objekt einer Methode eines anderen Objektes übergeben Java Basics - Anfänger-Themen 5
I Klassen von einem package laden, Statisches Feld auslesen und Objekt erstellen Java Basics - Anfänger-Themen 8
B Objekt aus generalisierter Liste entfernen Java Basics - Anfänger-Themen 11
Soranix Erste Schritte Struktur als Anfänger // Von einer Klasse auf ein Objekt einer anderen Klasse zugreifen. Java Basics - Anfänger-Themen 6
Say Objekt Java Basics - Anfänger-Themen 4
Say abstract class und Objekt erzeugen - Dringend Hilfe Java Basics - Anfänger-Themen 10
T Wie kann man es machen das ein Objekt nicht übermalt wird Java Basics - Anfänger-Themen 2
D OOP Array einem Objekt zuweisen Java Basics - Anfänger-Themen 2
K warum kann ich das Objekt nicht erstellen ? Java Basics - Anfänger-Themen 2
K wie kann ich alle Attribute von dem Objekt(pagode) ausgeben lassen ? Java Basics - Anfänger-Themen 3
H Ein übergegebenes Objekt auf null setzen Java Basics - Anfänger-Themen 9
M BlueJ Objekt in Objektliste Java Basics - Anfänger-Themen 2
B Objekt in Klassendiagramm an fremdes Objekt weiterreichen? Java Basics - Anfänger-Themen 6
Fodoboo131 RegEx- Umwandlung von String in ausführbares Objekt/ Befehl Java Basics - Anfänger-Themen 9
frager2345 Aufgabe Hash Objekt Elemente ausgeben Java Basics - Anfänger-Themen 2
amelie123456 Objekt Farbe Quellcode Java Basics - Anfänger-Themen 4
M Objekt in einem Objekt speichern Java Basics - Anfänger-Themen 9
U Warum kann ich, auf private Variablen zugreifen, wenn ich ein Objekt in der Klasse, die private Variablen hat erstelle und dort drauf zugreifen will? Java Basics - Anfänger-Themen 7
missy72 Klassen Objekt Array NullPointerException Java Basics - Anfänger-Themen 3
J Hinzufügen eines Objektes in ein Objekt-Array Java Basics - Anfänger-Themen 62
O Warum bekommen wir nicht die Referenz vom zurückgegebenen Objekt? Java Basics - Anfänger-Themen 4
K Ein Objekt Auto kennt den Inhalt seines links und rechtsstehenden Autos, wie soll man das ermöglichen Java Basics - Anfänger-Themen 2
W Unterschiede bei Zugriff auf Objekt und Klassenvariablen über einen Getter? Java Basics - Anfänger-Themen 2
melaniemueller Fernseher als Objekt Java Basics - Anfänger-Themen 9
B Datentyp für Einzelnes Objekt oder Liste Java Basics - Anfänger-Themen 9
Nina Pohl Ein Vorgang bezog sich auf ein Objekt, das kein Socket ist Java Basics - Anfänger-Themen 6
B Objekt kopieren und sämtliche Referenzen von diesem Objekt? Java Basics - Anfänger-Themen 3
S JavaFX - Objekt an neue Stage übergeben Java Basics - Anfänger-Themen 12
T Verständnisfrage Objekt Getter Setter Java Basics - Anfänger-Themen 102
P Objekt in mehreren Methoden verwenden. Java Basics - Anfänger-Themen 3
S Aufzurufendes Objekt Java Basics - Anfänger-Themen 3
CptK Überprüfen ob übergebenes Objekt zu Generics passt Java Basics - Anfänger-Themen 2
C Konstruktor ab serialisiertem Objekt Java Basics - Anfänger-Themen 4
Kalibru Problem bei Ausgabe von Objekt Java Basics - Anfänger-Themen 1
P Wie rufe ich Methoden mit einer Referenz auf eine Klasse||Objekt auf Java Basics - Anfänger-Themen 4
J Input/Output Konstruktor ergänzen, der zur Datei mit einem Objekt passt Java Basics - Anfänger-Themen 0
P Ein Objekt nach einem String durchsuchen? Java Basics - Anfänger-Themen 7
S Objekt aus Arraylist in andere Arraylist kopieren? Java Basics - Anfänger-Themen 2
J Objekt-Array dynamischer Länge aus Benutzereingaben erstellen Java Basics - Anfänger-Themen 6
W Mehrfach das gleiche Attribut für ein Objekt erzeugen (mit verschiedenen Werten) Java Basics - Anfänger-Themen 2
C Arrays - deklarieren, initialisieren? Ist das ein Objekt? Java Basics - Anfänger-Themen 3
B Interface List - Objekt übergeben? Einzelnes Objekt geht, aber Liste nicht? Java Basics - Anfänger-Themen 4
B Objekt von EJB in Controller (CDI) - Klasse füllen? Java Basics - Anfänger-Themen 3
L Zufälliges Objekt aus der ArraylList ohne java.util.Random Java Basics - Anfänger-Themen 56
N LocalTime einem Objekt zuweisen Java Basics - Anfänger-Themen 2
N Länge eines Arrays in einem Objekt testen Java Basics - Anfänger-Themen 51
M Wie kann ich ein Objekt erstellen, wenn sich der Klassenname in einer Variablen befindet? Java Basics - Anfänger-Themen 10
R Zugriff auf den Index eines Arrays, welches ein Objekt ist. Java Basics - Anfänger-Themen 4
tom.j85 Doppelte Foreach Schleife: Am Ende wird immer das Gleiche Objekt eingefügt Java Basics - Anfänger-Themen 4
J RSA Verschlüsselung Testen / byte[] in Objekt umwandeln Java Basics - Anfänger-Themen 1
M ArrayList - Objekt kopieren und ändern Java Basics - Anfänger-Themen 11
L Objekt an Methode übergeben Java Basics - Anfänger-Themen 4
S Spiel-Programmieren. Wenn ein Objekt den anderen berührt. Java Basics - Anfänger-Themen 6
J Y-Koordinate von GUI-Objekt bestimmen Java Basics - Anfänger-Themen 2
M Auf erstelltes Objekt einer anderen Klasse zugreifen. Java Basics - Anfänger-Themen 5
H Referenz Objekt aufrufen Java Basics - Anfänger-Themen 12
M Objekt mit eindeutiger ID löschen, das nächste Objekt hat dann diese ID Java Basics - Anfänger-Themen 5
N Mit Objekt der Superklasse auf Methode der Subklasse zugreifen Java Basics - Anfänger-Themen 6
E Objekt durch Benutzer über Konsole erzeugen - Java Java Basics - Anfänger-Themen 3
J Objekt bei Auswahl in jList ändern Java Basics - Anfänger-Themen 6
Kirby.exe Generische Objekt Instanz erstellen Java Basics - Anfänger-Themen 14
H Objekt aus einem Array löschen Java Basics - Anfänger-Themen 1
H Objekt im Array speichern Java Basics - Anfänger-Themen 2
H Objekt mit Methode erstellen Java Basics - Anfänger-Themen 6
H Objekt als Attribut speichern Java Basics - Anfänger-Themen 11
E Was kommt in ein Objekt und was in die Main Methode? Java Basics - Anfänger-Themen 8
R Objekt in Konstruktor ist nicht zulässig Java Basics - Anfänger-Themen 5
W OOP Objekt Methode Java Basics - Anfänger-Themen 9
A Objekt in Arrayliste Java Basics - Anfänger-Themen 2
B Mit methode Objekt aus anderer Klasse erstellen Java Basics - Anfänger-Themen 6
I Object-Oriented Programming, Objekt erzeugen Java Basics - Anfänger-Themen 1
M Objekt einer Klasse speichert die Veränderung nicht Java Basics - Anfänger-Themen 1
K Konstruktor für ein Objekt mit Zugriffsmethoden Java Basics - Anfänger-Themen 7
S Variablen Klassenvariable über Objekt aufrufen Java Basics - Anfänger-Themen 16
A Zufälliges Objekt basierend auf Wahrscheinlichkeiten bekommen. Java Basics - Anfänger-Themen 4
R Value von einem JSON-Objekt ausgeben Java Basics - Anfänger-Themen 4
P Objekt aus String-Array erzeugen Java Basics - Anfänger-Themen 104
N Bewegtes Objekt soll sich um eine Parallele bewegen Java Basics - Anfänger-Themen 0
S Objekt-Attribute "variabel" gestalten Java Basics - Anfänger-Themen 10
J Datenbankstruktur als Objekt anlegen Java Basics - Anfänger-Themen 4
L Objekt aus Textdatei in ArrayList speichern Java Basics - Anfänger-Themen 4
B Objekt an neue Stage übergeben? Java Basics - Anfänger-Themen 9
scratchy1 Wie deklariert man eine Methode, die ein Objekt zurückgeben soll? Java Basics - Anfänger-Themen 22
B Klassen Zugriff auf ein Objekt einer Klasse aus einer Methode heraus Java Basics - Anfänger-Themen 4
J Objekt erste freie Stelle zuweisen Java Basics - Anfänger-Themen 3

Ähnliche Java Themen

Neue Themen


Oben