通过手动抛自定义异常实现spring事务回滚

spring默认事务管理:默认当一个方法出现RunTimeException(运行期异常)时会自动回滚事务。

有些时候,我们需要从业务上对spring事务进行控制,这时候,如果用spring的默认事务管理,事务没有回滚就达不到我们所期望的结果。

demo用的spring+mybatis+springmvc+mysql。

解决方法:

applicationContext-service.xml 中增删改方法加上rollback-for="MyException",当方法抛出自定义异常被spring接收,会回滚事务。

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop" 
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:task="http://www.springframework.org/schema/task"
    xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans-4.2.xsd 
        http://www.springframework.org/schema/mvc 
        http://www.springframework.org/schema/mvc/spring-mvc-4.2.xsd 
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context-4.2.xsd 
        http://www.springframework.org/schema/aop 
        http://www.springframework.org/schema/aop/spring-aop-4.2.xsd 
        http://www.springframework.org/schema/tx 
        http://www.springframework.org/schema/tx/spring-tx-4.2.xsd
        http://www.springframework.org/schema/task
           http://www.springframework.org/schema/task/spring-task-4.2.xsd
        http://code.alibabatech.com/schema/dubbo        
        http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
        
        
        <!-- 配置  扫描   @Service -->
        <context:component-scan base-package="com.educloud.service"/>
        
        <!-- 事务管理器 -->
    <bean id="transactionManager"
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!-- 数据源 -->
        <property name="dataSource" ref="dataSource" />
    </bean>
    <!-- 通知 -->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <!-- 传播行为 -->
            <tx:method name="save*" propagation="REQUIRED" rollback-for="MyException"/>
            <tx:method name="insert*" propagation="REQUIRED" rollback-for="MyException"/>
            <tx:method name="add*" propagation="REQUIRED" rollback-for="MyException"/>
            <tx:method name="create*" propagation="REQUIRED" rollback-for="MyException"/>
            <tx:method name="delete*" propagation="REQUIRED" rollback-for="MyException"/>
            <tx:method name="update*" propagation="REQUIRED" rollback-for="MyException"/>
            <tx:method name="find*" propagation="SUPPORTS" read-only="true" />
            <tx:method name="select*" propagation="SUPPORTS" read-only="true" />
            <tx:method name="get*" propagation="SUPPORTS" read-only="true" />
        </tx:attributes>
    </tx:advice>
    <!-- 切面 -->
    <aop:config>
        <aop:advisor advice-ref="txAdvice"
            pointcut="execution(* com.educloud.service.impl.*.*(..))" />
    </aop:config>
        
        
</beans>
View Code

MyException 自定义异常类:

public class MyException extends Exception {

private String message;

public String getMessage() {
return message;
}

public void setMessage(String message) {
this.message = message;
}

public MyException(String message) {
super();
this.message = message;
}

public MyException() {
super();
}

public MyException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}

public MyException(String message, Throwable cause) {
super(message, cause);
}

public MyException(Throwable cause) {
super(cause);
}
View Code

ProMapper.java

package com.educloud.mapper;

import com.educloud.pojo.Pro;

public interface ProMapper {
    

    int deletePro(Integer id);
    
    int insertPro(Pro record);

    Pro selectPro(Integer id);

    int updatePro(Pro record);

}
View Code

ProMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.educloud.mapper.ProMapper" >
  <resultMap id="BaseResultMap" type="com.educloud.pojo.Pro" >
    <id column="id" property="id" jdbcType="INTEGER" />
    <result column="pro_name" property="proName" jdbcType="VARCHAR" />
    <result column="data_flag" property="dataFlag" jdbcType="INTEGER" />
    <result column="create_date" property="createDate" jdbcType="TIMESTAMP" />
  </resultMap>
  
  <sql id="Base_Column_List" >
    id, pro_name, data_flag, create_date
  </sql>
 
  <select id="selectPro" resultMap="BaseResultMap" parameterType="java.lang.Integer" >
    select 
    <include refid="Base_Column_List" />
    from pro
    where id = #{id,jdbcType=INTEGER}
  </select>
  
  <delete id="deletePro" parameterType="java.lang.Integer" >
    delete from pro
    where id = #{id,jdbcType=INTEGER}
  </delete>
  
  
  <insert id="insertPro" parameterType="com.educloud.pojo.Pro" >
      <selectKey keyProperty="id" resultType="Integer" order="AFTER">
          select LAST_INSERT_ID()
      </selectKey>
      
    insert into pro
    <trim prefix="(" suffix=")" suffixOverrides="," >
      <if test="proName != null and proName != '' " >
        pro_name,
      </if>
      <if test="dataFlag != null" >
        data_flag,
      </if>
      <if test="createDate != null" >
        create_date,
      </if>
    </trim>
    <trim prefix="values (" suffix=")" suffixOverrides="," >
      <if test="proName != null and proName != '' " >
        #{proName,jdbcType=VARCHAR},
      </if>
      <if test="dataFlag != null" >
        #{dataFlag,jdbcType=INTEGER},
      </if>
      <if test="createDate != null" >
        #{createDate,jdbcType=TIMESTAMP},
      </if>
    </trim>
  </insert>
  
  
  
  <update id="updatePro" parameterType="com.educloud.pojo.Pro" >
    update pro
    <set >
      <if test="proName != null" >
        pro_name = #{proName,jdbcType=VARCHAR},
      </if>
      <if test="dataFlag != null" >
        data_flag = #{dataFlag,jdbcType=INTEGER},
      </if>
      <if test="createDate != null" >
        create_date = #{createDate,jdbcType=TIMESTAMP},
      </if>
    </set>
    where id = #{id,jdbcType=INTEGER}
  </update>
 
