通过手动抛自定义异常实现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>
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); }
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); }
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>
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);
}
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>
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; }
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; } }
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); } }
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 + "]"; } }
项目百度网盘地址: https://pan.baidu.com/s/1L_zMjmqu-gXRqifcVEfQ1A 提取码: idii