详解事务传播特性

事务传播特性汇总:

required:使用当前的事务,如果当前没有事务,则创建一个事务,子方法是必须运行在一个事务中的,如果当前存在事务,则加入这个事务,成为一个整体。

supports:如果当前有事务,则使用事务,如果当前没有事务,则不使用事务

mandatory:该传播属性强制必须存在一个事务,如果不存在,则抛出异常

required_new:如果当前有事务,则挂起该事务,并且自己创建一个新的事务给自己使用;如果当前没有事务,则同required   

not_support:如果当前有事务,则把事务挂起,自己不使用事务去进行数据库操作

never:如果当前事务存在,则抛出异常

nested:  如果当前有事务,则开启子事务(嵌套事务),嵌套事务是独立提交或者回滚;如果当前没有事务,则同required

但是如果父事务提交,则会携带子事务一起提交。如果父事务回滚,则子事务会一起回滚。相反,子事务异常,则父事务可以不会滚(捕获子事务的异常),也可以回滚。

有异常才会回滚事务,如果异常被捕获,也就是try,catch,就不会回滚事务了,

发生异常,或者抛出异常都会回滚事务

准备工作

演示required

每次测试之前都会清空数据库

导入test依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

编写test类

import com.imooc.Application;
import com.imooc.service.impl.TestTransService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
public class TransTest {
    @Autowired
    private TestTransService testTransService;
    /*
    * 事务传播特性
    *   required:
    *   supports:
    *   mandatory:
    *   required_new:
    *   not_supported:
    *   never:
    *   nested:
    * */
    @Test
    public void demo(){
        testTransService.saveParent();
        testTransService.saveChildren();
    }
}

编写需要的测试方法

package com.imooc.service.impl;

import com.imooc.mapper.StuMapper;
import com.imooc.pojo.Stu;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class TestTransService {
    @Autowired
    private StuMapper stuMapper;
    public void saveParent(){
        Stu stu=new Stu();
        stu.setName("parent");
        stu.setAge(55);
        stuMapper.insert(stu);
    }
    public void saveChildren(){
        saveChild1();
        int a=1/0;
        saveChild2();
    }
    public void saveChild1(){
        Stu stu1=new Stu();
        stu1.setName("child-1");
        stu1.setAge(11);
        stuMapper.insert(stu1);
    }
    public void saveChild2(){
        Stu stu2=new Stu();
        stu2.setName("child-2");
        stu2.setAge(22);
        stuMapper.insert(stu2);
    }
}

没有开启事务,直接测试

报错:java.lang.ArithmeticException: / by zero

结论:在报错之前,已经执行的代码会进行数据库操作,之后代码没有执行,也就没有操作数据库

在demo()方法上开启事务,进行测试

import com.imooc.Application;
import com.imooc.service.impl.TestTransService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
public class TransTest {
    @Autowired
    private TestTransService testTransService;
    /*
    * 事务传播特性
    *   required:
    *   supports:
    *   mandatory:
    *   required_new:
    *   not_supported:
    *   never:
    *   nested:
    * */
    @Transactional(propagation = Propagation.REQUIRED)
    @Test
    public void demo(){
        testTransService.saveParent();
        testTransService.saveChildren();
    }
}

报错:java.lang.ArithmeticException: / by zero

结论:事务具有传播特性,demo()方法开启事务,方体体里面的方法也具有事务,所以报错后数据库进行了回滚操作

如果demo方法没有开启事务,在saveChildren()上开启了事务(  @Transactional(propagation = Propagation.REQUIRED))

,则会保存saveParent()方法插入的数据。

required:使用当前的事务,如果当前没有事务,则创建一个事务,子方法是必须运行在一个事务中的,如果当前存在事务,则加入这个事务,成为一个整体。

================================================================================================

演示required_new

spring boot测试环境会自动回滚,不适合测试事务,直接使用开发环境,然后用postman调用

controller

package com.imooc.controller;

import com.imooc.service.impl.TestTransService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class TestTransController {
    @Autowired
    private TestTransService testTransService;
    @PostMapping("/demo")
    @Transactional(propagation = Propagation.REQUIRED)
    public void demo()throws Exception{
        testTransService.saveParent();
        testTransService.saveChildren();
    }
}

demo()方法上面加@Transactional(propagation = Propagation.REQUIRED)

saveChildren()方法上面加@Transactional(propagation = Propagation.REQUIRES_NEW)

调用postman运行

报错:java.lang.NullPointerException: null

结论:由于抛出空指针异常,所以saveChildren()这个新事物会回滚,而抛出的异常会传递给父方法,父方法的事务也会回滚,所有没有一条记录

另外一种情况

saveChildren()

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void saveChildren(){
        saveChild1();
        /*String demon=null;
        System.out.println(demon.charAt(0));*/
        saveChild2();
    }
demo()
    @PostMapping("/demo")
    @Transactional(propagation = Propagation.REQUIRED)
    public void demo(){
        testTransService.saveParent();
        testTransService.saveChildren();
        String demon=null;
        System.out.println(demon.charAt(0));
    }

调用postman

报错:java.lang.NullPointerException: null

结论:可以证明required_new创建的时新事务

================================================================================================

演示nested

saveChildren
    @Transactional(propagation = Propagation.NESTED)
    public void saveChildren(){
        saveChild1();
        saveChild2();
    }
demo
    @PostMapping("/demo")
    @Transactional(propagation = Propagation.REQUIRED)
    public void demo(){
        testTransService.saveParent();
        testTransService.saveChildren();
        String demon=null;
        System.out.println(demon.charAt(0));
    }

调用postman

报错是一定的:java.lang.NullPointerException: null

结论:父事务回滚,子事务也一起回滚

另外一种情况

demo
    @PostMapping("/demo")
    @Transactional(propagation = Propagation.REQUIRED)
    public void demo(){
        testTransService.saveParent();
        testTransService.saveChildren();

    }
saveChildren
    @Transactional(propagation = Propagation.NESTED)
    public void saveChildren(){
        saveChild1();
        String demon=null;
        System.out.println(demon.charAt(0));
        saveChild2();
    }

万年不变报错:java.lang.NullPointerException: null

结论:子事务异常,父事务没有捕获异常,则一起回滚

另外一种情况

saveChildren
    @Transactional(propagation = Propagation.NESTED)
    public void saveChildren(){
        saveChild1();
        String demon=null;
        System.out.println(demon.charAt(0));
        saveChild2();
    }
demo
    @PostMapping("/demo")
    @Transactional(propagation = Propagation.REQUIRED)
    public void demo(){
        testTransService.saveParent();
        try {
            //相当于数据库中的savepoint 捕获异常之后,不影响其他事务操作
            testTransService.saveChildren();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

调用postman:

报错:java.lang.NullPointerException

结论:捕获子事务异常之后,父事务不需要回滚,子事务进行回滚

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值