</mapper>
View Code

ProDetailMapper.java

package com.educloud.mapper;

import com.educloud.pojo.ProDetail;

public interface ProDetailMapper {

    int deleteProDetail(Integer id);


    int insertProDetail(ProDetail record);


    ProDetail selectProDetail(Integer id);

  
    int updateProDetail(ProDetail record);

}
View Code

ProDetailMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.educloud.mapper.ProDetailMapper" >
  <resultMap id="BaseResultMap" type="com.educloud.pojo.ProDetail" >
    <id column="id" property="id" jdbcType="INTEGER" />
    <result column="pro_detail_name" property="proDetailName" jdbcType="VARCHAR" />
    <result column="data_flag" property="dataFlag" jdbcType="INTEGER" />
    <result column="create_date" property="createDate" jdbcType="TIMESTAMP" />
    <result column="pro_id" property="proId" jdbcType="INTEGER" />
  </resultMap>
  
  <sql id="Base_Column_List" >
    id, pro_detail_name, data_flag, create_date, pro_id
  </sql>

  
  <select id="selectProDetail" resultMap="BaseResultMap" parameterType="java.lang.Integer" >
    select 
    <include refid="Base_Column_List" />
    from pro_detail
    where id = #{id,jdbcType=INTEGER}
  </select>
  
  <delete id="deleteProDetail" parameterType="java.lang.Integer" >
    delete from pro_detail
    where id = #{id,jdbcType=INTEGER}
  </delete>
  
  
  <insert id="insertProDetail" parameterType="com.educloud.pojo.ProDetail" >
    insert into pro_detail
    <trim prefix="(" suffix=")" suffixOverrides="," >
      
      <if test="proDetailName != null and proDetailName != '' " >
        pro_detail_name,
      </if>
      <if test="dataFlag != null" >
        data_flag,
      </if>
      <if test="createDate != null" >
        create_date,
      </if>
      <if test="proId != null" >
        pro_id,
      </if>
    </trim>
    <trim prefix="values (" suffix=")" suffixOverrides="," >
      
      <if test="proDetailName != null and proDetailName != '' " >
        #{proDetailName,jdbcType=VARCHAR},
      </if>
      <if test="dataFlag != null" >
        #{dataFlag,jdbcType=INTEGER},
      </if>
      <if test="createDate != null" >
        #{createDate,jdbcType=TIMESTAMP},
      </if>
      <if test="proId != null" >
        #{proId,jdbcType=INTEGER},
      </if>
    </trim>
  </insert>
  
  
  
  <update id="updateProDetail" parameterType="com.educloud.pojo.ProDetail" >
    update pro_detail
    <set >
      <if test="proDetailName != null" >
        pro_detail_name = #{proDetailName,jdbcType=VARCHAR},
      </if>
      <if test="dataFlag != null" >
        data_flag = #{dataFlag,jdbcType=INTEGER},
      </if>
      <if test="createDate != null" >
        create_date = #{createDate,jdbcType=TIMESTAMP},
      </if>
      <if test="proId != null" >
        pro_id = #{proId,jdbcType=INTEGER},
      </if>
    </set>
    where id = #{id,jdbcType=INTEGER}
  </update>
  
</mapper>
View Code

ProService.java

package com.educloud.service;

import com.educloud.pojo.Pro;
import com.educloud.utils.MyException;

public interface ProService {
    
    int deletePro(Integer id) throws MyException;
    
    int insertPro(String proStr) throws MyException;

    Pro selectPro(Integer id) throws MyException;

    int updatePro(Pro record) throws MyException;

}
View Code

ProController.java

package com.educloud.controller;

import java.util.HashMap;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.educloud.pojo.Pro;
import com.educloud.service.ProService;
import com.educloud.utils.MyException;

