Spring中事务的传播机制

232 阅读5分钟

1、以下是事物的传播机制:

@Transactional(propagation=Propagation.REQUIRED)
如果有事务, 那么加入事务, 没有的话新建一个(默认情况下)
换句话说,使用当前的事务,如果当前没有事务,则自己新建一个事务,
子方法是必须运行在一个事务中的,如果当前存在事务,则加入这个事务,成为一个整体
@Transactional(propagation=Propagation.SUPPORTS)
如果当前有事务,则使用事务,如果当前没有事务,则不使用事务
@Transactional(propagation=Propagation.MANDATORY)
必须在一个已有的事务中执行,否则抛出异常
@Transactional(propagation=Propagation.REQUIRES_NEW)
不管是否存在事务,都创建一个新的事务,原来的挂起,新的执行完毕,继续执行老的事务
@Transactional(propagation=Propagation.NOT_SUPPORTED)
容器不为这个方法开启事务
@Transactional(propagation=Propagation.NEVER)
必须在一个没有的事务中执行,否则抛出异常(与Propagation.MANDATORY相反)
@Transactional(propagation=Propagation.NESTED)
父子嵌套事务,父事务发生错误回滚,子方法如果是嵌套事务,则一起回滚。
相反,如果子方法发生错误,在父方法try catch后,父方法则不不需要一起回滚。

2、代码验证说明:

2.1 无任何事务

// service层
public interface StuService {
    public void saveParent();
    public void saveChildren();
}
// service实现类
@Service
public class StuServiceImpl implements StuService {
    @Autowired
    private StuMapper stuMapper;
    
    @Override
    public void saveParent(){
        Stu stu = new Stu();
        stu.setAge(19);
        stu.setName("parent");
        stuMapper.insert(stu);
    }
    @Override
    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);
    }

}
//测试service接口及实现类

public interface TransTest {
    public void testPropagationTrans();
}


@Service
public class TransTestImpl implements TransTest {
    @Autowired
    private StuService stuService;

    @Override
    public void testPropagationTrans() {
        stuService.saveParent();
        stuService.saveChildren();
    }
}
// 单元测试


@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)  //配置启动类
public class Test {
    @Autowired
    private TransTest transTest;
    @org.junit.Test
    public void myTest(){
        transTest.testPropagationTrans();
    }
}

结果:

2.2 测试Propagation.REQUIRED

2.2.1 父方法有Propagation.REQUIRED

@Service
public class StuServiceImpl implements StuService {
    @Autowired
    private StuMapper stuMapper;
    
    @Override
    public void saveParent(){
        Stu stu = new Stu();
        stu.setAge(19);
        stu.setName("parent");
        stuMapper.insert(stu);
    }
    @Override
    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);
    }

}
@Service
public class TransTestImpl implements TransTest {
    @Autowired
    private StuService stuService;

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public void testPropagationTrans() {
        stuService.saveParent();
        stuService.saveChildren();
    }
}

结果: 数据库未新增任何数据。

2.2.2 子方法有Propagation.REQUIRED

@Service
public class StuServiceImpl implements StuService {
    @Autowired
    private StuMapper stuMapper;
    
    @Override
    public void saveParent(){
        Stu stu = new Stu();
        stu.setAge(19);
        stu.setName("parent");
        stuMapper.insert(stu);
    }
    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    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);
    }

}
@Service
public class TransTestImpl implements TransTest {
    @Autowired
    private StuService stuService;

    @Override
    public void testPropagationTrans() {
        stuService.saveParent();
        stuService.saveChildren();
    }
}

结果:

2.3 Propagation.SUPPORTS

2.3.1子方法SUPPORTS,父方法无事务

@Service
public class StuServiceImpl implements StuService {
    @Autowired
    private StuMapper stuMapper;
    
    @Override
    public void saveParent(){
        Stu stu = new Stu();
        stu.setAge(19);
        stu.setName("parent");
        stuMapper.insert(stu);
    }
    @Override
    @Transactional(propagation = Propagation.SUPPORTS)
    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);
    }

}
@Service
public class TransTestImpl implements TransTest {
    @Autowired
    private StuService stuService;

    @Override
    public void testPropagationTrans() {
        stuService.saveParent();
        stuService.saveChildren();
    }
}

结果:

2.3.2 子方法SUPPORTS,父方法REQUIRD

@Service
public class StuServiceImpl implements StuService {
    @Autowired
    private StuMapper stuMapper;
    
    @Override
    public void saveParent(){
        Stu stu = new Stu();
        stu.setAge(19);
        stu.setName("parent");
        stuMapper.insert(stu);
    }
    @Override
    @Transactional(propagation = Propagation.SUPPORTS)
    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);
    }

}
@Service
public class TransTestImpl implements TransTest {
    @Autowired
    private StuService stuService;

    @Override
    @Transactional(propagation = Propagation.REQUIRD)
    public void testPropagationTrans() {
        stuService.saveParent();
        stuService.saveChildren();
    }
}

结果: 数据库无任何新增。

2.4 Propagation.MANDATORY

2.4.1 子方法有MANDATORY,父方法无事务

@Service
public class StuServiceImpl implements StuService {
    @Autowired
    private StuMapper stuMapper;
    
    @Override
    public void saveParent(){
        Stu stu = new Stu();
        stu.setAge(19);
        stu.setName("parent");
        stuMapper.insert(stu);
    }
    @Override
    @Transactional(propagation = Propagation.MANDATORY)
    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);
    }

}
@Service
public class TransTestImpl implements TransTest {
    @Autowired
    private StuService stuService;

