详解Spring事务

目录

1.声明式事务

1.1.概述

1.2.使用

1.2.1.建表

1.2.2.maven依赖

1.2.3.配置

1.2.4.业务

1.2.5.测试

 2.事务的传播行为


1.声明式事务

1.1.概述

spring中事务分为两种:

1.编程式事务,通过写代码来实现,每一步。

2.声明式事务,直接通过配置来实现。

常用的是声明式事务,接下来介绍的也是声明式事务。

1.2.使用

1.2.1.建表

一个用户表,有id和账户余额两个字段。

CREATE TABLE user (
    id INT(255) AUTO_INCREMENT PRIMARY KEY,
    balance INT(255)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

insert into user VALUES(NULL,100),(NULL,100);

1.2.2.maven依赖


    5.2.0.RELEASE



    
        org.springframework
        spring-core
        ${spring.version}
    
    
        org.springframework
        spring-context
        ${spring.version}
    
    
        org.springframework
        spring-tx
        ${spring.version}
    
    
        org.springframework
        spring-jdbc
        ${spring.version}
    
    
    
        com.mchange
        c3p0
        0.9.5.5
    

    
    
        mysql
        mysql-connector-java
        8.0.18
    

1.2.3.配置

尤其要注意命名空间不要少引入!!!



    
    
        
        
        
        
    
    
        
    
    
    
        
    
    
    

    
    

1.2.4.业务

这里模拟id为1的用户向id为2的用户转账100块,转账有两步组成:

  • id为1的用户账户扣100块
  • id为2的用户账户增加100块

在两步中模拟一个异常,导致只有只完成了id为1的用户扣100块的SQL执行了,但是id为2的用户增加100块的SQL没有执行。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

@Component
public class UserService {
    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Transactional
    public void transfer(){
        try {
            // 从 fromUserId 账户中扣除金额
            jdbcTemplate.update("update user set balance = balance - ? where id = ?", 100, 1);

            // 抛出异常,测试事务是否回滚
            int i = 1 / 0;

            // 将金额转入 toUserId 账户中
            jdbcTemplate.update("update user set balance = balance + ? where id = ?", 100, 2);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

1.2.5.测试

public static void main(String[] args) {
        ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
        UserService userService = applicationContext.getBean("userService", UserService.class);
        userService.transfer();
    }

如果没有事务的话,会是这种情况:

详解Spring事务_第1张图片

 有了事务的话,事务中所有SQL会具有原子性,要么全部成功,要么全部失败,会是这个结果:

详解Spring事务_第2张图片

 2.事务的传播行为

Spring中存在着一个概念——事务的传播行为。事务的传播行为指的是一个事务方法被另一个事务方法调用,即嵌套事务,出现异常该怎么回滚。 

Spring规定有7种事务的传播行为:

required 如果出现异常的方法有事务就用这个事务,没有的话再去用其他的事务。例如:方法A调用方法B,如果B出现异常,B有事务就用B的事务,B没有事务,才会去用A的事务(只要有一个回滚,整体就会回滚)
requires_new 如果当前有事务,就用当前事务,否则就重新开一个事务。例如:方法A调用方法B,如果B出现异常,B有事务就用B的事务,B没有事务,就会去新建一个事务,最后效果是B会回滚,但是A不会回滚。
supports 当前没有事务,就以非事务运行。当前有事务呢?就以当前事务运行。
mandatory 其他没有事务就会抛异常。当前没有事务抛出异常,当前有事务则支持当前事务。
not_supported 以非事务执行。
never 以非事务执行,如果存在事务,抛出异常。
nested 如果当前已经存在一个事务,那么该方法将会在嵌套事务中运行。嵌套的事务可以独立于当前事务进行单独地提交或回滚。

这里附上一篇其它博主对于七种事务的传播属性的介绍,其中有详细的代码示例和讲解,很清晰:

Spring事务传播行为_荠菜煎包的博客-CSDN博客

你可能感兴趣的:(spring,java,mysql)