@Controller
public class ProController {
    
    @Autowired
    private ProService proService;
    
    @RequestMapping(value="/insertPro")
    @ResponseBody
    public Map<String, Object> insertPro(String proStr){
        //模拟前台数据
        proStr = "{"pro": {"proName": "体"},"proDetailList": [{"proDetailName": "身高"},{"proDetailName": ""},{"proDetailName": "健康状况"}]}";
        Map<String, Object> map = new HashMap<>();
        String mString = "";
        try {
            int count = proService.insertPro(proStr);
            mString = "新增成功!";
        } catch (MyException e) {
            mString = e.getMessage();
        }
        map.put("msg", mString);
        return map;
    }

}
View Code

ProServiceImpl.java

方法抛出自定义异常  thorw new MyException();

package com.educloud.service.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.educloud.mapper.ProDetailMapper;
import com.educloud.mapper.ProMapper;
import com.educloud.pojo.Pro;
import com.educloud.pojo.ProDetail;
import com.educloud.service.ProService;
import com.educloud.utils.MyException;

@Service
public class ProServiceImpl implements ProService {
    
    @Autowired
    private ProMapper proMapper;
    
    @Autowired
    private ProDetailMapper proDetailMapper;

    @Override
    public int insertPro(String proStr) throws MyException{
        // proStr = "{"pro": {"proName": "体"},"proDetailList": [{"proDetailName": "身高"},{"proDetailName": ""},{"proDetailName": "健康状况"}]}";
        
        //把json字符串转为json对象
        JSONObject object = JSONObject.parseObject(proStr);
        //获得pro评价指标对象
        JSONObject proObj = object.getJSONObject("pro");
        Pro pro = new Pro();
        pro.setProName(proObj.getString("proName"));
        int count = 0;
        count = proMapper.insertPro(pro);
        if (count ==0) {
            throw new MyException("新增指标失败!");
        }
        //获得proDetail评价指标明细list
        JSONArray proDetailList = object.getJSONArray("proDetailList");
        ProDetail proDetail = null;
        int count1 = 0;
        
        //方式一:
        for (int i = 0; i < proDetailList.size(); i++) {
            //获得proDetail评价指标明细list每一条数据
            JSONObject proDetailObj = proDetailList.getJSONObject(i);
            proDetail = new ProDetail();
            proDetail.setProDetailName(proDetailObj.getString("proDetailName"));
            proDetail.setProId(pro.getId());
            try {
                count1 += proDetailMapper.insertProDetail(proDetail);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        //抛自定义异常进行事务控制
        if (count1 < proDetailList.size()) {
            throw new MyException("新增指标明细失败!");
        }
        return 1;
        
        //方式二
//        for (int i = 0; i < proDetailList.size(); i++) {
//            /**获得proDetail评价指标明细list每一条数据*/
//            JSONObject proDetailObj = proDetailList.getJSONObject(i);
//            proDetail = new ProDetail();
//            proDetail.setProDetailName(proDetailObj.getString("proDetailName"));
//            proDetail.setProId(pro.getId());
//            count1 += proDetailMapper.insertProDetail(proDetail);
//        }
//        int resultNum = proDetailList.size() + 1; 
//        /**抛自定义异常进行事务控制*/
//        if(resultNum == count+count1){
//            return 1;
//        }else{
//            throw new MyException("新增失败!");
//        }
        
    }
    
    @Override
    public int deletePro(Integer id) throws MyException{
        return proMapper.deletePro(id);
    }

    
    @Override
    public Pro selectPro(Integer id) throws MyException{
        return proMapper.selectPro(id);
    }

    @Override
    public int updatePro(Pro record) throws MyException{
        return proMapper.updatePro(record);
    }

}
View Code

Pro.java

package com.educloud.pojo;

import java.util.Date;

public class Pro {
    private Integer id;

    private String proName;

    private Integer dataFlag;

    private Date createDate;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getProName() {
        return proName;
    }

    public void setProName(String proName) {
        this.proName = proName == null ? null : proName.trim();
    }

    public Integer getDataFlag() {
        return dataFlag;
    }

    public void setDataFlag(Integer dataFlag) {
        this.dataFlag = dataFlag;
    }

    public Date getCreateDate() {
        return createDate;
    }

    public void setCreateDate(Date createDate) {
        this.createDate = createDate;
    }

    @Override
    public String toString() {
        return "Pro [id=" + id + ", proName=" + proName + ", dataFlag=" + dataFlag + ", createDate=" + createDate + "]";
    }
    
    
}
View Code

项目百度网盘地址: https://pan.baidu.com/s/1L_zMjmqu-gXRqifcVEfQ1A  提取码: idii 

原文地址:https://www.cnblogs.com/javalanger/p/10912482.html