[JAVA] Ich habe versucht, dies und das von Spring @ Transactional zu überprüfen

Spring's @ Transactional ist eine praktische Anmerkung, die automatisch zurückgesetzt wird, wenn eine Ausnahme auftritt. Allerdings überprüfe (I) das Rollback im Unit-Test nicht, und manchmal mache ich mir Sorgen, ob es wirklich funktioniert.

Also habe ich versucht, die Bewegung von "@ Transactional" auf verschiedene Weise zu überprüfen.

** Bestätigungsumgebung ** JDK 1.8.0 Spring Boot 2.0.5.RELEASE Doma2.0

@ Transactional funktioniert nur, wenn es an eine Methode angehängt ist, die direkt von der DI-Klasse aufgerufen wird

Überprüfungsverfahren

  1. Rufen Sie Methode A im Dienst DI von der Steuerung auf.
  2. Rufen Sie Methode B mit @ Transactional von Methode A auf.
  3. Auslösen einer Ausnahme unmittelbar nach dem Einfügen eines Datensatzes in die Datenbank mit Methode B.

Verifizierungs-Schlüssel

Regler


public class TestController {

    @Autowired
    TestService testService;

    @PostMapping("/post")
    public void postTest() {
        testService.insertMethodA();
    }
}

Bedienung


@Service
public class TestService {

    @Autowired
    ItemDao itemDao;

    public void insertMethodA() {
        insertMethodB();
    }

    @Transactional
    public void insertMethodB() {

        //Datensatz fertig einfügen
        Item item = new Item();
        item.setItemCd("1");
        item.setItemName("hoge");
        item.setSellFlg("0");

        //Datensatz einfügen
        itemDao.insert(item);

        //Ausnahme aufgetreten
        throw new RuntimeException();
    }
}

Ausführungsergebnis

Es wurde eingefügt, ohne zurückgesetzt zu werden.

mysql> select * from item;
+---------+-----------+----------+
| ITEM_CD | ITEM_NAME | SELL_FLG |
+---------+-----------+----------+
| 1       | hoge      | 0        |
+---------+-----------+----------+

Code korrigieren

Fügen Sie Methode A "@ Transactional" hinzu.


    @Transactional
    public void insertMethodA() {
        insertMethodB();
    }

    public void insertMethodB() {

        //Datensatz fertig einfügen
        Item item = new Item();
        item.setItemCd("1");
        item.setItemName("hoge");
        item.setSellFlg("0");

        //Datensatz einfügen
        itemDao.insert(item);

        //Ausnahme aufgetreten
        throw new RuntimeException();
    }

** Ausführungsergebnis **

mysql> select * from item;
Empty set (0.00 sec)

Es wurde zurückgerollt. Ja ok ~.

Wenn Sie einer Klasse "@ Transactinal" hinzufügen, wird es an alle Methoden in der Klasse angehängt.

Durch Hinzufügen von "@ Transactional" zu einer Klasse wird implizit "@ Transactional" zu allen Methoden in der Klasse hinzugefügt.

Überprüfungsverfahren

  1. Fügen Sie der Serviceklasse "@ Transactional" hinzu
  2. Rufen Sie Methode A vom Controller aus auf, ohne "@ Transactional" hinzuzufügen

Verifizierungs-Schlüssel

Der Controller ist derselbe wie oben (Aufrufmethode A aus der Serviceklasse).

Bedienung


@Service
@Transactional
public class TestService {

    @Autowired
    ItemDao itemDao;

    public void insertMethodA() {
        insertMethodB();
    }

    public void insertMethodB() {

        //Datensatz fertig einfügen
        Item item = new Item();
        item.setItemCd("1");
        item.setItemName("hoge");
        item.setSellFlg("0");

        //Datensatz einfügen
        itemDao.insert(item);

        //Ausnahme aufgetreten
        throw new RuntimeException();
    }
}

Ausführungsergebnis

Es wurde zurückgesetzt. Das Aufrufen von Methode B von der Steuerung wurde ebenfalls zurückgesetzt.

mysql> select * from item;
Empty set (0.00 sec)

Eine Ausnahme wird ausgelöst, wenn versucht wird, einen Datensatz mit dem Attribut "readonly" zu manipulieren, das auf "true" gesetzt ist

"@ Transactinal" hat ein Attribut namens "readonly". Wenn Sie es auf "true" setzen, wird eine Ausnahme ausgelöst, wenn der Aufzeichnungsvorgang ausgeführt wird.

