[JAVA] J'ai essayé de vérifier ceci et celui de Spring @ Transactional

«@ Transactional» de Spring est une annotation pratique qui revient automatiquement lorsqu'une exception se produit. Cependant, (je) ne vérifie pas la restauration dans le test unitaire, et parfois je me demande si cela fonctionne vraiment.

J'ai donc essayé de vérifier le mouvement de @ Transactional de différentes manières.

** Environnement de confirmation ** JDK 1.8.0 Spring Boot 2.0.5.RELEASE Doma2.0

@ Transactional ne fonctionne que s'il est attaché à une méthode appelée directement depuis la classe DI

Procédure de vérification

  1. Appelez la méthode A dans le service qui est DI à partir du contrôleur.
  2. Appelez la méthode B avec «@ Transactional» à partir de la méthode A.
  3. Soulevez une exception immédiatement après avoir inséré un enregistrement dans la base de données avec la méthode B.

code de vérification

manette


public class TestController {

    @Autowired
    TestService testService;

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

un service


@Service
public class TestService {

    @Autowired
    ItemDao itemDao;

    public void insertMethodA() {
        insertMethodB();
    }

    @Transactional
    public void insertMethodB() {

        //Insérer un enregistrement prêt
        Item item = new Item();
        item.setItemCd("1");
        item.setItemName("hoge");
        item.setSellFlg("0");

        //Insérer un enregistrement
        itemDao.insert(item);

        //Il y a une exception
        throw new RuntimeException();
    }
}

Résultat d'exécution

Il a été inséré sans être annulé.

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

Correction de code

Ajoutez @ Transactional à la méthode A.


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

    public void insertMethodB() {

        //Insérer un enregistrement prêt
        Item item = new Item();
        item.setItemCd("1");
        item.setItemName("hoge");
        item.setSellFlg("0");

        //Insérer un enregistrement
        itemDao.insert(item);

        //Il y a une exception
        throw new RuntimeException();
    }

** Résultat d'exécution **

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

Il a été annulé. Oui ok ~.

Si vous ajoutez @ Transactinal à une classe, il sera attaché à toutes les méthodes de la classe.

L'ajout de «@ Transactional» à une classe ajoute implicitement «@ Transactional» à toutes les méthodes de la classe.

Procédure de vérification

  1. Ajoutez @ Transactional à la classe de service
  2. Appelez la méthode A depuis le contrôleur sans ajouter @ Transactional

code de vérification

Le contrôleur est le même que celui ci-dessus (appelez la méthode A depuis la classe de service).

un service


@Service
@Transactional
public class TestService {

    @Autowired
    ItemDao itemDao;

    public void insertMethodA() {
        insertMethodB();
    }

    public void insertMethodB() {

        //Insérer un enregistrement prêt
        Item item = new Item();
        item.setItemCd("1");
        item.setItemName("hoge");
        item.setSellFlg("0");

        //Insérer un enregistrement
        itemDao.insert(item);

        //Il y a une exception
        throw new RuntimeException();
    }
}

Résultat d'exécution

Il a été annulé. L'appel de la méthode B à partir du contrôleur a également été annulé.

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

Une exception est levée lorsque vous essayez de manipuler un enregistrement avec l'attribut readonly défini sur true

@ Transactinal a un attribut appelé readonly, et si vous le définissez sur true, il lèvera une exception lors de l'exécution du processus d'opération d'enregistrement.

code de vérification

Le contrôleur utilisé ci-dessus.

un service


@Service
public class TestService {

    @Autowired
    ItemDao itemDao;

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

    public void insertMethodB() {

        //Insérer un enregistrement prêt
        Item item = new Item();
        item.setItemCd("1");
        item.setItemName("hoge");
        item.setSellFlg("0");

        //Insérer un enregistrement
        itemDao.insert(item);
    }
}

Résultat d'exécution

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

Il est préférable de le définir comme un service d'acquisition qui n'est pas censé être mis à jour.

Vous pouvez définir une exception d'occurrence de cible d'annulation avec l'attribut rollbackFor

Par défaut, les exceptions annulées sont «RuntimeException» et ses sous-classes. L'attribut rollbackFor remplace la classe d'exception définie dans la valeur et ses sous-classes par l'exception levée à restaurer.

code de vérification

Déclenche une exception ʻExceptiondans l'état par défaut sansrollbackFor`.

@Service
public class TestService {

    @Autowired
    ItemDao itemDao;

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

