Spring事務(wù)的傳播特性

前言:

? ? Spring的事務(wù),也就是數(shù)據(jù)庫(kù)的事務(wù)操作,符合ACID標(biāo)準(zhǔn),也具有標(biāo)準(zhǔn)的事務(wù)隔離級(jí)別。

? ? 但是Spring事務(wù)有自己的特點(diǎn),也就是事務(wù)傳播機(jī)制。

? ??所謂事務(wù)傳播機(jī)制,也就是在事務(wù)在多個(gè)方法的調(diào)用中是如何傳遞的,是重新創(chuàng)建事務(wù)還是使用父方法的事務(wù)?父方法的回滾對(duì)子方法的事務(wù)是否有影響?這些都是可以通過(guò)事務(wù)傳播機(jī)制來(lái)決定的。

? ? 本文就測(cè)試一下這些事務(wù)傳播機(jī)制的使用及異同

1.準(zhǔn)備測(cè)試方法

? ? 主要是創(chuàng)建兩個(gè)service接口(接口主要是對(duì)數(shù)據(jù)庫(kù)表的操作),并創(chuàng)建其實(shí)現(xiàn)類

1)創(chuàng)建beans.xml,開(kāi)啟事務(wù)


xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xmlns:aop="http://www.springframework.org/schema/aop"

xmlns:tx="http://www.springframework.org/schema/tx"

xsi:schemaLocation="

? ? ? ? http://www.springframework.org/schema/beans

? ? ? ? http://www.springframework.org/schema/beans/spring-beans.xsd

? ? ? ? http://www.springframework.org/schema/tx

? ? ? ? http://www.springframework.org/schema/tx/spring-tx.xsd

? ? ? ? http://www.springframework.org/schema/aop

? ? ? ? http://www.springframework.org/schema/aop/spring-aop.xsd">

</beans>

?? 2)創(chuàng)建實(shí)體類和表(表創(chuàng)建讀者可自定義創(chuàng)建)

@Data

@AllArgsConstructor

@NoArgsConstructor

publicclassBlog{

privateintid;

privateString name;

privateString ur;

}

? ? 3)創(chuàng)建service接口(BlogService和BlogService2,主要是對(duì)Blog的不同操作)

// BlogService

packagejdbc;

// 主要負(fù)責(zé)Blog的添加和修改

publicinterfaceBlogService{

voidsave(Blog blog);

voidupdate(Blog blog);

}

// BlogService2

packagejdbc;

// 主要負(fù)責(zé)Blog的刪除

publicinterfaceBlogService2{

voiddelete(intid);

}

?4)創(chuàng)建其實(shí)現(xiàn)類(BlogServiceImpl,BlogService2)

BlogServiceImpl.java

@Transactional(propagation=Propagation.REQUIRED)

@Component

publicclassBlogServiceImplimplementsBlogService{

@Autowired

privateJdbcTemplate jdbcTemplate;

@Autowired

privateBlogService2 blogService2;

@Override

publicvoidsave(Blog blog){

String sql ="insert into blog values(?,?,?)";

jdbcTemplate.update(sql,

newObject[]{blog.getId(),blog.getName(),blog.getUr()},

newint[]{java.sql.Types.INTEGER,java.sql.Types.VARCHAR,java.sql.Types.VARCHAR});

blogService2.delete(16);

// update(blog);

// throw new RuntimeException("error");

}

@Override

publicvoidupdate(Blog blog){

String sql ="update blog set name = ? where id=?";

jdbcTemplate.update(sql,newObject[]{blog.getName(),blog.getId()},

newint[]{java.sql.Types.VARCHAR,java.sql.Types.INTEGER});

}

}

BlogService2.java

@Transactional(propagation=Propagation.REQUIRED)

@Component

publicclassBlogServiceImpl2implementsBlogService2{

@Autowired

privateJdbcTemplate jdbcTemplate;

@Override

publicvoiddelete(intid){

String sql ="delete from blog where id=?";

jdbcTemplate.update(sql, id);

}

}

? ? 注意:既然要實(shí)現(xiàn)多事務(wù)的傳播,就需要在一個(gè)方法里調(diào)用另一個(gè)類的方法,下面的測(cè)試就是基于這種方法,在BlogService的save()方法中調(diào)用BlogService2的delete()方法


? ? 5)創(chuàng)建Configuration類,用于創(chuàng)建DataSource實(shí)現(xiàn)

@Configuration

