美文网首页
Spring事务为什么不生效?

Spring事务为什么不生效?

作者: AnimoBlog | 来源:发表于2020-08-25 16:47 被阅读0次

本文章通过SpringBoot2.2.0.RELEASE,mybatis-spring-boot-starter2.1.1构建的测试项目。

Bean

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Nav {

    private Integer id;

    private String name;

    private Integer pid;

    private String des;

    private String key;

    public Nav(String name, Integer pid) {
        this.name = name;
        this.pid = pid;
    }
}

Mapper

@Mapper
public interface NavMapper {
    /**
     * 保存
     * @param nav
     * @return
     */
    void save(Nav nav);
    /**
     * 根据Id获取导航栏
     * @param id
     * @return
     */
    Nav getById(Integer id);
    /**
     * 更新对象
     * @param nav
     */
    void update(Nav nav);
}

Mapper 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.animo.mybatis.mapper.NavMapper">

    <insert id="save" parameterType="com.animo.mybatis.entity.Nav"
            useGeneratedKeys="true" keyProperty="id">
        insert into nav (name,pid) values (#{name},#{pid})
    </insert>

    <update id="update">
      update nav set name = #{name} where id = #{id}
    </update>

    <select id="getById" resultType="com.animo.mybatis.entity.Nav">
        select id,name from nav where id = #{-parameters}
    </select>
</mapper>

#{-parameters}:当你在处理一个带有多个形参的构造方法时,很容易搞乱 arg 元素的顺序。 从版本 3.4.3 开始,可以在指定参数名称的前提下,以任意顺序编写 arg 元素。 为了通过名称来引用构造方法参数,你可以添加 @Param 注解,或者使用 '-parameters' 编译选项并启用 useActualParamName 选项(默认开启)来编译项目。

Server

@Transactional(rollbackFor = Exception.class)
    public void transactionalTest(Integer id){
        try {
            //1.先查询
            Nav nav = navMapper.getById(id);
            //2.更新
            nav.setName("事务测试更新");
            navMapper.update(nav);
            //3.新增
            navMapper.save(new Nav("事务测试保存",3));
            FileOutputStream fileOutputStream = new FileOutputStream(new File("/usr/local/xxx.html"));
            //.....重要代码
        }catch (IOException e){
        }
    }

这边多条SQL操作需开启事务保证原子性,代码中有个文件找不到异常这里是测试异常,不过业务角度的话可能是很重要的代码需要被捕获。

测试结果

事务的话遇到异常就会回滚所以我们带着这个理念测试类执行以下代码之后的数据库前后的状态。

  • 执行前数据状态


    执行前数据状态

这边代码执行之后肯定是报异常了java.io.FileNotFoundException: /usr/local/xxx.html (Permission denied),由于我们捕获了异常很显然事务回滚失效了。

  • 执行后数据状态


    执行后数据状态

解决方案

程序运行如果没有错误会自动提交事务,如果程序发生异常则会自动回滚。
但是如果使用了try捕获异常(检查时异常)时,一定要注意在catch里面手动回滚否者事务失效。

手动回滚

try{
    //重要代码
}catch(Exception e){
    e.printStackTrace();
    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}

抛出异常

try{
    //重要代码
}catch(Exception e){
    e.printStackTrace();
    throw new Exception();
}

在Web开发中一般会自定义异常,然后通过全局异常处理人性化返回提示,这里可以抛出自定义异常一样可以回滚事务。

博客链接:http://www.ljyanimo.com/

相关文章

网友评论

      本文标题:Spring事务为什么不生效?

      本文链接:https://www.haomeiwen.com/subject/urezjktx.html