Verifizierungs-Schlüssel

Der oben verwendete Controller.

Bedienung


@Service
public class TestService {

    @Autowired
    ItemDao itemDao;

    @Transactional(readOnly = true)
    public void insertMethodA() {
        insertMethodB();
    }

    public void insertMethodB() {

        //Datensatz fertig einfügen
        Item item = new Item();
        item.setItemCd("1");
        item.setItemName("hoge");
        item.setSellFlg("0");

        //Datensatz einfügen
        itemDao.insert(item);
    }
}

Ausführungsergebnis

java.sql.SQLException: Connection is read-only. Queries leading to data modification are not allowed

Es ist besser, es als Akquisitionsdienst festzulegen, der nicht aktualisiert werden soll.

Sie können eine Ausnahme für das Auftreten eines Rollback-Ziels mit dem Attribut "rollbackFor" festlegen

Standardmäßig sind die zurückgesetzten Ausnahmen "RuntimeException" und seine Unterklassen. Das Attribut rollbackFor ändert die im Wert festgelegte Ausnahmeklasse und ihre Unterklassen in die ausgelöste Ausnahme, die zurückgesetzt werden soll.

Verifizierungs-Schlüssel

Lösen Sie eine "Ausnahme" -Ausnahme im Standardzustand ohne "rollbackFor" aus.

@Service
public class TestService {

    @Autowired
    ItemDao itemDao;

    @Transactional
    public void insertMethodA() throws Exception{
        insertMethodB();
    }

    public void insertMethodB() throws Exception{

        //Datensatz fertig einfügen
        Item item = new Item();
        item.setItemCd("1");
        item.setItemName("hoge");
        item.setSellFlg("0");

        //Datensatz einfügen
        itemDao.insert(item);

        //Ausnahme aufgetreten
        throw new Exception();
    }
}

Ausführungsergebnis

Es wird nicht zurückgesetzt.

mysql> select * from item;
+---------+-----------+----------+
| ITEM_CD | ITEM_NAME | SELL_FLG |
+---------+-----------+----------+
| 1       | hoge      | 0        |
+---------+-----------+----------+

Codeänderung

Setzen Sie rollbackFor auf Exception.class.


    @Transactional(rollbackFor = Exception.class)
    public void insertMethodA() throws Exception{
        insertMethodB();
    }

Ausführungsergebnis (nach Änderung)

Es wird jetzt zurückgesetzt.

mysql> select * from item;
Empty set (0.00 sec)

An die äußere Klasse angehängtes "@ Transactional" gilt nicht für die innere Klasse

Das an die äußere Klasse angehängte "@ Transactional" gilt nicht für die innere Klasse, daher muss es separat an die innere Klasse angehängt werden. Seien Sie vorsichtig, wenn Sie innere Klassen in Junit verwenden, um Testklassen zu schichten.

Verifizierungs-Schlüssel

Regler

public class TestController {

    @Autowired
    TestService testService;

    @Autowired
    TestService.TestInnerService testInnerService;

    @PostMapping("/post")
    public void postTest() throws Exception{
       testInnerService.insertMethodA();
    }
}

Bedienung


@Service
@Transactional
public class TestService {

    @Autowired
    ItemDao itemDao;

    @Service
    public class TestInnerService{

        public void insertMethodA() throws Exception{
            insertMethodB();
        }

        public void insertMethodB(){

            //Datensatz fertig einfügen
            Item item = new Item();
            item.setItemCd("1");
            item.setItemName("hoge");
            item.setSellFlg("0");

            //Datensatz einfügen
            itemDao.insert(item);

            //Ausnahme aufgetreten
            throw new RuntimeException();
        }
    }
}

Ausführungsergebnis

Nicht zurückgerollt.

mysql> select * from item;
+---------+-----------+----------+
| ITEM_CD | ITEM_NAME | SELL_FLG |
+---------+-----------+----------+
| 1       | hoge      | 0        |
+---------+-----------+----------+

Codeänderung

