I'm creating microservice application with spring boot. so, just think there are 2 services called A and B. A makes a request to do some execution to B by HTTP. so, the database might not be available in some times when the request are coming. that kind of situation, A service has to know if it's a connection error from the database side or one of other exceptions from the service B.
if A server will be known about that, A server can replay
the request again after connection fixed.
for that I want to filter the connection-exception
from the exception that MYSQL throws.
but I tried to catch it in the service layer by using Exception
. unfortunately the error is not caught.
the code like below.
try {
userRepository.incrementReputationByOne(userUid);
} catch (Exception e) {
//the exception doesn't come here
e.printStackTrace();
}
I want to set the Http status code as HttpStatus.SERVICE_UNAVAILABLE
. then the service A know that the error is due to the connection issue oof the database or endpoint. the the server can retry the request again after while or some scheduled time.
CodePudding user response:
You can't catch the SQLException related to the repository in the service layer like this. because the transaction is managed from the service layer. therefore you have to use the try-catch block in the controller layer. otherwise, the request status will be internal-server-error
. if you catch the transaction error in the controller layer, you have to duplicate the same catch process for each. therefore you can use a ControllerAdvice
.
anyway, the spring does not throw the SQL exception directly. instead of that spring will throw the CannotCreateTransactionException
. it contains the ConnectException
. spring provides a handy method to find out if it contains the exception that you are looking for.
without ControllerAdvice
in the controller's method, you can catch the error like below.
@PutMapping
public ResponseEntity<?> incrementByOne(@RequestParam("user_uid") String userUid) {
try {
userService.incrementReputationByOne(userUid);
} catch (CannotCreateTransactionException e) {
if (e.contains(ConnectException.class)) {
log.debug("ConnectException {}", e.getMessage());
return ResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE).build();
} else {
ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
}
return ResponseEntity.ok().build();
}
with ControllerAdvice
if you use ControllerAdvice to catch the exception, it is very easy and you don't want to cath the database exception the service layer or controller layer as well.
@ControllerAdvice
@Slf4j
@ResponseBody
public class DatabaseExceptionHandler {
@ExceptionHandler(value = {CannotCreateTransactionException.class})
public ResponseEntity<?> cannotCreateTransactionException(CannotCreateTransactionException exception, WebRequest request) {
if (exception.contains(ConnectException.class)) {
log.error("DB ConnectException : {}", exception.getMessage());
return ResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE).build();
}else {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
}
}
in your service layer keep your code without catching errors. the ControllerAdvice
will take care of the exceptions.