一文解析spring中事務(wù)的傳播機(jī)制

一文解析spring中事務(wù)的傳播機(jī)制

本文講解"一文解析spring中事務(wù)的傳播機(jī)制",希望能夠解決相關(guān)問(wèn)題。

 

spring中的事務(wù)

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

spring中的事務(wù)只是對(duì)jdbc事務(wù)進(jìn)行一些封裝與擴(kuò)展,其底層最終還是會(huì)使用到j(luò)dbc的這套api。但是spring事務(wù)有自己的特點(diǎn),也就是事務(wù)傳播機(jī)制。

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

準(zhǔn)備工作

實(shí)體類

area

package com.morris.spring.entity;import lombok.data;import java.io.serializable;@datapublic class area implements serializable {private integer id;private string areaname;private integer areacode;}

good

package com.morris.spring.entity;import lombok.data;import java.io.serializable;import java.math.bigdecimal;@datapublic class good implements serializable {private integer id;private string goodname;private bigdecimal price;}

dao層

areadao

package com.morris.spring.dao;import com.morris.spring.entity.area;import org.springframework.beans.factory.annotation.autowired;import org.springframework.jdbc.core.jdbctemplate;public class areadao {@autowiredprivate jdbctemplate jdbctemplate;public boolean insert(area area) {string sql = "insert into t_area(area_name, area_code) values(?,?)";return jdbctemplate.update(sql, area.getareaname(), area.getareacode()) > 0;}}

gooddao

package com.morris.spring.dao;import com.morris.spring.entity.good;import org.springframework.beans.factory.annotation.autowired;import org.springframework.jdbc.core.jdbctemplate;public class gooddao {@autowiredprivate jdbctemplate jdbctemplate;public boolean insert(good good) {string sql = "insert into t_good(good_name, price) values(?,?)";return jdbctemplate.update(sql, good.getgoodname(), good.getprice()) > 0;}}

service層

areaserviceimpl

package com.morris.spring.service;import com.morris.spring.dao.areadao;import com.morris.spring.entity.area;import org.springframework.beans.factory.annotation.autowired;import org.springframework.transaction.annotation.propagation;import org.springframework.transaction.annotation.transactional;public class areaserviceimpl implements areaservice {@autowiredprivate areadao areadao;@transactional(propagation = propagation.required)@overridepublic boolean addarea(int i) {int y = 1000000 / i;area area = new area();area.setareacode(y);area.setareaname("shenzhen");return areadao.insert(area);}}

goodserviceimpl

package com.morris.spring.service;import com.morris.spring.dao.gooddao;import com.morris.spring.entity.good;import org.springframework.beans.factory.annotation.autowired;import org.springframework.transaction.annotation.propagation;import org.springframework.transaction.annotation.transactional;import java.math.bigdecimal;public class goodserviceimpl implements goodservice {@autowiredprivate gooddao gooddao;@transactional(propagation = propagation.required)@overridepublic boolean addgood() {good good = new good();good.setgoodname("iphone");good.setprice(bigdecimal.valueof(99999));return gooddao.insert(good);}}

transactionservice

package com.morris.spring.service;import org.springframework.beans.factory.annotation.autowired;import org.springframework.stereotype.component;import org.springframework.transaction.annotation.propagation;import org.springframework.transaction.annotation.transactional;@componentpublic class transactionservice {@autowiredprivate goodservice goodservice;@autowiredprivate areaservice areaservice;@transactional(propagation = propagation.required)public void addgoodandarea() {system.out.println("------addgoodandarea-------");areaservice.addarea(10);goodservice.addgood();}}
測(cè)試類

transactionpropagationdemo

package com.morris.spring.demo.jdbc;import com.morris.spring.config.jdbcconfig;import com.morris.spring.dao.areadao;import com.morris.spring.dao.gooddao;import com.morris.spring.service.areaserviceimpl;import com.morris.spring.service.goodserviceimpl;import com.morris.spring.service.transactionservice;import org.junit.jupiter.api.test;import org.springframework.context.annotation.annotationconfigapplicationcontext;/** * 事務(wù)的傳播機(jī)制 */public class transactionpropagationdemo {@testpublic void test() {annotationconfigapplicationcontext applicationcontext = new annotationconfigapplicationcontext();applicationcontext.register(gooddao.class);applicationcontext.register(areadao.class);applicationcontext.register(goodserviceimpl.class);applicationcontext.register(areaserviceimpl.class);applicationcontext.register(jdbcconfig.class);applicationcontext.register(transactionservice.class);applicationcontext.refresh();transactionservice transactionservice = applicationcontext.getbean(transactionservice.class);transactionservice.addgoodandarea();}}