@ComponentScan(basePackages={"jdbc"})// 掃描BlogService實(shí)現(xiàn)類所在的包路徑

@ImportResource(locations={"classpath:beans.xml"})// 添加事務(wù)管理

publicclassJdbcConfig{

@Bean

publicJdbcTemplatejdbcTemplate(DataSource dataSource){

returnnewJdbcTemplate(dataSource);

}

@Bean

publicDataSourceTransactionManagertransactionManager(DataSource dataSource){

returnnewDataSourceTransactionManager(dataSource);

}

@Bean

publicDataSourcedataSource(){

try{

returnnewSimpleDriverDataSource(newcom.mysql.jdbc.Driver(),"jdbc:mysql://localhost:3306/test","root","root");

}catch(SQLException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

returnnull;

}

6)測(cè)試

publicclassTest{

publicstaticvoidmain(String[] args){

AnnotationConfigApplicationContext ac =newAnnotationConfigApplicationContext(JdbcConfig.class);

BlogService service = ac.getBean(BlogService.class);

Blog b =newBlog(18,"lili","url");

service.save(b);

}

}

總結(jié):大體的測(cè)試框架就如上所示,下面的測(cè)試修改主要是修改BlogServiceImpl和BlogServiceImpl2的事務(wù)傳播機(jī)制@Transactional(propagation=Propagation.REQUIRED)



3.事務(wù)傳播機(jī)制的測(cè)試


? ? 1)REQUIRED

定義:如果有事務(wù)則加入事務(wù),如果沒(méi)有事務(wù),則創(chuàng)建一個(gè)新的(默認(rèn)值)

操作1:將BlogServiceImpl和BlogServiceImpl2的事務(wù)傳播機(jī)制都修改為

@Transactional(propagation=Propagation.REQUIRED)

?結(jié)果1

操作2:將BlogServiceImpl事務(wù)傳播機(jī)制修改為@Transactional(propagation=Propagation.NOT_SUPPORTED),BlogServiceImpl2的仍為@Transactional(propagation=Propagation.REQUIRED)

結(jié)果2:

總結(jié):

? ??? ??當(dāng)BlogServiceImpl提供事務(wù)的時(shí)候,BlogServiceImpl2的方法執(zhí)行使用當(dāng)前已有事務(wù),不再新建事務(wù);

如果出現(xiàn)異常則全部回滾;

? ? ? ? 當(dāng)BlogServiceImpl不創(chuàng)建事務(wù)的時(shí)候,BlogServiceImpl2的方法執(zhí)行發(fā)現(xiàn)沒(méi)有事務(wù)可用,自己新建事務(wù);

2)NOT_SUPPORTED

定義:Spring不為當(dāng)前方法開(kāi)啟事務(wù),相當(dāng)于沒(méi)有事務(wù)

? ? 操作:將BlogServiceImpl和BlogServiceImpl2的事務(wù)傳播機(jī)制都

修改為@Transactional(propagation=Propagation.NOT_SUPPORTED)

結(jié)果:

總結(jié):

? ? ? ? NOT_SUPPORTED相當(dāng)于沒(méi)有Spring事務(wù),每條執(zhí)行語(yǔ)句單獨(dú)執(zhí)行,單獨(dú)提交

3)REQUIRES_NEW

定義:不管是否存在事務(wù),都創(chuàng)建一個(gè)新的事務(wù),原來(lái)的方法掛起,新的方法執(zhí)行完畢后,繼續(xù)執(zhí)行老的事務(wù)

操作:將BlogServiceImpl事務(wù)傳播機(jī)制修改為@Transactional(propagation=Propagation.REQUIRED),BlogServiceImpl2的仍為@Transactional(propagation=Propagation.REQUIRES_NEW)

結(jié)果:

? ? 總結(jié):

? ? ? ? REQUIRES_NEW為當(dāng)前方法創(chuàng)建一個(gè)新的事務(wù),并且當(dāng)前事務(wù)先提交,然后再提交老的事務(wù)

4)MANDATORY

定義:必須在一個(gè)已有的事務(wù)中執(zhí)行,否則報(bào)錯(cuò)

操作:將BlogServiceImpl事務(wù)傳播機(jī)制修改為@Transactional(propagation=Propagation.NOT_SUPPORTED),BlogServiceImpl2的仍為@Transactional(propagation=Propagation.MANDATORY),查看是否報(bào)錯(cuò)

? 結(jié)果:

? ? 總結(jié):? ??