    @Override
    public void testPropagationTrans() {
        stuService.saveParent();
        stuService.saveChildren();
    }
}

结果抛出异常:

2.4.2 子方法有MANDATORY,父方法有有REQUIRD

@Service
public class StuServiceImpl implements StuService {
    @Autowired
    private StuMapper stuMapper;
    
    @Override
    public void saveParent(){
        Stu stu = new Stu();
        stu.setAge(19);
        stu.setName("parent");
        stuMapper.insert(stu);
    }
    @Override
    @Transactional(propagation = Propagation.MANDATORY)
    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);
    }

}
@Service
public class TransTestImpl implements TransTest {
    @Autowired
    private StuService stuService;

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public void testPropagationTrans() {
        stuService.saveParent();
        stuService.saveChildren();
    }
}

结果:数据库无任何变化。

2.5 Propagation.REQUIRES_NEW

@Service
public class StuServiceImpl implements StuService {
    @Autowired
    private StuMapper stuMapper;
    
    @Override
    public void saveParent(){
        Stu stu = new Stu();
        stu.setAge(19);
        stu.setName("parent");
        stuMapper.insert(stu);
    }
    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    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);
    }

}
@Service
public class TransTestImpl implements TransTest {
    @Autowired
    private StuService stuService;

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public void testPropagationTrans() {
        stuService.saveParent();
        stuService.saveChildren();
    }
}

结果:因为其新启动了一个事务,因此,子方法失败,父方法是另一个事务,接收到子方法的失败后,自身也失败,数据库无任何新增数据。

2.6 Propagation.NOT_SUPPORTED

2.6.1 子Propagation.NOT_SUPPORTED,父无

@Service
public class StuServiceImpl implements StuService {
    @Autowired
    private StuMapper stuMapper;
    
    @Override
    public void saveParent(){
        Stu stu = new Stu();
        stu.setAge(19);
        stu.setName("parent");
        stuMapper.insert(stu);
    }
    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    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);
    }

}
@Service
public class TransTestImpl implements TransTest {
    @Autowired
    private StuService stuService;

    @Override
    public void testPropagationTrans() {
        stuService.saveParent();
        stuService.saveChildren();
    }
}

结果:

2.6.2 子Propagation.NOT_SUPPORTED,父Propagation.REQUIRD

@Service
public class StuServiceImpl implements StuService {
    @Autowired
    private StuMapper stuMapper;
    
    @Override
    public void saveParent(){
        Stu stu = new Stu();
        stu.setAge(19);
        stu.setName("parent");
        stuMapper.insert(stu);
    }
    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    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);
    }

}
@Service
public class TransTestImpl implements TransTest {
    @Autowired
    private StuService stuService;

    @Override
    @Transactional(propagation = Propagation.REQUIRD)
    public void testPropagationTrans() {
        stuService.saveParent();
        stuService.saveChildren();
    }
}

结果:

2.7 Propagation.NEVER

2.7.1 子Propagation.NEVER,父Propagation.REQUIRD

@Service
public class StuServiceImpl implements StuService {
    @Autowired
    private StuMapper stuMapper;
    
    @Override
    public void saveParent(){
        Stu stu = new Stu();
        stu.setAge(19);
        stu.setName("parent");
        stuMapper.insert(stu);
    }
    @Override
    @Transactional(propagation = Propagation.NEVER)
    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);
    }

}
@Service
public class TransTestImpl implements TransTest {
    @Autowired
    private StuService stuService;

    @Override
    @Transactional(propagation = Propagation.REQUIRD)
    public void testPropagationTrans() {
        stuService.saveParent();
        stuService.saveChildren();
    }
}

结果:

2.7.2 子Propagation.NEVER,父无

@Service
public class StuServiceImpl implements StuService {
    @Autowired
    private StuMapper stuMapper;
    
    @Override
    public void saveParent(){
        Stu stu = new Stu();
        stu.setAge(19);
        stu.setName("parent");
        stuMapper.insert(stu);
    }
    @Override
    @Transactional(propagation = Propagation.NEVER)
    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);
    }

}
@Service
public class TransTestImpl implements TransTest {
    @Autowired
    private StuService stuService;

    @Override
    public void testPropagationTrans() {
        stuService.saveParent();
        stuService.saveChildren();
    }
}

结果:

2.8 Propagation.NESTED

@Service
public class StuServiceImpl implements StuService {
    @Autowired
    private StuMapper stuMapper;
    
    @Override
    public void saveParent(){
        Stu stu = new Stu();
        stu.setAge(19);
        stu.setName("parent");
        stuMapper.insert(stu);
    }
    @Override
    @Transactional(propagation = Propagation.NESTED)
    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);
    }

}
@Service
public class TransTestImpl implements TransTest {
    @Autowired
    private StuService stuService;

    @Override
     @Transactional(propagation = Propagation.REQUIRED)
    public void testPropagationTrans() {
        stuService.saveParent();
        stuService.saveChildren();
    }
}

结果: 无任何数据。 即,如果当前有事务,则开启子事务(嵌套事务),嵌套事务是独立提交或者回滚;如果当前没有事务,则同REQUIRD。

3、为什么不需要手动开启@Enabletransactionmanagement

在spring boot项目中,注解@SpringBootApplication在加载容器的时候,已经将开启事务管理的功能了,不需要额外添加注解