Announcement

Collapse
No announcement yet.

EntityManager/User-/EntityTransaction -> Rollback

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • EntityManager/User-/EntityTransaction -> Rollback

    Moin,

    bin grad ein wenig am verzweifeln, weil ich so langsam das Gefühl haben, für mein Problem gäbe es keine Lösung.

    Ist-Zustand:
    WebService-Schicht -> Controller-Schicht -> Service-Schicht -> OracleDB

    Für JUnitTests zum testen der WebServices setze ich OpenEJB ein. Der Test befindet sich in der WebService-Schicht.

    Die Service-Schicht, holt sich per Injection einen EntityManager und persistiert darauf die Daten die ich über die WebService-Schicht abgebe.

    Soll-Zustand:
    Nun würde ich am liebsten folgendes tun. Ich öffne eine Transaction (wie auch immer), stoße meine tests an und lasse zu den bestehenden Stammdaten, Testdaten generieren. Ich führe einen Rollback auf der Transaction aus, so dass die daten aus dem Test da auf keinen Fall verbleiben.

    Nun der Part wo ihr mir Helfen könnt:
    Wo und wie sind Transactions und EntityManager gültig?
    Die JTA-Spec verbietet es mir, dass ich mir per getTransaction aus einem in den JUnitTest Injezierten EntityManager die Transaction ziehe die wohlmöglich ?global? gültig ist? Ist das allgemein eine falsche herangehensweise?
    Gibt es eine bessere?

    Ich hab da einfach überhaupt keine Idee mehr für einen Ansatz. Ich hoffe ihr habt noch was in Petto!!!

    Schöne Grüße,
    Uschi

    edit:
    eine per @Resource injezierte UserTransaction bringt mir auch nur für den lokal injezierten EntityManager etwas. Wenn ich direkt etwas an diesem persiste, verschwindet das durch einen Rollback wieder. Wenn ich mir ID's ansehe sind beim debuggen, der EntityManager im JUnitTest und die EntityManager in der Service-Schicht jedes mal andere. Auch für jeden Persistierungsvorgang im Backend (also auch innerhalb eines einzelnen WebService-Aurufs mit mehreren Objekten die persitiert werden) einen anderen EntityManager.

  • #2
    Ich fasse zusammen:

    Du willst in Transaktion 1 die Testdaten in die Oracle-DB schreiben, aber nicht committen. Dann willst du in deinem Service mit Transaktion 2 die Daten lesen/ändern und committen(?) und danach einen Rollback auf Transaktion 1 durchführen und die Daten wieder zu löschen.

    Das wird so nicht gehen: Damit du in der Transaktion 2 die Daten überhaupt sehen kannst, müssten diese in der TA 1 mit TA-Level "Read Uncommitted" geschrieben werden. Soweit ich in Erinnerung habe unterstützt Oracle diesen TA-Level nicht - das kann aber evtl. von der verwendeten Version von Oracle abhängen (DB und/oder Treiber).

    Und selbst wenn du in der TA 2 die nicht-committeten Daten von TA 1 siehst, weiss ich nicht, ob du diese ändern kannst, möglichst noch mit einem Commit auf TA 2.

    Habe ich dasso richtig verstanden? Dann würde ich das nicht so machen, sondern eher "klassisch" vorgehen: Testdaten im "setUp()" einfügen und committen, Testcase ausführen und im "tearDown()" die Testdaten explizit löschen.

    Comment


    • #3
      so schnell eine reaktion =)

      folgendes kann sich für jemanden der sich mit EJB und Transactions auskennt dumm klingen, aber theoretisch wäre es das optimum, könnte ich um alles eine transaction öffnen.

      ich habe aber auch schon gemerkt, das pro JUnitTest eine instand der Testklasse erstellt wird, seh ich das richtig? Denn folgende Methoden werden für jeden Test/Webserviceaufruf ausgeführt:
      Code:
      @Resource
      UserTransaction userTransaction;
      
      @Before
      public void doBefore(){
      userTransaction.beginn();
      }
      
      @After
      public void doAfter(){
      userTransaction.rollback();
      }
      Im Einsatz ist eine OracleXE. Ob sie diesen TA-Level unterstützt, weiss ich nicht. Werde ich morgen rausfinden! Ein explizites tearDown wie du es nennst wäre sehr ungünstig und umstöndlich. Es sollen ja vor allem nur die hinzugefügten Sachen gelöscht werden, nicht aber Stammdaten. Dann wären da noch Objekte die erst in der Service-Schicht generiert werden, wo ich keine ID's von habe.

      Die Tests können dann auch noch Fehlschlagen. Dazu sind sie ja da und dadurch werden dann ab ner gewissen Stelle keine weiteren Daten mehr erstellt. Löschen ist auch immer ein Problem weil es sehr viele Constraints gibt.

      Nochmal zurück zum Anfang:
      Ich möchte alle, während des Test, erstellten Daten aus allen EntityManagern am ende wieder aus der Datenbank raushaben.

      Ich möchte am liebsten nur eine Transaction haben, das wäre ja aber schon aus dem Grund schwachsinnig weil das ein Dauer-Lock auf die DB haben würde. Also nur gut wenn das aus dem Test heraus anstoßbar sein würde.

      Da fehlt mir halt komplett das Wissen wie, wo, wann und wielang EntityManager und Transactions gültig sind.

      Comment


      • #4
        Mir ging es mit meiner Antwort lediglich darum klarzumachen, dass du mit deinem Ansatz evtl. Probleme bekommst, die zunächst nicht mit Embeddable-EJB3-Container, Annotations, UserTransactions, EntityManager ... zu tun haben.

        So gesehen kann ich dir zu deiner eigentlichen Frage der "Sichtbarkeit" des EntityMangers und der Transaktionen im JUnitTest nicht viel sagen. Ich würde aber - bevor ich mich in den o.g. Komponenten mit Fehlersuche verliere zunächst mal auf SQL/JDBC-Ebene testen, ob es funktioniert (Z.B. mit SQLExplorer einen Datensatz einfügen und nicht committen, und dann per Java/JDBC versuchen den Datensatz zu lesen). Wenn das nicht klappt, dann helfen auch keine EntityManager o.ä.

        Comment


        • #5
          Schau dir doch mal DBUnit an, ob es dir vielleicht helfen kann:

          http://www.land-of-kain.de/docs/ejb3_dbunit/

          Comment

          Working...
          X