傳播機(jī)制

具體選項(xiàng)可以參考枚舉類org.springframework.transaction.annotation.propagation。

選項(xiàng) 說(shuō)明
required 默認(rèn)選項(xiàng)。如果當(dāng)前沒(méi)有事務(wù),就新建一個(gè)事務(wù),如果已經(jīng)存在一個(gè)事務(wù)中,加入到這個(gè)事務(wù)中。
supports 支持當(dāng)前事務(wù),如果當(dāng)前沒(méi)有事務(wù),就以非事務(wù)方式執(zhí)行。
mandatory 使用當(dāng)前的事務(wù),如果當(dāng)前沒(méi)有事務(wù),就拋出異常。
requires_new 新建事務(wù),如果當(dāng)前存在事務(wù),把當(dāng)前事務(wù)掛起。
not_supported 以非事務(wù)方式執(zhí)行操作,如果當(dāng)前存在事務(wù),就把當(dāng)前事務(wù)掛起。
never 以非事務(wù)方式執(zhí)行,如果當(dāng)前存在事務(wù),則拋出異常。
nested 如果當(dāng)前存在事務(wù),則在嵌套事務(wù)內(nèi)執(zhí)行。如果當(dāng)前沒(méi)有事務(wù),則執(zhí)行與required類似的操作。
required

默認(rèn)選項(xiàng)。如果當(dāng)前沒(méi)有事務(wù),就新建一個(gè)事務(wù),如果已經(jīng)存在一個(gè)事務(wù)中,加入到這個(gè)事務(wù)中。

配置如下:

  • transactionservice:required

  • areaserviceimpl:required

  • goodserviceimpl:required

運(yùn)行上面的demo,運(yùn)行結(jié)果如下:

