«@ 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 DImanette
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();
}
}
Il a été inséré sans être annulé.
mysql> select * from item;
+---------+-----------+----------+
| ITEM_CD | ITEM_NAME | SELL_FLG |
+---------+-----------+----------+
| 1 | hoge | 0 |
+---------+-----------+----------+
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 ~.
@ 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.
@ Transactional
à la classe de service@ Transactional
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();
}
}
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)
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.
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);
}
}
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.
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.
Déclenche une exception ʻExceptiondans l'état par défaut sans
rollbackFor`.
@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();
}
}
Il ne sera pas annulé.
mysql> select * from item;
+---------+-----------+----------+
| ITEM_CD | ITEM_NAME | SELL_FLG |
+---------+-----------+----------+
| 1 | hoge | 0 |
+---------+-----------+----------+
Définissez rollbackFor
sur ʻException.class`.
@Transactional(rollbackFor = Exception.class)
public void insertMethodA() throws Exception{
insertMethodB();
}
Il est maintenant annulé.
mysql> select * from item;
Empty set (0.00 sec)
@ Transactional
attaché à la classe externe ne s'applique pas à la classe interneLe @ 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.
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();
}
}
}
Non annulé.
mysql> select * from item;
+---------+-----------+----------+
| ITEM_CD | ITEM_NAME | SELL_FLG |
+---------+-----------+----------+
| 1 | hoge | 0 |
+---------+-----------+----------+
Ajoutez @ Transactinal
à la classe interne.
@Service
@Transactional
public class TestInnerService{
Il a été annulé.
mysql> select * from item;
Empty set (0.00 sec)