webentwicklung-frage-antwort-db.com.de

Wie lösche ich Daten in der aktiven Frühlingstransaktion in die Datenbank?

Ich möchte die save () - Methode der Hibernate-Sitzung mit dem Frühlingstest-Framework testen. @ Test Methode ist:

@Test
@Transactional
public void testSave() {
    User expected = createUser();
    getGenericDao().currentSession().save(expected);
    User actual = getUser(generatedId);
    assertUsersEqual(expected,actual);
}

Ich möchte den Benutzer in die Datenbank spülen. Ich möchte, dass sich mein Benutzer nach dieser Methode in der Datenbank befindet

getGenericDao().currentSession().save(expected);

Dann möchte ich mit Spring Data Framework zur Datenbank gehen und diesen gespeicherten Benutzer in der nächsten Zeile abrufen:

User actual = getUser(generatedId);

Ich habe versucht, die Ruhezustandsmethode wie folgt zu verwenden:

currentSession().setFlushMode(MANUAL);
//do saving here
currentSession().flush();

Es spült meinen Benutzer nicht in die Datenbank! Wenn ich jedoch @Transactional Spring Annotation nicht verwende und meinen Benutzer in einer programmgesteuerten Spring-Transaktion speichere, erreiche ich, was ich will. Leider wird der in db gespeicherte Benutzer dann nicht zurückgesetzt, da es kein spring @Transactional gibt. Daher ändert meine Testmethode die Datenbank und das Verhalten nachfolgender Testmethoden.

Ich muss also meinen Benutzer in die Datenbank innerhalb der Testmethode (nicht am Ende) einweihen und am Ende der Testmethode alle Änderungen in die Datenbank zurücksetzen.

UPDATEvorschlag zur vorbereitung der methode wie folgt:

@Transactional
public void doSave(User user){
    getGenericDao().currentSession().save(user);
}

Und ruf doSave in testSave macht nichts. Trotzdem habe ich keinen Benutzer in der Datenbank, nachdem ich diese Methode ausgeführt habe. Ich setze einen Haltepunkt und überprüfe meine Datenbank von der Kommandozeile aus.

UPDATEVielen Dank für die Antwort. Das Problem ist, dass die Methode flush () meinen Benutzer nicht in die Datenbank einfügt. Ich habe Isolation.READ_UNCOMMITTED ausprobiert und meinen Benutzer nicht in die Datenbank einfügt. Ich kann erreichen, was ich will, aber nur, wenn ich die Frühlingstransaktion auf der @ Test-Methode deaktiviere und in der programmatischen Transaktion speichere. ABER dann wird die @ Test-Methode nicht zurückgesetzt und der gespeicherte Benutzer bleibt für nachfolgende @ Test-Methoden erhalten. Hier ist die @ Test-Methode zum Speichern des Benutzers nicht so gefährlich wie die @ Test-Methode zum Löschen des Benutzers, da sie nicht zurückgesetzt wird. Es muss also eine Frühlingstransaktionsunterstützung für die @ Test-Methode geben, mit der ich meinen Benutzer ohnehin nicht in db eintragen (oder löschen) kann. Tatsächlich wird der Benutzer erst in die Datenbank verschoben (oder gelöscht), nachdem die @ Test-Methode beendet und die Transaktion für die @ Test-Methode festgeschrieben wurde. Also möchte ich meinen Benutzer in der Mitte der @ Test-Methode in db speichern und es am Ende der @ Test-Methode zurücksetzen

Vielen Dank!

13

Schließlich hielt ich an der folgenden Lösung fest:

Erstens laufen meine @Test-Methoden nicht im Spring @Transactional-Support. In diesem Artikel erfahren Sie, wie gefährlich es sein kann. Statt @Repository-Beans in @Test-Methoden zu verwenden, verwende ich automatisch @Service-Beans, die @Transactional-Annotation verwenden. Das Wunder ist die @Test-Methode wie diese 

@Test
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void testSave() {
    Answer created = createAnswer();
    Long generatedId = answerService.save(created);
//at this moment answer is already in db
    Answer actual=getAnswerById(generatedId);
... }

setzt mein Answer-Objekt in die Datenbank (direkt nach answerService.save(created);) und die Methode getAnswerById geht in die DB und extrahiert sie, um zu prüfen, ob das Speichern korrekt war.
Um Änderungen an der Datenbank in der @Test-Methode zu entfernen, stelle ich die Datenbank mit JdbcTestUtils.executeSqlScript neu ein.

9
  1. Werfen Sie einen Blick auf hier mit Warnung vor @Transactional-Tests ( Spring Pitfalls: Transaktionsprüfungen als schädlich ). Ich habe @org.springframework.test.context.jdbc.Sql verwendet, um DB in meinen Servicetests und @Transactional für Controller erneut aufzufüllen.
  2. ConstraintViolationException für den Controller-Aktualisierungstest mit ungültigen Daten wurde nur ausgegeben, wenn die Transaktion festgeschrieben ist. Ich habe also 3 Optionen gefunden:
    • 2.1 Kommentieren Sie den Test mit @Commit oder mit @Transactional(propagation = Propagation.NEVER). Beachten Sie die DB-Änderung.
    • 2.2 Verwenden Sie TestTransaction

Code:

     TestTransaction.flagForCommit();
     TestTransaction.end();
  • 2.3 Verwenden Sie TransactionTemplate

Code:

    @Autowired
    private PlatformTransactionManager platformTransactionManager;

    @Test(expected = Exception.class)
    public void testUpdate() throws Exception {
        TransactionTemplate transactionTemplate = new TransactionTemplate(platformTransactionManager);
        transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
        String json = ...
        transactionTemplate.execute(ts -> {
            try {
                mockMvc.perform(put(REST_URL + USER_ID)
                    .contentType(MediaType.APPLICATION_JSON)
                    .content(json))
                    .andExpect(status().isOk());
                ...
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        });
4
GKislin

Wenn flush nicht funktioniert, hängt es sehr stark von der Isolationsstufe Ihrer Datenbank ab. 

Isolation ist eine der ACID-Eigenschaften der Datenbank, die definiert, wie und wann die von einer Operation vorgenommenen Änderungen für andere gleichzeitige Operationen sichtbar werden.

Ich glaube, Ihre Isolationsstufe ist auf Read Committed oder Repeatable Read eingestellt. 

1
JSS

Sie sollten sich auch um das importierte Paket kümmern: In meinem Fall habe ich importiert

import javax.transaction.Transactional;

anstatt 

import org.springframework.transaction.annotation.Transactional;

0
Meinew