一文解析spring中事務的傳播機制
本文講解"一文解析spring中事務的傳播機制",希望能夠解決相關(guān)問題。
spring中的事務
spring的事務其實就是數(shù)據(jù)庫的事務操作,符合acid標準,也具有標準的事務隔離級別。
spring中的事務只是對jdbc事務進行一些封裝與擴展,其底層最終還是會使用到jdbc的這套api。但是spring事務有自己的特點,也就是事務傳播機制。
所謂事務傳播機制,也就是在事務在多個方法的調(diào)用中是如何傳遞的,是重新創(chuàng)建事務還是使用父方法的事務?父方法的回滾對子方法的事務是否有影響?這些都是可以通過事務傳播機制來決定的。
準備工作
實體類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();}}測試類
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;/** * 事務的傳播機制 */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();}}
傳播機制
具體選項可以參考枚舉類org.springframework.transaction.annotation.propagation。
選項 | 說明 |
required | 默認選項。如果當前沒有事務,就新建一個事務,如果已經(jīng)存在一個事務中,加入到這個事務中。 |
supports | 支持當前事務,如果當前沒有事務,就以非事務方式執(zhí)行。 |
mandatory | 使用當前的事務,如果當前沒有事務,就拋出異常。 |
requires_new | 新建事務,如果當前存在事務,把當前事務掛起。 |
not_supported | 以非事務方式執(zhí)行操作,如果當前存在事務,就把當前事務掛起。 |
never | 以非事務方式執(zhí)行,如果當前存在事務,則拋出異常。 |
nested | 如果當前存在事務,則在嵌套事務內(nèi)執(zhí)行。如果當前沒有事務,則執(zhí)行與required類似的操作。 |
默認選項。如果當前沒有事務,就新建一個事務,如果已經(jīng)存在一個事務中,加入到這個事務中。
配置如下:
- transactionservice:required
- areaserviceimpl:required
- goodserviceimpl:required
運行上面的demo,運行結(jié)果如下:
// 創(chuàng)建第一個事務 debug datasourcetransactionmanager:381 - creating new transaction with name [com.morris.spring.service.transactionservice.addgoodandarea]: propagation_required,isolation_default // 創(chuàng)建第一個連接 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------- // 在第一個事務中執(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(?,?)] // 在第一個事務中執(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(?,?)] // 提交第一個事務 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é):
- 當外層沒有事務的時候,transactionservice.addgoodandarea()方法執(zhí)行發(fā)現(xiàn)沒有事務可用,自己新建事務。
- goodservice.addgood()和areaservice.addarea()執(zhí)行時發(fā)現(xiàn)已有事務,就使用當前事務執(zhí)行。
新建事務,如果當前存在事務,把當前事務掛起。
配置如下:
- transactionservice:required
- goodserviceimpl:requires
- areaserviceimpl:requires_new
運行結(jié)果如下:
// 創(chuàng)建第一個事務 debug datasourcetransactionmanager:381 - creating new transaction with name [com.morris.spring.service.transactionservice.addgoodandarea]: propagation_required,isolation_default // 創(chuàng)建第一個連接 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------- // 掛起第一個事務并創(chuàng)建第二個事務 debug datasourcetransactionmanager:446 - suspending current transaction, creating new transaction with name [com.morris.spring.service.areaserviceimpl.addarea] // 創(chuàng)建第二個連接 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(?,?)] // 提交第二個事務 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 // 恢復第一個事務 debug datasourcetransactionmanager:1043 - resuming suspended transaction after completion of inner transaction // 在第一個事務中執(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í)行時發(fā)現(xiàn)已有事務,就把當前事務掛起,執(zhí)行完后再恢復。
supports支持當前事務,如果當前沒有事務,就以非事務方式執(zhí)行。
配置如下:
- transactionservice:supports
- areaserviceimpl:required
- goodserviceimpl:supports
運行結(jié)果如下:
// transactionservice.addgoodandarea以非事務方式運行 ------addgoodandarea------- // 開啟第一個事務 debug datasourcetransactionmanager:381 - creating new transaction with name [com.morris.spring.service.areaserviceimpl.addarea]: propagation_required,isolation_default // 創(chuàng)建第一個連接 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(?,?)] // 提交第一個事務 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以非事務方式運行 debug jdbctemplate:860 - executing prepared sql update debug jdbctemplate:609 - executing prepared sql statement [insert into t_good(good_name, price) values(?,?)]
總結(jié):當前沒有事務,transactionservice.addgoodandarea()和areaserviceimpl.addarea()以非事務方式運行。
修改配置如下:
- transactionservice:required
- areaserviceimpl:supports
- goodserviceimpl:supports
運行結(jié)果如下:
// 開啟第一個事務 debug datasourcetransactionmanager:381 - creating new transaction with name [com.morris.spring.service.transactionservice.addgoodandarea]: propagation_required,isolation_default // 創(chuàng)建第一個連接 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------- // 在第一個事務中執(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(?,?)] // 在第一個事務中執(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@11158fb] debug datasourcetransactionmanager:390 - releasing jdbc connection [com.mysql.cj.jdbc.connectionimpl@11158fb] after transaction
總結(jié):當前有事務,goodserviceimpl.addgood()和areaserviceimpl.addarea()以事務方式運行。
mandatory使用當前的事務,如果當前沒有事務,就拋出異常。
配置如下:
- transactionservice:required
- areaserviceimpl:required
- goodserviceimpl:mandatory
運行結(jié)果如下:
// 創(chuàng)建第一個事務 ebug datasourcetransactionmanager:381 - creating new transaction with name [com.morris.spring.service.transactionservice.addgoodandarea]: propagation_required,isolation_default // 創(chuàng)建第一個連接 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------- // 在第一個事務中執(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(?,?)] // 在第一個事務中執(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@11c4a3f] debug datasourcetransactionmanager:390 - releasing jdbc connection [com.mysql.cj.jdbc.connectionimpl@11c4a3f] after transaction
總結(jié):當前有事務,goodserviceimpl.addgood()以事務方式運行。
修改配置如下:
- transactionservice:supports
- areaserviceimpl:mandatory
- goodserviceimpl:supports
運行結(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é):當前沒有有事務,areaserviceimpl.addarea()會拋出異常。
not_supported以非事務方式執(zhí)行操作,如果當前存在事務,就把當前事務掛起。
配置如下:
- transactionservice:required
- areaserviceimpl:not_supported
- goodserviceimpl:not_supported
運行結(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:436 - suspending current transaction // 以非事務方式運行 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 datasourcetransactionmanager:1043 - resuming suspended transaction after completion of inner transaction // 掛起第一個事務 debug datasourcetransactionmanager:436 - suspending current transaction // 以非事務方式運行 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] // 恢復第一個事務 debug datasourcetransactionmanager:1043 - resuming suspended transaction after completion of inner transaction // 提交第一個事務 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()時當前存在事務,就把當前事務掛起。
never以非事務方式執(zhí)行,如果當前存在事務,則拋出異常。
配置如下:
- transactionservice:never
- areaserviceimpl:never
- goodserviceimpl:never
運行結(jié)果如下:
// 沒有事務都以非事務方式運行 ------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é):當前沒有事務都以非事務方式執(zhí)行。
修改配置如下:
- transactionservice:required
- areaserviceimpl:never
- goodserviceimpl:never
運行結(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: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í)行時存在事務就會拋出異常。
nested如果當前存在事務,則在嵌套事務內(nèi)執(zhí)行。如果當前沒有事務,則執(zhí)行與required類似的操作。
配置如下:
- transactionservice:required
- goodserviceimpl:nested
- areaserviceimpl:nested
運行結(jié)果如下:
// 創(chuàng)建第一個事務 ebug datasourcetransactionmanager:381 - creating new transaction with name [com.morris.spring.service.transactionservice.addgoodandarea]: propagation_required,isolation_default // 創(chuàng)建第一個連接 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)建回滾點 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(?,?)] // 釋放回滾點 debug datasourcetransactionmanager:754 - releasing transaction savepoint // 創(chuàng)建回滾點 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
如果不拋出異常,使用required與nested都差不多,區(qū)別在于發(fā)生異常,下面演示required與nested發(fā)生異常時的區(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(); }
運行結(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) ... ...
從運行結(jié)果可以發(fā)現(xiàn)事務全部都回滾了。
將上面的配置修改如下:
- transactionservice:required
- areaserviceimpl:nested
- goodserviceimpl:nested
運行結(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
從運行結(jié)果可以發(fā)現(xiàn)areaservice.addarea()回滾了(本來就沒有提交內(nèi)容),goodservice.addgood()的內(nèi)容提交了。
注意只有運行時異常以及rollbakcfor指定的異常才會回滾。