1仅孩,Propagation.REQUIRED
如果當(dāng)前沒(méi)有事務(wù),就新建一個(gè)事務(wù)碧磅,如果已經(jīng)存在一個(gè)事務(wù)中碘箍,加入到這個(gè)事務(wù)中遵馆。詳細(xì)解釋在代碼下方。
看下代碼
員工service
@Service
public class EmployeeServiceImpl implements EmployeeService {
@Autowired
EmployeeMapper employeeMapper;
@Autowired
DepartmentService departmentService;
/**
* 添加員工的同時(shí)添加部門(mén)
* REQUIRED 傳播
* @param name 員工姓名
*/
@Override
@Transactional(propagation = Propagation.REQUIRED)
public void addEmpByRequired(String name) {
Employee employee = new Employee();
employee.setDeptId(1);
employee.setName(name);
employee.setAddress("邯鄲");
employeeMapper.insertSelective(employee);
departmentService.addDept("jishubu");
int i = 1/0;
}
}
部門(mén)service
@Service
public class DepartmentServiceImpl implements DepartmentService {
@Autowired
DepartmentMapper departmentMapper;
@Override
public void addDeptByRequired(String name) {
Department department = new Department();
department.setName(name);
departmentMapper.insertSelective(department);
// int i = 1/0;
}
}
注:該篇文章所測(cè)試的皆是運(yùn)行addEmpByRequired方法丰榴。
1货邓,上述代碼中,無(wú)論int i =1/0 這個(gè)異常出現(xiàn)在哪里四濒,添加員工和添加部門(mén)都會(huì)回滾换况。
因?yàn)?REQUIRED 會(huì)讓添加員工和添加部門(mén)變?yōu)橐粋€(gè)事務(wù)。,
2盗蟆,值得一提的是戈二,如果異常在addDept中,但是在addEmpByRequired把 addDept方法 try喳资,catch了觉吭,則會(huì)拋出異常:Transaction rolled back because it has been marked as rollback-only 。
3仆邓,如果在addDeptByRequired上添加@Transactional(propagation = Propagation.REQUIRED)鲜滩,在addEmpByRequired不添加事務(wù),則addDeptByRequired是一個(gè)事務(wù)节值,addEmpByRequired并不是一個(gè)事務(wù)绒北。因?yàn)閍ddDeptByRequired開(kāi)啟了一個(gè)事務(wù),但是addEmpByRequired并不存在一個(gè)事務(wù)中察署。
2,Propagation.SUPPORTS
支持當(dāng)前事務(wù)峻汉,如果當(dāng)前沒(méi)有事務(wù)贴汪,就以非事務(wù)方式執(zhí)行。
員工service
@Override
@Transactional(propagation = Propagation.REQUIRED)
public void addEmpBySupports(String name) {
Employee employee = new Employee();
employee.setDeptId(2);
employee.setName(name);
employee.setAddress("邯鄲");
employeeMapper.insertSelective(employee);
departmentService.addDeptBySupports("jishubu");
// int i = 1/0;
}
部門(mén)Service
@Override
@Transactional(propagation = Propagation.SUPPORTS)
public void addDeptBySupports(String name) {
Department department = new Department();
department.setName(name);
departmentMapper.insertSelective(department);
int i = 1/0;
}
關(guān)于這個(gè)屬性休吠,在以上代碼中扳埂,主要是添加到addDeptBySupports上的,也就是被調(diào)用方法上瘤礁。因?yàn)樘砑拥絘ddEmpBySupports就不以事務(wù)的方式運(yùn)行了阳懂。
然后,如果addEmpBySupports為事務(wù)柜思,則addDeptBySupports也為事務(wù)岩调。如果addEmpBySupports不是事務(wù),則addDeptBySupports也不是事務(wù)赡盘。
3号枕,Propagation.MANDATORY
使用當(dāng)前的事務(wù),如果當(dāng)前沒(méi)有事務(wù)陨享,就拋出異常葱淳。
員工Service
@Override
// @Transactional(propagation = Propagation.REQUIRED)
public void addEmpByMandatory(String name) {
System.out.println("aaaaaa");
Employee employee = new Employee();
employee.setDeptId(3);
employee.setName(name);
employee.setAddress("邯鄲");
employeeMapper.insertSelective(employee);
departmentService.addDeptByMandatory("jishubu");
int i = 1/0;
}
部門(mén)Service
@Override
@Transactional(propagation = Propagation.MANDATORY)
public void addDeptByMandatory(String name) {
Department department = new Department();
department.setName(name);
departmentMapper.insertSelective(department);
int i = 1/0;
}
這個(gè)屬性也是添加到addDeptByMandatory(被調(diào)用者) 上的钝腺。如果添加到addEmpByMandatory(調(diào)用者)上,則直接拋出異常赞厕。
該屬性添加到addDeptByMandatory上艳狐, 如果addEmpByMandatory有事務(wù),則addDeptByMandatory加入到addEmpByMandatory的事務(wù)中皿桑,如果addEmpByMandatory沒(méi)有事務(wù)毫目,則直接拋出異常。
4唁毒,Propagation.REQUIRES_NEW
員工Service
@Override
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void addEmpByRequiresNew(String name) {
Employee employee = new Employee();
employee.setDeptId(4);
employee.setName(name);
employee.setAddress("邯鄲");
employeeMapper.insertSelective(employee);
departmentService.addDeptByRequiresNew("jishubu");
int i = 1/0;
}
部門(mén)Service
@Override
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void addDeptByRequiresNew(String name) {
Department department = new Department();
department.setName(name);
departmentMapper.insertSelective(department);
// int i = 1/0;
}
這個(gè)屬性應(yīng)該是除了REQUIRED用的最多的蒜茴。這個(gè)屬性也是針對(duì)被調(diào)用者的(addDeptByRequiresNew)。
不管調(diào)用者(addEmpByRequiresNew)是否存在事務(wù)浆西,被調(diào)用者(addDeptByRequiresNew)都會(huì)新開(kāi)一個(gè)事務(wù)粉私,相當(dāng)于被調(diào)用者都存在于自己的事務(wù)中和調(diào)用者沒(méi)有關(guān)系。
如上述代碼近零,addEmpByRequiresNew會(huì)回滾诺核,但addDeptByRequiresNew不會(huì)回滾。因?yàn)樗麄兪莾蓚€(gè)事務(wù)久信。
5窖杀,Propagation.NOT_SUPPORTED
以非事務(wù)方式執(zhí)行操作,如果當(dāng)前存在事務(wù)裙士,就把當(dāng)前事務(wù)掛起入客。
員工Service
@Override
@Transactional(propagation = Propagation.REQUIRED)
public void addEmpByNotSupported(String name) {
Employee employee = new Employee();
employee.setDeptId(5);
employee.setName(name);
employee.setAddress("邯鄲");
employeeMapper.insertSelective(employee);
departmentService.addDeptByNotSupported("jishubu");
int i = 1/0;
}
部門(mén)Service
@Override
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void addDeptByNotSupported(String name) {
Department department = new Department();
department.setName(name);
departmentMapper.insertSelective(department);
int i = 1/0;
}
這個(gè)屬性如果放在調(diào)用者(addEmpByNotSupported)上,則是以非事務(wù)方式運(yùn)行腿椎。
如果放在被調(diào)用者(addDeptByNotSupported)上桌硫,該方法(addDeptByNotSupported)以非事務(wù)運(yùn)行,調(diào)用者如果有事務(wù)啃炸,則運(yùn)行單獨(dú)的事務(wù)(掛起)铆隘。
上述代碼,會(huì)出現(xiàn)添加員工回滾南用,添加部門(mén)不回滾膀钠。
6,Propagation.NEVER
以非事務(wù)方式執(zhí)行裹虫,如果當(dāng)前存在事務(wù)肿嘲,則拋出異常。
員工Service
@Override
@Transactional(propagation = Propagation.REQUIRED)
public void addEmpByNever(String name) {
Employee employee = new Employee();
employee.setDeptId(6);
employee.setName(name);
employee.setAddress("邯鄲");
employeeMapper.insertSelective(employee);
departmentService.addDeptByNever("jishubu");
int i = 1/0;
}
部門(mén)Service
@Override
@Transactional(propagation = Propagation.NEVER)
public void addDeptByNever(String name) {
Department department = new Department();
department.setName(name);
departmentMapper.insertSelective(department);
int i = 1/0;
}
這個(gè)屬性如果在調(diào)用者上筑公,則直接以非事務(wù)運(yùn)行睦刃。如果作用在被調(diào)用者上,則看調(diào)用者是否有事務(wù)十酣,如果調(diào)用者有事務(wù)涩拙,則拋出異常际长,如果沒(méi)有事務(wù),則以非事務(wù)運(yùn)行兴泥。
上述代碼中工育,則會(huì)拋出異常。(并不是除0異常搓彻,而是:Existing transaction found for transaction marked with propagation 'never')
7如绸,Propagation.NESTED
如果當(dāng)前存在事務(wù),則在嵌套事務(wù)內(nèi)執(zhí)行旭贬。如果當(dāng)前沒(méi)有事務(wù)怔接,則執(zhí)行與PROPAGATION_REQUIRED類(lèi)似的操作。
(這個(gè)和REQUIRED區(qū)別在于一個(gè)是加入到一個(gè)事務(wù)稀轨,一個(gè)是在嵌套事務(wù)運(yùn)行)
員工Service
@Override
@Transactional(propagation = Propagation.REQUIRED)
public void addEmpByNested(String name) {
Employee employee = new Employee();
employee.setDeptId(7);
employee.setName(name);
employee.setAddress("邯鄲");
employeeMapper.insertSelective(employee);
try {
departmentService.addDeptByNested("jishubu");
}catch (Exception e){
}
// int i = 1/0;
}
部門(mén)Service
@Override
@Transactional(propagation = Propagation.NESTED)
public void addDeptByNested(String name) {
Department department = new Department();
department.setName(name);
departmentMapper.insertSelective(department);
int i = 1/0;
}
可以這么理解扼脐,大多數(shù)情況下,效果和REQUIRED一樣奋刽。但是有一種情況瓦侮,就是上述代碼中,被調(diào)用者事務(wù)傳播屬性為NESTED佣谐,當(dāng)出現(xiàn)異常時(shí)肚吏, 調(diào)用者把departmentService try,catch了狭魂。這個(gè)區(qū)別與REQUIRED的并不會(huì)報(bào)錯(cuò)罚攀,而且addEmpByNested方法不會(huì)回滾,只有addDeptByNested回滾了雌澄。
大概原理:當(dāng)被調(diào)用者使用PROPAGATION_NESTED時(shí)坞生,底層的數(shù)據(jù)源必須基于JDBC 3.0,并且實(shí)現(xiàn)者需要支持保存點(diǎn)事務(wù)機(jī)制掷伙。按上述代碼來(lái)說(shuō)(去掉try,catch)又兵,當(dāng)執(zhí)行到addDeptByNested這個(gè)方法時(shí)任柜,Spring會(huì)為它創(chuàng)建一個(gè)內(nèi)部的嵌套事務(wù),如果addDeptByNested執(zhí)行失敗沛厨,則事務(wù)回滾到addDeptByNested之前的點(diǎn)宙地,此時(shí)如果不拋異常,則不會(huì)回滾逆皮。這個(gè)嵌套事務(wù)宅粥,是addEmpByNested的一部分,只有外層事務(wù)提交了电谣,內(nèi)層的嵌套事務(wù)才會(huì)一起提交秽梅,這也是與REQUIRED(加入事務(wù))抹蚀,REQUIRES_NEW(開(kāi)啟新事務(wù))的區(qū)別。
還值得一提的是企垦,NESTED是嵌套的意思环壤,其實(shí)并不是只有NESTED用于嵌套,只要理解上述7個(gè)傳播機(jī)制的意思钞诡,都可以嵌套用郑现。
github:https://github.com/zycisbg/transaction-propagate
下邊是一個(gè)我同事總結(jié)的圖。非常精確荧降,簡(jiǎn)短接箫。