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@ Transactional
von Methode A auf.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();
}
}
Es wurde eingefügt, ohne zurückgesetzt zu werden.
mysql> select * from item;
+---------+-----------+----------+
| ITEM_CD | ITEM_NAME | SELL_FLG |
+---------+-----------+----------+
| 1 | hoge | 0 |
+---------+-----------+----------+
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 ~.
Durch Hinzufügen von "@ Transactional" zu einer Klasse wird implizit "@ Transactional" zu allen Methoden in der Klasse hinzugefügt.
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();
}
}
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)
"@ Transactinal" hat ein Attribut namens "readonly". Wenn Sie es auf "true" setzen, wird eine Ausnahme ausgelöst, wenn der Aufzeichnungsvorgang ausgeführt wird.
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);
}
}
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.
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.
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();
}
}
Es wird nicht zurückgesetzt.
mysql> select * from item;
+---------+-----------+----------+
| ITEM_CD | ITEM_NAME | SELL_FLG |
+---------+-----------+----------+
| 1 | hoge | 0 |
+---------+-----------+----------+
Setzen Sie rollbackFor
auf Exception.class
.
@Transactional(rollbackFor = Exception.class)
public void insertMethodA() throws Exception{
insertMethodB();
}
Es wird jetzt zurückgesetzt.
mysql> select * from item;
Empty set (0.00 sec)
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.
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();
}
}
}
Nicht zurückgerollt.
mysql> select * from item;
+---------+-----------+----------+
| ITEM_CD | ITEM_NAME | SELL_FLG |
+---------+-----------+----------+
| 1 | hoge | 0 |
+---------+-----------+----------+
Fügen Sie der inneren Klasse @ Transactinal
hinzu.
@Service
@Transactional
public class TestInnerService{
Es wurde zurückgerollt.
mysql> select * from item;
Empty set (0.00 sec)