进入 Transactional 注解,默认使用的属性是 REQUIRED,表示当前方法是一定要使用事务,如果当前事务不存在,则创建新的事务,如果当前方法本身有事务,则不创建新的事务。
Propagation 一共有七个属性
下面通过示例详细介绍七个属性的作用
foodie-dev-service 中 StuService 接口添加两个方法
package com.imooc.service;
import com.imooc.pojo.Stu;
/**
* @author 92578
* @since 1.0
*/
public interface StuService {
public Stu getStuInfo(int id);
public void saveStu();
public void updateStu(int id);
public void deleteStu(int id);
public void saveParent();
public void saveChildren();
}
foodie-dev-service 中 StuServiceImpl 实现对应的方法
package com.imooc.service.impl;
import com.imooc.mapper.StuMapper;
import com.imooc.pojo.Stu;
import com.imooc.service.StuService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
/**
* @author 92578
* @since 1.0
*/
@Service
public class StuServiceImpl implements StuService {
@Autowired
private StuMapper stuMapper;
@Transactional(propagation = Propagation.SUPPORTS)
@Override
public Stu getStuInfo(int id) {
return stuMapper.selectByPrimaryKey(id);
}
@Transactional(propagation = Propagation.REQUIRED)
@Override
public void saveStu() {
Stu stu = new Stu();
stu.setName("jack");
stu.setAge(19);
stuMapper.insert(stu);
}
@Transactional(propagation = Propagation.REQUIRED)
@Override
public void updateStu(int id) {
Stu stu = new Stu();
stu.setId(id);
stu.setName("lucy");
stu.setAge(20);
stuMapper.updateByPrimaryKey(stu);
}
@Transactional(propagation = Propagation.REQUIRED)
@Override
public void deleteStu(int id) {
stuMapper.deleteByPrimaryKey(id);
}
// 测试事务 required 属性
@Override
public void saveParent() {
Stu stu = new Stu();
stu.setName("parent");
stu.setAge(19);
stuMapper.insert(stu);
}
@Override
public void saveChildren() {
saveChild1();
int a = 1 / 0;
saveChild2();
}
public void saveChild1() {
Stu stu = new Stu();
stu.setName("child-1");
stu.setAge(11);
stuMapper.insert(stu);
}
public void saveChild2() {
Stu stu = new Stu();
stu.setName("child-2");
stu.setAge(22);
stuMapper.insert(stu);
}
}
foodie-dev-service 中 创建 TestTransService 接口
package com.imooc.service;
public interface TestTransService {
public void testPropagationTrans();
}
foodie-dev-service 中 创建 TestTransServiceImpl 实现类
package com.imooc.service.impl;
import com.imooc.service.StuService;
import com.imooc.service.TestTransService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* Created by 92578 on 2020/8/15 0:49
**/
@Service
public class TestTransServiceImpl implements TestTransService {
@Autowired
private StuService stuService;
@Override
public void testPropagationTrans() {
stuService.saveParent();
stuService.saveChildren();
}
}
在 foodie-dev-api 的 pom 中添加 JUnit 包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
在 foodie-dev-api 的 src/test/java/com/test 包下创建 TransTest 类
package com.test;
import com.imooc.Application;
import com.imooc.service.StuService;
import com.imooc.service.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;
/**
* Created by 92578 on 2020/8/15 1:10
**/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
public class TransTest {
@Autowired
public StuService stuService;
@Autowired
private TestTransService testTransService;
@Test
public void myTest() {
testTransService.testPropagationTrans();
}
}
确保 Stu 表中没有数据
运行测试后提示出错
数据库中插入了两条记录
2.20.1 Propagation.REQUIRED
在 TestTransServiceImpl 类中的 testPropagationTrans 方法启用事务
@Transactional(propagation = Propagation.REQUIRED)
@Override
public void testPropagationTrans() {
stuService.saveParent();
stuService.saveChildren();
}
清除原有数据,重新运行测试方法,发现表中没有再插入数据
通过上面示例可以发现,事务会进行传播,我们在测试的父方法上面开启事务,调用的子方法 saveParent 和 saveChildren 虽然没有添加事务,但是事务会传递到子方法中。
在 StuServiceImpl 类中的 saveChildren 方法上添加事务
@Transactional(propagation = Propagation.REQUIRED)
@Override
public void saveChildren() {
saveChild1();
int a = 1 / 0;
saveChild2();
}
在 TestTransServiceImpl 类中的 testPropagationTrans 方法关闭事务
// @Transactional(propagation = Propagation.REQUIRED)
@Override
public void testPropagationTrans() {
stuService.saveParent();
stuService.saveChildren();
}
}
重新运行测试方法,发现数据库中插入一条记录
由于父级方法并没有事务,因此 saveParent 方法执行后会保存到数据库中,saveChildren 方法开启了事务,因此进行回滚
【总结】
Propagation.REQUIRED:使用当前的事务,如果当前没有事务,则自己新建一个事务,子方法是必须运行在一个事务中的;如果当前存在事务,则加入这个事务,成为一个整体。(适用于增加、修改、删除)
举例:领导没饭吃,我有钱,我会自己买了自己吃;领导有的吃,会分给你一起吃。
2.20.2 Propagation.SUPPORTS
在 StuServiceImpl 类中的 saveChildren 方法上添加事务
@Transactional(propagation = Propagation.SUPPORTS)
@Override
public void saveChildren() {
saveChild1();
int a = 1 / 0;
saveChild2();
}
清空数据,执行测试方法,发现数据库中插入两条记录
在 TestTransServiceImpl 类中的 testPropagationTrans 方法启用事务
@Transactional(propagation = Propagation.REQUIRED)
@Override
public void testPropagationTrans() {
stuService.saveParent();
stuService.saveChildren();
}
清空数据,执行测试方法,发现数据库中没有记录
【总结】
Propagation.SUPPORTS:如果当前有事务,则使用事务;如果当前没有事务,则不使用事务。(适用于查询)
举例:领导没饭吃,我也没饭吃;领导有饭吃,我也有饭吃。
2.20.3 Propagation.MANDATORY
在 TestTransServiceImpl 类中的 testPropagationTrans 方法关闭事务
// @Transactional(propagation = Propagation.REQUIRED)
@Override
public void testPropagationTrans() {
stuService.saveParent();
stuService.saveChildren();
}
}
在 StuServiceImpl 类中的 saveChildren 方法上添加事务
@Transactional(propagation = Propagation.MANDATORY)
@Override
public void saveChildren() {
saveChild1();
int a = 1 / 0;
saveChild2();
}
执行测试方法,提示出错,没有找到一个存在的事务
在 TestTransServiceImpl 类中的 testPropagationTrans 方法启用事务
@Transactional(propagation = Propagation.REQUIRED)
@Override
public void testPropagationTrans() {
stuService.saveParent();
stuService.saveChildren();
}
执行测试方法,提示出错
【总结】
Propagation.MANDATORY:该传播属性强制必须存在一个事务,如果不存在,则抛出异常。
举例:领导必须管饭,不管饭没饭吃,我就不乐意了,就不干了(抛出异常)