? ? ? ? MANDATORY必須在已有事務(wù)下被調(diào)用,否則報(bào)錯(cuò)

? ? ? ? NOT_SUPPORTED執(zhí)行數(shù)據(jù)庫(kù)層面的事務(wù)操作,故當(dāng)前測(cè)試中,insert方法成功執(zhí)行,delete方法的拋錯(cuò)并不影響insert方法的執(zhí)行

5)NEVER

? ? 定義:必須在一個(gè)沒(méi)有的事務(wù)中執(zhí)行,否則報(bào)錯(cuò)

操作:將BlogServiceImpl事務(wù)傳播機(jī)制修改為@Transactional(propagation=Propagation.REQUIRED),BlogServiceImpl2的仍為@Transactional(propagation=Propagation.MANDATORY),查看是否報(bào)錯(cuò)

? 結(jié)果:

? ? 總結(jié):

? ? ? ? NEVER必須在沒(méi)有事務(wù)的方法中執(zhí)行,否則報(bào)錯(cuò);

? ? ? ? save方法開(kāi)啟一個(gè)事務(wù),還沒(méi)來(lái)及提交發(fā)現(xiàn)delete方法報(bào)錯(cuò),只能回滾事務(wù)

? 6)SUPPORTS

定義:如果其他bean調(diào)用這個(gè)方法時(shí),其他bean聲明了事務(wù),則就用這個(gè)事務(wù),如果沒(méi)有聲明事務(wù),那就不用事務(wù)

操作1:將BlogServiceImpl事務(wù)傳播機(jī)制修改為@Transactional(propagation=Propagation.REQUIRED),BlogServiceImpl2的仍為@Transactional(propagation=Propagation.SUPPORTS)

結(jié)果1:

操作1:將BlogServiceImpl事務(wù)傳播機(jī)制修改為@Transactional(propagation=Propagation.NOT_SUPPORTED),BlogServiceImpl2的仍為@Transactional(propagation=Propagation.SUPPORTS)

結(jié)果1:

? ??總結(jié):

? ? ? ? SUPPORTS類型的事務(wù)傳播機(jī)制,是否使用事務(wù)取決于調(diào)用方法是否有事務(wù),如果有則直接用,如果沒(méi)有則不使用事務(wù)

7)NESTED

定義:如果當(dāng)前存在事務(wù),則在嵌套事務(wù)內(nèi)執(zhí)行。如果當(dāng)前沒(méi)有事務(wù),則執(zhí)行與REQUIRED類似的操作

操作1:將BlogServiceImpl事務(wù)傳播機(jī)制修改為@Transactional(propagation=Propagation.REQUIRED),BlogServiceImpl2的仍為@Transactional(propagation=Propagation.NESTED)

?結(jié)果1:

操作2:將BlogServiceImpl事務(wù)傳播機(jī)制修改為@Transactional(propagation=Propagation.NOT_SUPPORTED),BlogServiceImpl2的仍為@Transactional(propagation=Propagation.NESTED)

?結(jié)果2:

? ? 總結(jié):

? ? ? ? save方法創(chuàng)建一個(gè)事務(wù),則再調(diào)用delete方法時(shí),直接在該事務(wù)的基礎(chǔ)上創(chuàng)建一個(gè)嵌套事務(wù),本質(zhì)上還是同一個(gè)事務(wù),做一次提交;

? ? ? ? save方法不創(chuàng)建事務(wù),則調(diào)用delete方法時(shí),直接創(chuàng)建一個(gè)新的事務(wù),單獨(dú)提交

4.注意事項(xiàng)


1)REQUIRED

? ? ? ? 當(dāng)兩個(gè)方法的傳播機(jī)制都是REQUIRED時(shí),如果一旦發(fā)生回滾,兩個(gè)方法都會(huì)回滾


? 2)REQUIRES_NEW

? ? ? ? 當(dāng)delete方法傳播機(jī)制為REQUIRES_NEW,會(huì)開(kāi)啟一個(gè)新的事務(wù),并單獨(dú)提交方法,所以save方法的回滾并不影響delete方法事務(wù)提交


? 3)NESTED

? ? ? ? 當(dāng)save方法為REQUIRED,delete方法為NESTED時(shí),delete方法開(kāi)啟一個(gè)嵌套事務(wù);

? ? ? ? 當(dāng)save方法回滾時(shí),delete方法也會(huì)回滾;反之,如果delete方法回滾,則并不影響save方法的提交

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容