天天看點

【springboot學習】spring事務傳播機制

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任意一方出現異常,都會復原。

【springboot學習】spring事務傳播機制

2、那麼如果方法A未啟用了事務,那麼B就新啟一個事務。此時,A出現異常不影響B,B方法出現異常也不影響A

【springboot學習】spring事務傳播機制

事務傳播機制

Propagation.REQUIRES_NEW

@Transactional(propagation = Propagation.REQUIRES_NEW)
# 建立事務,如果目前存在事務,則把目前事務挂起
# 這個方法會獨立送出事務,不受調用者影響,父級異常,他也是正常送出
           

這個方法會獨立送出事務,不受調用者影響,父級異常,他也是正常送出

【springboot學習】spring事務傳播機制

也就是說事務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)
# 以非事務運作,如果目前存在事務,則抛出異常,即父級方法必須沒有事務
           

繼續閱讀