The Spring annotation "
@ Transactional "is convenient because it automatically executes a transaction just by attaching it to a method and rolls back when a RuntimeException occurs by default. However, there are cases where the transaction cannot be performed just by adding `` `@ Transactional
, and it does not cause a build error, so when I actually moved it, the transaction was not performed.
So, I have summarized how to use `` `@ Transactional``` to work.
After moving it around and checking it, it seems that the following conditions must be met.
--It must be a public method of the class you are DI --Called directly by another class or framework that is DI
There is also a method of using Bean definition file as a method of DI class, but here we will describe the implementation using Spring annotation.
ServiceClass.java
@Service
public class ServiceClass {
@Transactional
public void updateDB() {
//DB update process
}
}
In the above, `@ Service``` is attached to the class, but other annotations that do DI such as
@ Controller``` and ``
@ Repository``` will also work.
The class that calls the above ServiceClass is as follows.
ControllerClass.java
@RequestMapping("/sample/*")
@Controller
public class ControllerClass {
@Autowired
ServiceClass serviceClass;
@RequestMapping(value = { "index" })
public String index(){
serviceClass.updateDB();
return "sample/index";
}
}
This is also a class that is DI using `` `@ Controller.
@autowired```The transaction works by automatically creating an instance of serviceclass using and calling the updatedb method.
It also works when a method with @ Transactional
is called from the Spring framework.
In the following cases, the transaction operates when the request corresponding to the setting of @ RequestMapping
comes and the method is called.
ControllerClass.java
@RequestMapping("/sample/*")
@Controller
public class ControllerClass {
@Autowired
ServiceClass serviceClass;
@RequestMapping(value = { "index" })
@Transactional
public String index(){
serviceClass.updateDB();
return "sample/index";
}
}
ServiceClass.java
@Service
public class ServiceClass {
public void updateDB() {
//DB update process
}
}
Also, the transaction works in the same way when the method is called by specifying the time by `` `@ Scheduled```.
ControllerClass.java
@Controller
public class ControllerClass {
@Autowired
ServiceClass serviceClass;
@Scheduled(cron = "0 0 10 * * *")
@Transactional
public String index(){
serviceClass.updateDB();
return "sample/index";
}
}
Considering a practical implementation, I want to roll back even if an exception other than RuntimeException occurs.
@Transactional(rollbackFor = Exception.class)Set Exception and classes that inherit Exception to be rolled back when thrown.
Try-catch with the calling method and divide the process according to success or failure.
#### **`ControllerClass.java`**
```java
@RequestMapping("/sample/*")
@Controller
public class ControllerClass {
@Autowired
ServiceClass serviceClass;
@RequestMapping(value = { "exec" })
public String exec(Model model){
try {
//Calling a method that makes a transaction
serviceClass.transaction();
//What to do if successful
model.addAttribute("message", "The process was successful.");
} catch (Exception e) {
//Processing when processing fails
if (e.getMessage() != null) {
model.addAttribute("message", e.getMessage());
} else {
model.addAttribute("message", "An error has occurred.");
}
return "sample/index";
}
return "sample/complete";
}
}
ServiceClass.java
@Service
public class ServiceClass {
@Transactional(rollbackFor = Exception.class)
public void transaction() throws Exception {
//A series of processes that you want to transaction
//If you want to roll back, throw Exception as below
throw new Exception("Processing failed.");
}
}
Recommended Posts