1. 程式人生 > >Day07 SpringBoot異常處理、事務處理

Day07 SpringBoot異常處理、事務處理

  • 一、事務處理

需求:當同時插入兩條資料,若有一條資料插入失敗,則兩條資料都將不插入。

分析:不用事務的話,成功的那條資料會被插入進去,導致資料不統一。

解決方案:
增加事務處理。只需要在插入資料的業務邏輯處理方法上面增加@Transactional註解

注意:必須將mysql引擎改為InnoDB才會生效
事務

controller:

@GetMapping(value = "/girls")
    public void InsertTwo(){
        girlService.InsertTwo();
    }

Service:

@Autowired
private GirlRepository girlRepository; //若不加事務,grilB出現數據異常,則B不會插入進去,A卻會插入進去 @Transactional public void InsertTwo(){ Girl girlA = new Girl(); girlA.setAge(25); girlA.setCup("C"); girlRepository.save(girlA); Girl girlB = new Girl(); girlB.setAge(28
); girlB.setCup("CCC"); girlRepository.save(girlB); }
  • 二、異常處理

需求:在實際的專案開發中,無論呼叫介面成功還是失敗,往往要求返回值有一個標準格式,來供大家檢視異常。
成功:

{
  "code": 1,
  "msg": "success",
  "data": {
   //json格式的資料資訊
  }
}

失敗:返回錯誤及錯誤資訊

{
  "code": 0,
  "msg": "error",
  "data": null
}

專案目錄結構:
專案目錄結構

  • 1.建立返回結果集用的類(Result.java)

    具體返回的資料用泛型表示(不確定會返回什麼資料,用泛型,對返回的資料不會進行限制)
package com.demo.springbootdemo.domain;

public class Result<T> {
    //錯誤碼
    private Integer code;
    //提示資訊
    private  String msg;
    //具體的內容
    private T data;

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }
}
  • 2.寫一個返回結果集的工具類(ResultUtil)
    為了使程式碼更加簡潔,複用率強。
    在這裡定義成功方法和返回方法,具體編寫成功或返回應該封裝的result資料。
package com.demo.springbootdemo.utils;

import com.demo.springbootdemo.domain.Result;

public class ResultUtil {
    public static Result success(Object object){
        Result result = new Result();
        result.setCode(0);
        result.setMsg("成功");
        result.setData(object);
        return result;
    }

    public static Result success(){
        return null;
    }

    public static Result error(Integer code, String msg){
        Result result = new Result();
        result.setCode(code);
        result.setMsg(msg);
        return result;
    }
}

-3. 寫結果列舉類(ResultEnum)統一維護
防止code,msg自己書寫導致寫重複,和,code,msg管理不方便。

package com.demo.springbootdemo.enums;

//統一維護,code,message
public enum ResultEnum {
    UNKONW_ERROR(-1,"未知錯誤"),
    success(0,"成功"),
    PRIMARY_SCHOOL(100,"你可能還在上小學"),
    MIDDLE_SCHOOL(101,"你在上初中吧");

    private Integer code;
    private String msg;

    ResultEnum(Integer code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }
}
  • 4.自定義異常類(GirlException)
    在遇到異常的時候,希望能通過code判斷{成功/自定義異常/系統未知錯誤}這裡建議自定義一個異常類。
    由於spring框架在處理Exception時不會進行事務回滾,在處理RuntimeException時會進行事務回滾,故應繼承RuntimeException
package com.demo.springbootdemo.exception;

import com.demo.springbootdemo.enums.ResultEnum;

public class GirlException extends RuntimeException{
    private Integer code;

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public GirlException(ResultEnum resultEnum) {
        super(resultEnum.getMsg());
        this.code = resultEnum.getCode();
    }
}

-5.Controller呼叫

@PostMapping(value = "/girlcheckTry")
    public Result<Girl> girlAddCheckTry(@Valid Girl girl, BindingResult bindingResult){
        if(bindingResult.hasErrors()){
           return null; //捕獲異常
            //如果驗證出錯,輸出錯誤資訊

           /*return ResultUtil.error(1,bindingResult.getFieldError().getDefaultMessage());*/
        }
        girl.setAge(girl.getAge());
        girl.setCup(girl.getCup());
        return ResultUtil.success(girlRepository.save(girl));
    }

@GetMapping(value = "/girls/getAge/{id}")
    public void getAge(@PathVariable("id") Integer id) throws Exception {
        girlService.getAge(id);
    }

Service業務層具體使用時丟擲異常,等待統一處理

public Girl getAge(Integer id) throws Exception {
        Optional<Girl> girl = girlRepository.findById(id);
        Integer age =girl.get().getAge();
        if(age < 10){
            throw new GirlException(ResultEnum.PRIMARY_SCHOOL);
        }else if(age > 10 && age < 16){
            throw new GirlException(ResultEnum.MIDDLE_SCHOOL);
        }
        return girl.get();
    }
  • 6.ExceptionHandle

在異常丟擲後,建立一個類捕獲程式執行中出現的所以異常,集中處理。

注意:在這裡捕獲處理過的異常,控制檯不會自動列印,因此在這裡捕捉到了系統錯誤,處理時需手動列印,以免實際執行中找不到錯誤原因

package com.demo.springbootdemo.handle;

import com.demo.springbootdemo.domain.Result;
import com.demo.springbootdemo.exception.GirlException;
import com.demo.springbootdemo.utils.ResultUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;


@ControllerAdvice
public class ExceptionHandle {

    private final static Logger logger = LoggerFactory.getLogger(ExceptionHandle.class);
    //捕獲異常類
    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public Result handle(Exception e){
        if(e instanceof GirlException){
            GirlException girlException = (GirlException) e;
            return ResultUtil.error(girlException.getCode(),girlException.getMessage());
        }else{
            logger.error("系統異常{}",e);
            return ResultUtil.error(-1,"未知錯誤");
        }

    }
}