    public void insertMethodB() throws Exception{

        //Insérer un enregistrement prêt
        Item item = new Item();
        item.setItemCd("1");
        item.setItemName("hoge");
        item.setSellFlg("0");

        //Insérer un enregistrement
        itemDao.insert(item);

        //Il y a une exception
        throw new Exception();
    }
}

Résultat d'exécution

Il ne sera pas annulé.

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

Changement de code

Définissez rollbackFor sur ʻException.class`.


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

Résultat de l'exécution (après modification)

Il est maintenant annulé.

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

@ Transactional attaché à la classe externe ne s'applique pas à la classe interne

Le @ Transactional attaché à la classe externe ne s'applique pas à la classe interne, il doit donc être attaché à la classe interne séparément. Soyez prudent lorsque vous utilisez des classes internes dans Junit pour superposer des classes de test.

code de vérification

manette

public class TestController {

    @Autowired
    TestService testService;

    @Autowired
    TestService.TestInnerService testInnerService;

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

un service


@Service
@Transactional
public class TestService {

    @Autowired
    ItemDao itemDao;

    @Service
    public class TestInnerService{

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

        public void insertMethodB(){

            //Insérer un enregistrement prêt
            Item item = new Item();
            item.setItemCd("1");
            item.setItemName("hoge");
            item.setSellFlg("0");

            //Insérer un enregistrement
            itemDao.insert(item);

            //Il y a une exception
            throw new RuntimeException();
        }
    }
}

Résultat d'exécution

Non annulé.

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

Changement de code

Ajoutez @ Transactinal à la classe interne.


    @Service
    @Transactional
    public class TestInnerService{

Résultat de l'exécution (après modification)

Il a été annulé.

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

Recommended Posts

J'ai essayé de vérifier ceci et celui de Spring @ Transactional
J'ai essayé de lier JavaFX et Spring Framework.
J'ai essayé de vérifier yum-cron
J'ai essayé de réduire la capacité de Spring Boot
J'ai essayé de résumer les bases de kotlin et java
Ceci et cela de JDK
Ceci et cela du contrôle exclusif
J'ai essayé de résumer les méthodes de Java String et StringBuilder
Ceci et cela de Swift Corner Radius
J'ai essayé Spring.
Je veux afficher des images avec REST Controller de Java et Spring!
J'ai essayé de résumer les points clés de la conception et du développement de gRPC
J'ai essayé de mesurer et de comparer la vitesse de Graal VM avec JMH
J'ai essayé de vérifier AdoptOpenJDK 11 (11.0.2) avec l'image Docker
J'ai essayé de lier grafana et postgres [docker-compose]
C # (base de l'encapsulation)
Ceci et celui de la dérivation conditionnelle du développement des rails
J'ai essayé de vérifier si ce serait amusant de combiner «programmation» et «hobbies».
J'ai essayé de cloner une application Web pleine de bugs avec Spring Boot
J'ai essayé de convertir Java Bean et XML avec le formateur XML de Jackson à cette époque
[J'ai essayé] Tutoriel de printemps
J'ai essayé Spring Batch
J'ai essayé d'implémenter le téléchargement de fichiers avec Spring MVC
J'ai essayé de lire et de sortir CSV avec Outsystems
J'ai essayé d'intégrer le bouton AWS I oT et Slack
J'ai essayé de démarrer avec Spring Data JPA
J'ai essayé de résumer divers link_to utilisés cette fois
J'ai essayé de mâcher C # (lire et écrire des fichiers)
J'ai essayé de créer une fonction / écran d'administrateur de site commercial avec Java et Spring
J'ai essayé d'utiliser Wercker pour créer et publier une image Docker qui lance GlassFish 5
Janken de Sazae J'ai essayé de vérifier la valeur théorique et la valeur mesurée de la probabilité de la même main 5 fois consécutives avec Ruby
L'argument de link_to est nul (nul) et un lien inattendu a été généré, j'ai donc essayé de le vérifier
J'ai essayé de collecter et de résoudre les problèmes liés à la «classe» de Ruby.
J'ai essayé la machine Spring State
J'ai essayé de développer une application web à partir d'un mois et demi d'histoire d'apprentissage de la programmation
J'ai essayé JAX-RS et pris note de la procédure
J'ai essayé de faire coexister Java Optional et la clause de garde
J'ai brièvement résumé la grammaire de base de Ruby
J'ai essayé de résumer les applications et les outils de développement personnellement utiles (outils de développement)
J'ai essayé de créer un environnement de WSL2 + Docker + VSCode
J'ai essayé de créer une application qui vous permet de publier et de discuter par genre ~ Vue d'ensemble de l'application ~
[Pour les débutants Swift] J'ai essayé de résumer le cycle de mise en page désordonné de ViewController et View
J'ai essayé de résumer les applications et les outils de développement personnellement utiles (Apps)
[Rails] strftime ceci et cela
J'ai créé un client RESAS-API en Java
Certificat électronique ceci et cela
J'ai essayé de démarrer avec Swagger en utilisant Spring Boot
Encodeur Base64 ceci et cela
J'ai essayé d'exprimer les résultats avant et après de la classe Date avec une ligne droite numérique
J'ai essayé d'imprimer un formulaire avec Spring MVC et Jasper Reports 1/3 (paramètres Jasper Reports)
J'ai essayé d'implémenter le traitement Ajax de la fonction similaire dans Rails
Je veux comprendre le flux des paramètres de demande de traitement Spring
J'ai essayé d'intégrer parfaitement Docker et Maven / Netbean en utilisant Jib