spring的事务传播机制

@Service
public class ServiceA {

	@Autowired
	ServiceB serviceB;

	public void methodA() {

		serviceB.methodB();
	}
}

@Service
public class ServiceB {

	public void methodB() {

	}
}
事务传播机制Propagation.REQUIRED(默认)
@Transactional(propagation = Propagation.REQUIRED)
# 如果有事务, 那么加入事务, 没有的话新建一个(默认情况下)

如果当前正在运行的事务不在其他事务中,则新启一个事务

例如:方法B使用了@Transactional(propagation = Propagation.REQUIRED)

1、那么如果方法A已经启用了事务,那么B就不启用事务。这时候方法A与方法B任意一方出现异常,都会回滚。

spring 默认事务 开启吗_事务传播


2、那么如果方法A未启用了事务,那么B就新启一个事务。此时,A出现异常不影响B,B方法出现异常也不影响A

spring 默认事务 开启吗_spring_02

事务传播机制Propagation.REQUIRES_NEW
@Transactional(propagation = Propagation.REQUIRES_NEW)
# 新建事务,如果当前存在事务,则把当前事务挂起
# 这个方法会独立提交事务,不受调用者影响,父级异常,他也是正常提交

这个方法会独立提交事务,不受调用者影响,父级异常,他也是正常提交

spring 默认事务 开启吗_spring_03


也就是说事务B是一个独立的事务,不受父类影响,但是如果事务B发生了异常,事务A会捕捉到异常,A就会发生回滚。

事务传播机制Propagation.NESTED
@Transactional(propagation = Propagation.NESTED)
#

NESTED事务跟REQUIRED事务区别就在这里,NESTED事务是回滚到回滚点,而回滚点生成是在进入内嵌事务的时候,外面事务是不会回滚的

@Service
public class ServiceA {

	@Autowired
	ServiceB serviceB;

	@Autowired
	SchoolMapper mapper;

	@Transactional
	public void methodA() {
		try {
			School school = new School();
			school.setGrade("9");
			school.setName("AAAAAAAAA");
			school.setSex("n");
			school.setTelephone("1111111111");
			mapper.insert(school);
			-- 回滚点
			serviceB.methodB();
		} catch (Exception e) {

		}
	}
}
@Service
public class ServiceB {

	@Autowired
	SchoolMapper mapper;

	@Transactional(propagation = Propagation.REQUIRES_NEW)
	public void methodB() {

		int i = 1 / 0;
	}
}

上面方法B使用的Propagation.REQUIRES_NEW声明事务,并且抛出了异常。而方法A调用B并处理了该异常,那么NESTED事务是回滚到回滚点,回滚点就是进入内嵌事务的地方。所以方法A保存的school记录会成功。

补充回滚点概念:某转账业务有 A B C D 四个事务。 需求:AB(必须)回滚点 CD(可选)。如果发生异常,如果有回滚点则会回滚CD,并提交AB,如果没有回滚点,则AB CD全部回滚。

这里有个想法,既然方法A可以捕捉异常,那么propagation = Propagation.REQUIRED是否也可以呢?

于是将方法B的事务传播改为propagation = Propagation.REQUIRED

@Service
public class ServiceA {

	@Autowired
	ServiceB serviceB;

	@Autowired
	SchoolMapper mapper;

	@Transactional
	public void methodA() {
		try {
			School school = new School();
			school.setGrade("9");
			school.setName("AAAAAAAAA");
			school.setSex("n");
			school.setTelephone("1111111111");
			mapper.insert(school);
			serviceB.methodB();
			// int i = 1 / 0;
		} catch (Exception e) {

		}
	}
}
@Service
public class ServiceB {

	@Autowired
	SchoolMapper mapper;

	@Transactional(propagation = Propagation.REQUIRED)
	public void methodB() {

		School school = new School();
		school.setGrade("1");
		school.setName("BBBBBBBB");
		school.setSex("n");
		school.setTelephone("1111111111");
		mapper.insert(school);
		int i = 1 / 0;
	}
}

此时发现会抛出异常Transaction rolled back because it has been marked as rollback-only

发现selectA调用selectB,如果selectB抛出Exception,selectA中捕获Exception但是并不继续向外抛出,最后会出现错误。
纠其原理其实很简单,在selectB返回的时候,transaction被设置为rollback-only了,但是selectA正常消化掉,没有继续向外抛。
那么selectA结束的时候,transaction会执commit操作,但是 transaction已经被设置为 rollback-only了。

那如果方法B不配置事务,然后方法B抛出异常,方法A捕获异常,会怎么办呢

@Service
public class ServiceA {

	@Autowired
	ServiceB serviceB;

	@Autowired
	SchoolMapper mapper;

	@Transactional
	public void methodA() {
		try {
			School school = new School();
			school.setGrade("9");
			school.setName("AAAAAAAAA");
			school.setSex("n");
			school.setTelephone("1111111111");
			mapper.insert(school);
			serviceB.methodB();
			// int i = 1 / 0;
		} catch (Exception e) {

		}
	}
}
@Service
public class ServiceB {

	@Autowired
	SchoolMapper mapper;

	// @Transactional(propagation = Propagation.REQUIRED)
	public void methodB() {

		School school = new School();
		school.setGrade("1");
		school.setName("BBBBBBBB");
		school.setSex("n");
		school.setTelephone("1111111111");
		mapper.insert(school);
		int i = 1 / 0;
	}
}

会发现A与B方法的数据库操作都成功了。

事务传播机制Propagation.SUPPORTS
@Transactional(propagation = Propagation.SUPPORTS)
# 如果当前存在事务,则加入事务,如果当前不存在事务,则以非事务运行,这个和不写没有区别。
事务传播机制Propagation.NOT_SUPPORTED
@Transactional(propagation = Propagation.NOT_SUPPORTED)
# 以非事务运行,如果当前存在事务,则把当前事务挂起
事务传播机制Propagation.MANDATORY(强制)
@Transactional(propagation = Propagation.MANDATORY)
# 如果当前存在事务,则运行再当前事务中;如果当前不存在事务,则抛出异常,即父级方法必须有事务
事务传播机制Propagation.NEVER
@Transactional(propagation = Propagation.NEVER)
# 以非事务运行,如果当前存在事务,则抛出异常,即父级方法必须没有事务