// 創(chuàng)建第一個(gè)事務(wù)
debug datasourcetransactionmanager:381 - creating new transaction with name [com.morris.spring.service.transactionservice.addgoodandarea]: propagation_required,isolation_default
// 創(chuàng)建第一個(gè)連接
debug drivermanagerdatasource:144 - creating new jdbc drivermanager connection to [jdbc:mysql://127.0.0.1:3306/test?useunicode=true&allowmultiqueries=true&characterencoding=utf-8&usefastdateparsing=false&zerodatetimebehavior=converttonull]
debug datasourcetransactionmanager:265 - acquired connection [com.mysql.cj.jdbc.connectionimpl@8ef162] for jdbc transaction
debug datasourcetransactionmanager:283 - switching jdbc connection [com.mysql.cj.jdbc.connectionimpl@8ef162] to manual commit
------addgoodandarea-------																				   
// 在第一個(gè)事務(wù)中執(zhí)行
debug datasourcetransactionmanager:487 - participating in existing transaction
debug jdbctemplate:860 - executing prepared sql update
debug jdbctemplate:609 - executing prepared sql statement [insert into t_good(good_name, price) values(?,?)]
// 在第一個(gè)事務(wù)中執(zhí)行
debug datasourcetransactionmanager:487 - participating in existing transaction
debug jdbctemplate:860 - executing prepared sql update
debug jdbctemplate:609 - executing prepared sql statement [insert into t_area(area_name, area_code) values(?,?)]
// 提交第一個(gè)事務(wù)
debug datasourcetransactionmanager:763 - initiating transaction commit
debug datasourcetransactionmanager:329 - committing jdbc transaction on connection [com.mysql.cj.jdbc.connectionimpl@8ef162]
debug datasourcetransactionmanager:390 - releasing jdbc connection [com.mysql.cj.jdbc.connectionimpl@8ef162] after transaction

總結(jié):

  • 當(dāng)外層沒(méi)有事務(wù)的時(shí)候,transactionservice.addgoodandarea()方法執(zhí)行發(fā)現(xiàn)沒(méi)有事務(wù)可用,自己新建事務(wù)。

  • goodservice.addgood()和areaservice.addarea()執(zhí)行時(shí)發(fā)現(xiàn)已有事務(wù),就使用當(dāng)前事務(wù)執(zhí)行。

requires_new

新建事務(wù),如果當(dāng)前存在事務(wù),把當(dāng)前事務(wù)掛起。

配置如下:

  • transactionservice:required

  • goodserviceimpl:requires

  • areaserviceimpl:requires_new

運(yùn)行結(jié)果如下:

// 創(chuàng)建第一個(gè)事務(wù)
debug datasourcetransactionmanager:381 - creating new transaction with name [com.morris.spring.service.transactionservice.addgoodandarea]: propagation_required,isolation_default
// 創(chuàng)建第一個(gè)連接
debug drivermanagerdatasource:144 - creating new jdbc drivermanager connection to [jdbc:mysql://127.0.0.1:3306/test?useunicode=true&allowmultiqueries=true&characterencoding=utf-8&usefastdateparsing=false&zerodatetimebehavior=converttonull]
debug datasourcetransactionmanager:265 - acquired connection [com.mysql.cj.jdbc.connectionimpl@f9aa66] for jdbc transaction
debug datasourcetransactionmanager:283 - switching jdbc connection [com.mysql.cj.jdbc.connectionimpl@f9aa66] to manual commit
------addgoodandarea-------																			   
// 掛起第一個(gè)事務(wù)并創(chuàng)建第二個(gè)事務(wù)
debug datasourcetransactionmanager:446 - suspending current transaction, creating new transaction with name [com.morris.spring.service.areaserviceimpl.addarea]
// 創(chuàng)建第二個(gè)連接
debug drivermanagerdatasource:144 - creating new jdbc drivermanager connection to [jdbc:mysql://127.0.0.1:3306/test?useunicode=true&allowmultiqueries=true&characterencoding=utf-8&usefastdateparsing=false&zerodatetimebehavior=converttonull]
debug datasourcetransactionmanager:265 - acquired connection [com.mysql.cj.jdbc.connectionimpl@116fc68] for jdbc transaction
debug datasourcetransactionmanager:283 - switching jdbc connection [com.mysql.cj.jdbc.connectionimpl@116fc68] to manual commit
debug jdbctemplate:860 - executing prepared sql update
debug jdbctemplate:609 - executing prepared sql statement [insert into t_area(area_name, area_code) values(?,?)]
// 提交第二個(gè)事務(wù)
debug datasourcetransactionmanager:763 - initiating transaction commit
debug datasourcetransactionmanager:329 - committing jdbc transaction on connection [com.mysql.cj.jdbc.connectionimpl@116fc68]
debug datasourcetransactionmanager:390 - releasing jdbc connection [com.mysql.cj.jdbc.connectionimpl@116fc68] after transaction
// 恢復(fù)第一個(gè)事務(wù)
debug datasourcetransactionmanager:1043 - resuming suspended transaction after completion of inner transaction
// 在第一個(gè)事務(wù)中執(zhí)行
debug datasourcetransactionmanager:487 - participating in existing transaction
debug jdbctemplate:860 - executing prepared sql update
debug jdbctemplate:609 - executing prepared sql statement [insert into t_good(good_name, price) values(?,?)]
debug datasourcetransactionmanager:763 - initiating transaction commit
debug datasourcetransactionmanager:329 - committing jdbc transaction on connection [com.mysql.cj.jdbc.connectionimpl@f9aa66]
debug datasourcetransactionmanager:390 - releasing jdbc connection [com.mysql.cj.jdbc.connectionimpl@f9aa66] after transaction

總結(jié):areaserviceimpl.addarea()執(zhí)行時(shí)發(fā)現(xiàn)已有事務(wù),就把當(dāng)前事務(wù)掛起,執(zhí)行完后再恢復(fù)。

supports

支持當(dāng)前事務(wù),如果當(dāng)前沒(méi)有事務(wù),就以非事務(wù)方式執(zhí)行。

配置如下:

  • transactionservice:supports

  • areaserviceimpl:required

  • goodserviceimpl:supports

運(yùn)行結(jié)果如下:

// transactionservice.addgoodandarea以非事務(wù)方式運(yùn)行
------addgoodandarea-------
// 開啟第一個(gè)事務(wù)
debug datasourcetransactionmanager:381 - creating new transaction with name [com.morris.spring.service.areaserviceimpl.addarea]: propagation_required,isolation_default
// 創(chuàng)建第一個(gè)連接
debug drivermanagerdatasource:144 - creating new jdbc drivermanager connection to [jdbc:mysql://127.0.0.1:3306/test?useunicode=true&allowmultiqueries=true&characterencoding=utf-8&usefastdateparsing=false&zerodatetimebehavior=converttonull]
debug datasourcetransactionmanager:265 - acquired connection [com.mysql.cj.jdbc.connectionimpl@1691f3d] for jdbc transaction
debug datasourcetransactionmanager:283 - switching jdbc connection [com.mysql.cj.jdbc.connectionimpl@1691f3d] to manual commit
debug jdbctemplate:860 - executing prepared sql update
debug jdbctemplate:609 - executing prepared sql statement [insert into t_area(area_name, area_code) values(?,?)]
// 提交第一個(gè)事務(wù)
debug datasourcetransactionmanager:763 - initiating transaction commit
debug datasourcetransactionmanager:329 - committing jdbc transaction on connection [com.mysql.cj.jdbc.connectionimpl@1691f3d]
debug datasourcetransactionmanager:390 - releasing jdbc connection [com.mysql.cj.jdbc.connectionimpl@1691f3d] after transaction
debug datasourcetransactionmanager:1043 - resuming suspended transaction after completion of inner transaction
// areaserviceimpl.addarea以非事務(wù)方式運(yùn)行
debug jdbctemplate:860 - executing prepared sql update
debug jdbctemplate:609 - executing prepared sql statement [insert into t_good(good_name, price) values(?,?)]

總結(jié):當(dāng)前沒(méi)有事務(wù),transactionservice.addgoodandarea()和areaserviceimpl.addarea()以非事務(wù)方式運(yùn)行。

修改配置如下:

  • transactionservice:required

  • areaserviceimpl:supports

  • goodserviceimpl:supports

運(yùn)行結(jié)果如下:

// 開啟第一個(gè)事務(wù)
debug datasourcetransactionmanager:381 - creating new transaction with name [com.morris.spring.service.transactionservice.addgoodandarea]: propagation_required,isolation_default
// 創(chuàng)建第一個(gè)連接
debug drivermanagerdatasource:144 - creating new jdbc drivermanager connection to [jdbc:mysql://127.0.0.1:3306/test?useunicode=true&allowmultiqueries=true&characterencoding=utf-8&usefastdateparsing=false&zerodatetimebehavior=converttonull]
debug datasourcetransactionmanager:265 - acquired connection [com.mysql.cj.jdbc.connectionimpl@11158fb] for jdbc transaction
debug datasourcetransactionmanager:283 - switching jdbc connection [com.mysql.cj.jdbc.connectionimpl@11158fb] to manual commit
------addgoodandarea-------																		  
// 在第一個(gè)事務(wù)中執(zhí)行
debug datasourcetransactionmanager:487 - participating in existing transaction
debug jdbctemplate:860 - executing prepared sql update
debug jdbctemplate:609 - executing prepared sql statement [insert into t_area(area_name, area_code) values(?,?)]
// 在第一個(gè)事務(wù)中執(zhí)行
debug datasourcetransactionmanager:487 - participating in existing transaction
debug jdbctemplate:860 - executing prepared sql update
debug jdbctemplate:609 - executing prepared sql statement [insert into t_good(good_name, price) values(?,?)]
// 提交第一個(gè)事務(wù)
debug datasourcetransactionmanager:763 - initiating transaction commit
debug datasourcetransactionmanager:329 - committing jdbc transaction on connection [com.mysql.cj.jdbc.connectionimpl@11158fb]
debug datasourcetransactionmanager:390 - releasing jdbc connection [com.mysql.cj.jdbc.connectionimpl@11158fb] after transaction

總結(jié):當(dāng)前有事務(wù),goodserviceimpl.addgood()和areaserviceimpl.addarea()以事務(wù)方式運(yùn)行。

mandatory

使用當(dāng)前的事務(wù),如果當(dāng)前沒(méi)有事務(wù),就拋出異常。

配置如下:

  • transactionservice:required

  • areaserviceimpl:required

  • goodserviceimpl:mandatory

運(yùn)行結(jié)果如下:

// 創(chuàng)建第一個(gè)事務(wù)
ebug datasourcetransactionmanager:381 - creating new transaction with name [com.morris.spring.service.transactionservice.addgoodandarea]: propagation_required,isolation_default
// 創(chuàng)建第一個(gè)連接
debug drivermanagerdatasource:144 - creating new jdbc drivermanager connection to [jdbc:mysql://127.0.0.1:3306/test?useunicode=true&allowmultiqueries=true&characterencoding=utf-8&usefastdateparsing=false&zerodatetimebehavior=converttonull]
debug datasourcetransactionmanager:265 - acquired connection [com.mysql.cj.jdbc.connectionimpl@11c4a3f] for jdbc transaction
debug datasourcetransactionmanager:283 - switching jdbc connection [com.mysql.cj.jdbc.connectionimpl@11c4a3f] to manual commit
------addgoodandarea-------																  
// 在第一個(gè)事務(wù)中執(zhí)行
debug datasourcetransactionmanager:487 - participating in existing transaction
debug jdbctemplate:860 - executing prepared sql update
debug jdbctemplate:609 - executing prepared sql statement [insert into t_area(area_name, area_code) values(?,?)]
// 在第一個(gè)事務(wù)中執(zhí)行
debug datasourcetransactionmanager:487 - participating in existing transaction
debug jdbctemplate:860 - executing prepared sql update
debug jdbctemplate:609 - executing prepared sql statement [insert into t_good(good_name, price) values(?,?)]
// 提交第一個(gè)事務(wù)
debug datasourcetransactionmanager:763 - initiating transaction commit
debug datasourcetransactionmanager:329 - committing jdbc transaction on connection [com.mysql.cj.jdbc.connectionimpl@11c4a3f]
debug datasourcetransactionmanager:390 - releasing jdbc connection [com.mysql.cj.jdbc.connectionimpl@11c4a3f] after transaction

總結(jié):當(dāng)前有事務(wù),goodserviceimpl.addgood()以事務(wù)方式運(yùn)行。

修改配置如下:

  • transactionservice:supports

  • areaserviceimpl:mandatory

  • goodserviceimpl:supports

運(yùn)行結(jié)果如下:

------addgoodandarea-------
debug datasourcetransactionmanager:888 - should roll back transaction but cannot - no transaction available
org.springframework.transaction.illegaltransactionstateexception: no existing transaction found for transaction marked with propagation 'mandatory'
	at org.springframework.transaction.support.abstractplatformtransactionmanager.gettransaction(abstractplatformtransactionmanager.java:372)
	at org.springframework.transaction.interceptor.transactionaspectsupport.createtransactionifnecessary(transactionaspectsupport.java:595)
	at org.springframework.transaction.interceptor.transactionaspectsupport.invokewithintransaction(transactionaspectsupport.java:374)
	at org.springframework.transaction.interceptor.transactioninterceptor.invoke(transactioninterceptor.java:118)
	at org.springframework.aop.framework.reflectivemethodinvocation.proceed(reflectivemethodinvocation.java:205)
	at org.springframework.aop.framework.jdkdynamicaopproxy.invoke(jdkdynamicaopproxy.java:219)
	at com.sun.proxy.$proxy23.addarea(unknown source)
	at com.morris.spring.service.transactionservice.addgoodandarea(transactionservice.java:20)

總結(jié):當(dāng)前沒(méi)有有事務(wù),areaserviceimpl.addarea()會(huì)拋出異常。

not_supported

以非事務(wù)方式執(zhí)行操作,如果當(dāng)前存在事務(wù),就把當(dāng)前事務(wù)掛起。

配置如下:

  • transactionservice:required

  • areaserviceimpl:not_supported

  • goodserviceimpl:not_supported

運(yùn)行結(jié)果如下:

// 開啟第一個(gè)事務(wù)
debug datasourcetransactionmanager:381 - creating new transaction with name [com.morris.spring.service.transactionservice.addgoodandarea]: propagation_required,isolation_default
debug drivermanagerdatasource:144 - creating new jdbc drivermanager connection to [jdbc:mysql://127.0.0.1:3306/test?useunicode=true&allowmultiqueries=true&characterencoding=utf-8&usefastdateparsing=false&zerodatetimebehavior=converttonull]
debug datasourcetransactionmanager:265 - acquired connection [com.mysql.cj.jdbc.connectionimpl@8ef162] for jdbc transaction
debug datasourcetransactionmanager:283 - switching jdbc connection [com.mysql.cj.jdbc.connectionimpl@8ef162] to manual commit
------addgoodandarea-------
// 掛起第一個(gè)事務(wù)
debug datasourcetransactionmanager:436 - suspending current transaction
// 以非事務(wù)方式運(yùn)行
debug jdbctemplate:860 - executing prepared sql update
debug jdbctemplate:609 - executing prepared sql statement [insert into t_area(area_name, area_code) values(?,?)]
debug datasourceutils:115 - fetching jdbc connection from datasource
debug drivermanagerdatasource:144 - creating new jdbc drivermanager connection to [jdbc:mysql://127.0.0.1:3306/test?useunicode=true&allowmultiqueries=true&characterencoding=utf-8&usefastdateparsing=false&zerodatetimebehavior=converttonull]
// 恢復(fù)第一個(gè)事務(wù)
debug datasourcetransactionmanager:1043 - resuming suspended transaction after completion of inner transaction
// 掛起第一個(gè)事務(wù)
debug datasourcetransactionmanager:436 - suspending current transaction
// 以非事務(wù)方式運(yùn)行
debug jdbctemplate:860 - executing prepared sql update
debug jdbctemplate:609 - executing prepared sql statement [insert into t_good(good_name, price) values(?,?)]
debug datasourceutils:115 - fetching jdbc connection from datasource
debug drivermanagerdatasource:144 - creating new jdbc drivermanager connection to [jdbc:mysql://127.0.0.1:3306/test?useunicode=true&allowmultiqueries=true&characterencoding=utf-8&usefastdateparsing=false&zerodatetimebehavior=converttonull]
// 恢復(fù)第一個(gè)事務(wù)
debug datasourcetransactionmanager:1043 - resuming suspended transaction after completion of inner transaction
// 提交第一個(gè)事務(wù)
debug datasourcetransactionmanager:763 - initiating transaction commit
debug datasourcetransactionmanager:329 - committing jdbc transaction on connection [com.mysql.cj.jdbc.connectionimpl@8ef162]
debug datasourcetransactionmanager:390 - releasing jdbc connection [com.mysql.cj.jdbc.connectionimpl@8ef162] after transaction

總結(jié):執(zhí)行g(shù)oodserviceimpl.addgood()和areaserviceimpl.addarea()時(shí)當(dāng)前存在事務(wù),就把當(dāng)前事務(wù)掛起。

never

以非事務(wù)方式執(zhí)行,如果當(dāng)前存在事務(wù),則拋出異常。

配置如下:

  • transactionservice:never

  • areaserviceimpl:never

  • goodserviceimpl:never

運(yùn)行結(jié)果如下:

// 沒(méi)有事務(wù)都以非事務(wù)方式運(yùn)行
------addgoodandarea-------
debug jdbctemplate:860 - executing prepared sql update
debug jdbctemplate:609 - executing prepared sql statement [insert into t_area(area_name, area_code) values(?,?)]
debug datasourceutils:115 - fetching jdbc connection from datasource
debug drivermanagerdatasource:144 - creating new jdbc drivermanager connection to [jdbc:mysql://127.0.0.1:3306/test?useunicode=true&allowmultiqueries=true&characterencoding=utf-8&usefastdateparsing=false&zerodatetimebehavior=converttonull]
debug jdbctemplate:860 - executing prepared sql update
debug jdbctemplate:609 - executing prepared sql statement [insert into t_good(good_name, price) values(?,?)]

總結(jié):當(dāng)前沒(méi)有事務(wù)都以非事務(wù)方式執(zhí)行。

修改配置如下:

  • transactionservice:required

  • areaserviceimpl:never

  • goodserviceimpl:never

運(yùn)行結(jié)果如下:

// 開啟第一個(gè)事務(wù)
debug datasourcetransactionmanager:381 - creating new transaction with name [com.morris.spring.service.transactionservice.addgoodandarea]: propagation_required,isolation_default
debug drivermanagerdatasource:144 - creating new jdbc drivermanager connection to [jdbc:mysql://127.0.0.1:3306/test?useunicode=true&allowmultiqueries=true&characterencoding=utf-8&usefastdateparsing=false&zerodatetimebehavior=converttonull]
debug datasourcetransactionmanager:265 - acquired connection [com.mysql.cj.jdbc.connectionimpl@8ef162] for jdbc transaction
debug datasourcetransactionmanager:283 - switching jdbc connection [com.mysql.cj.jdbc.connectionimpl@8ef162] to manual commit
------addgoodandarea-------
debug datasourcetransactionmanager:864 - initiating transaction rollback
debug datasourcetransactionmanager:345 - rolling back jdbc transaction on connection [com.mysql.cj.jdbc.connectionimpl@8ef162]
debug datasourcetransactionmanager:390 - releasing jdbc connection [com.mysql.cj.jdbc.connectionimpl@8ef162] after transaction
org.springframework.transaction.illegaltransactionstateexception: existing transaction found for transaction marked with propagation 'never'
	at org.springframework.transaction.support.abstractplatformtransactionmanager.handleexistingtransaction(abstractplatformtransactionmanager.java:430)
	at org.springframework.transaction.support.abstractplatformtransactionmanager.gettransaction(abstractplatformtransactionmanager.java:362)
	at org.springframework.transaction.interceptor.transactionaspectsupport.createtransactionifnecessary(transactionaspectsupport.java:595)
	at org.springframework.transaction.interceptor.transactionaspectsupport.invokewithintransaction(transactionaspectsupport.java:374)
	at org.springframework.transaction.interceptor.transactioninterceptor.invoke(transactioninterceptor.java:118)
	at org.springframework.aop.framework.reflectivemethodinvocation.proceed(reflectivemethodinvocation.java:205)
	at org.springframework.aop.framework.jdkdynamicaopproxy.invoke(jdkdynamicaopproxy.java:219)
	at com.sun.proxy.$proxy23.addarea(unknown source)
	at com.morris.spring.service.transactionservice.addgoodandarea(transactionservice.java:20)

總結(jié):areaserviceimpl.addarea()執(zhí)行時(shí)存在事務(wù)就會(huì)拋出異常。

nested

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

配置如下:

  • transactionservice:required

  • goodserviceimpl:nested

  • areaserviceimpl:nested

運(yùn)行結(jié)果如下:

// 創(chuàng)建第一個(gè)事務(wù)
ebug datasourcetransactionmanager:381 - creating new transaction with name [com.morris.spring.service.transactionservice.addgoodandarea]: propagation_required,isolation_default
// 創(chuàng)建第一個(gè)連接
debug drivermanagerdatasource:144 - creating new jdbc drivermanager connection to [jdbc:mysql://127.0.0.1:3306/test?useunicode=true&allowmultiqueries=true&characterencoding=utf-8&usefastdateparsing=false&zerodatetimebehavior=converttonull]
debug datasourcetransactionmanager:265 - acquired connection [com.mysql.cj.jdbc.connectionimpl@8ef162] for jdbc transaction
debug datasourcetransactionmanager:283 - switching jdbc connection [com.mysql.cj.jdbc.connectionimpl@8ef162] to manual commit
------addgoodandarea-------
// 創(chuàng)建回滾點(diǎn)
debug datasourcetransactionmanager:466 - creating nested transaction with name [com.morris.spring.service.areaserviceimpl.addarea]
debug jdbctemplate:860 - executing prepared sql update
debug jdbctemplate:609 - executing prepared sql statement [insert into t_area(area_name, area_code) values(?,?)]
// 釋放回滾點(diǎn)
debug datasourcetransactionmanager:754 - releasing transaction savepoint
// 創(chuàng)建回滾點(diǎn)
debug datasourcetransactionmanager:466 - creating nested transaction with name [com.morris.spring.service.goodserviceimpl.addgood]
debug jdbctemplate:860 - executing prepared sql update
debug jdbctemplate:609 - executing prepared sql statement [insert into t_good(good_name, price) values(?,?)]
// 釋放回滾點(diǎn)
debug datasourcetransactionmanager:754 - releasing transaction savepoint
debug datasourcetransactionmanager:763 - initiating transaction commit
debug datasourcetransactionmanager:329 - committing jdbc transaction on connection [com.mysql.cj.jdbc.connectionimpl@8ef162]
debug datasourcetransactionmanager:390 - releasing jdbc connection [com.mysql.cj.jdbc.connectionimpl@8ef162] after transaction

如果不拋出異常,使用required與nested都差不多,區(qū)別在于發(fā)生異常,下面演示required與nested發(fā)生異常時(shí)的區(qū)別:

配置如下:

  • transactionservice:required

  • areaserviceimpl:required

  • goodserviceimpl:required

transactionservice.addgoodandarea修改如下:

@transactional(propagation = propagation.required)
public void addgoodandarea() {
	system.out.println("------addgoodandarea-------");
	try {
		areaservice.addarea(0);
	} catch (exception e) {
		e.printstacktrace();
	}
	goodservice.addgood();
}

運(yùn)行結(jié)果如下:

debug datasourcetransactionmanager:381 - creating new transaction with name [com.morris.spring.service.transactionservice.addgoodandarea]: propagation_required,isolation_default
debug drivermanagerdatasource:144 - creating new jdbc drivermanager connection to [jdbc:mysql://127.0.0.1:3306/test?useunicode=true&allowmultiqueries=true&characterencoding=utf-8&usefastdateparsing=false&zerodatetimebehavior=converttonull]
debug datasourcetransactionmanager:265 - acquired connection [com.mysql.cj.jdbc.connectionimpl@f9aa66] for jdbc transaction
debug datasourcetransactionmanager:283 - switching jdbc connection [com.mysql.cj.jdbc.connectionimpl@f9aa66] to manual commit
------addgoodandarea-------
debug datasourcetransactionmanager:487 - participating in existing transaction
debug datasourcetransactionmanager:877 - participating transaction failed - marking existing transaction as rollback-only
debug datasourcetransactionmanager:360 - setting jdbc transaction [com.mysql.cj.jdbc.connectionimpl@f9aa66] rollback-only
java.lang.arithmeticexception: / by zero
	at com.morris.spring.service.areaserviceimpl.addarea(areaserviceimpl.java:18)
... ...
debug datasourcetransactionmanager:487 - participating in existing transaction
debug jdbctemplate:860 - executing prepared sql update
debug jdbctemplate:609 - executing prepared sql statement [insert into t_good(good_name, price) values(?,?)]
debug datasourcetransactionmanager:723 - global transaction is marked as rollback-only but transactional code requested commit
debug datasourcetransactionmanager:877 - participating transaction failed - marking existing transaction as rollback-only
debug datasourcetransactionmanager:360 - setting jdbc transaction [com.mysql.cj.jdbc.connectionimpl@f9aa66] rollback-only
debug datasourcetransactionmanager:723 - global transaction is marked as rollback-only but transactional code requested commit
debug datasourcetransactionmanager:864 - initiating transaction rollback
debug datasourcetransactionmanager:345 - rolling back jdbc transaction on connection [com.mysql.cj.jdbc.connectionimpl@f9aa66]
debug datasourcetransactionmanager:390 - releasing jdbc connection [com.mysql.cj.jdbc.connectionimpl@f9aa66] after transaction
org.springframework.transaction.unexpectedrollbackexception: transaction rolled back because it has been marked as rollback-only
	at org.springframework.transaction.support.abstractplatformtransactionmanager.processrollback(abstractplatformtransactionmanager.java:905)
... ...

從運(yùn)行結(jié)果可以發(fā)現(xiàn)事務(wù)全部都回滾了。

將上面的配置修改如下:

  • transactionservice:required

  • areaserviceimpl:nested

  • goodserviceimpl:nested

運(yùn)行結(jié)果如下:

debug datasourcetransactionmanager:381 - creating new transaction with name [com.morris.spring.service.transactionservice.addgoodandarea]: propagation_required,isolation_default
debug drivermanagerdatasource:144 - creating new jdbc drivermanager connection to [jdbc:mysql://127.0.0.1:3306/test?useunicode=true&allowmultiqueries=true&characterencoding=utf-8&usefastdateparsing=false&zerodatetimebehavior=converttonull]
debug datasourcetransactionmanager:265 - acquired connection [com.mysql.cj.jdbc.connectionimpl@8ef162] for jdbc transaction
debug datasourcetransactionmanager:283 - switching jdbc connection [com.mysql.cj.jdbc.connectionimpl@8ef162] to manual commit
------addgoodandarea-------
debug datasourcetransactionmanager:466 - creating nested transaction with name [com.morris.spring.service.areaserviceimpl.addarea]
debug datasourcetransactionmanager:857 - rolling back transaction to savepoint
java.lang.arithmeticexception: / by zero
	at com.morris.spring.service.areaserviceimpl.addarea(areaserviceimpl.java:18)
... ...
debug datasourcetransactionmanager:466 - creating nested transaction with name [com.morris.spring.service.goodserviceimpl.addgood]
debug jdbctemplate:860 - executing prepared sql update
debug jdbctemplate:609 - executing prepared sql statement [insert into t_good(good_name, price) values(?,?)]
debug datasourcetransactionmanager:754 - releasing transaction savepoint
debug datasourcetransactionmanager:763 - initiating transaction commit
debug datasourcetransactionmanager:329 - committing jdbc transaction on connection [com.mysql.cj.jdbc.connectionimpl@8ef162]
debug datasourcetransactionmanager:390 - releasing jdbc connection [com.mysql.cj.jdbc.connectionimpl@8ef162] after transaction

從運(yùn)行結(jié)果可以發(fā)現(xiàn)areaservice.addarea()回滾了(本來(lái)就沒(méi)有提交內(nèi)容),goodservice.addgood()的內(nèi)容提交了。

注意只有運(yùn)行時(shí)異常以及rollbakcfor指定的異常才會(huì)回滾。

相關(guān)文章
亚洲国产精品第一区二区,久久免费视频77,99V久久综合狠狠综合久久,国产免费久久九九免费视频