Fügen Sie der inneren Klasse @ Transactinal hinzu.


    @Service
    @Transactional
    public class TestInnerService{

Ausführungsergebnis (nach Änderung)

Es wurde zurückgerollt.

mysql> select * from item;
Empty set (0.00 sec)

Recommended Posts

Ich habe versucht, dies und das von Spring @ Transactional zu überprüfen
Ich habe versucht, JavaFX und Spring Framework zu verknüpfen.
Ich habe versucht, yum-cron zu verifizieren
Ich habe versucht, die Kapazität von Spring Boot zu reduzieren
Ich habe versucht, die Grundlagen von Kotlin und Java zusammenzufassen
Dies und das von JDK
Dies und das der ausschließlichen Kontrolle
Ich habe versucht, die Methoden von Java String und StringBuilder zusammenzufassen
Dies und das von Swift Corner Radius
Ich habe es mit Spring versucht.
Ich möchte Bilder mit REST Controller von Java und Spring anzeigen!
Ich habe versucht, die wichtigsten Punkte des gRPC-Designs und der Entwicklung zusammenzufassen
Ich habe versucht, die Geschwindigkeit von Graal VM mit JMH zu messen und zu vergleichen
Ich habe versucht, AdoptOpenJDK 11 (11.0.2) mit dem Docker-Image zu überprüfen
Ich habe versucht, grafana und postgres [docker-compose] zu verknüpfen
C # (Grund der Kapselung)
Dies und das der bedingten Verzweigung der Schienenentwicklung
Ich habe versucht zu überprüfen, ob es Spaß machen würde, "Programmierung" und "Hobbys" zu kombinieren.
Ich habe versucht, eine Webanwendung voller Fehler mit Spring Boot zu klonen
In dieser Zeit habe ich versucht, Java Bean und XML mit dem Jackson-Formatierer XML zu konvertieren
[Ich habe es versucht] Spring Tutorial
Ich habe Spring Batch ausprobiert
Ich habe versucht, das Hochladen von Dateien mit Spring MVC zu implementieren
Ich habe versucht, CSV mit Outsystems zu lesen und auszugeben
Ich habe versucht, AWS I oT Button und Slack zu integrieren
Ich habe versucht, mit Spring Data JPA zu beginnen
Ich habe versucht, verschiedene link_to zusammenzufassen, die dieses Mal verwendet wurden
Ich habe versucht, C # zu kauen (Dateien lesen und schreiben)
Ich habe versucht, mit Java und Spring eine Funktion / einen Bildschirm für den Administrator einer Einkaufsseite zu erstellen
Ich habe versucht, mit Wercker ein Docker-Image zu erstellen und zu veröffentlichen, mit dem GlassFish 5 gestartet wird
Sazae's Janken Ich habe versucht, den theoretischen Wert und den gemessenen Wert der Wahrscheinlichkeit derselben Hand 5 Mal hintereinander mit Ruby zu überprüfen
Das Argument von link_to ist nil (null) und ein unerwarteter Link wurde generiert, daher habe ich versucht, ihn zu überprüfen
Ich habe versucht, Rubys "Klassen" -Probleme zu sammeln und zu lösen.
Ich habe Spring State Machine ausprobiert
Ich habe versucht, eine Webanwendung aus anderthalb Monaten Programmier-Lerngeschichte zu entwickeln
Ich habe JAX-RS ausprobiert und mir das Verfahren notiert
Ich habe versucht, Java Optional und Guard-Klausel koexistieren zu lassen
Ich habe die grundlegende Grammatik von Ruby kurz zusammengefasst
Ich habe versucht, persönlich nützliche Apps und Entwicklungstools (Entwicklungstools) zusammenzufassen.
Ich habe versucht, eine Umgebung mit WSL2 + Docker + VSCode zu erstellen
Ich habe versucht, eine App zu erstellen, mit der Sie nach Genre posten und chatten können ~ Übersicht über die App ~
[Für Swift-Anfänger] Ich habe versucht, den chaotischen Layoutzyklus von ViewController und View zusammenzufassen
Ich habe versucht, persönlich nützliche Apps und Entwicklungstools (Apps) zusammenzufassen.
[Rails] strftime dies und das
Ich habe einen RESAS-API-Client in Java erstellt
Elektronisches Zertifikat dies und das
Ich habe versucht, mit Swagger mit Spring Boot zu beginnen
Base64 Encoder dies und das
Ich habe versucht, die Ergebnisse vor und nach der Date-Klasse mit einer geraden Zahl auszudrücken
Ich habe versucht, ein Formular mit Spring MVC und Jasper Reports 1/3 (Jasper Reports-Einstellungen) zu drucken.
Ich habe versucht, die Ajax-Verarbeitung der ähnlichen Funktion in Rails zu implementieren
Ich möchte den Ablauf der Spring-Verarbeitungsanforderungsparameter verstehen
Ich habe versucht, Docker und Maven / Netbean mit Jib gut zu integrieren