spring的事務傳播屬性required_nested的原理介紹
本文講解"spring的事務傳播屬性required_nested的原理介紹",希望能夠解決相關問題。
傳統(tǒng)事務中回滾點的使用
package?com.morris.spring.demo.jdbc; import?java.sql.*; /** ?*?傳統(tǒng)jdbc中回滾點的使用 ?*/ public?class?traditionsavepointdemo?{ public?static?void?main(string[]?args)?throws?sqlexception?{ string?url?=?"jdbc:mysql://127.0.0.1:3306/test?useunicode=true&allowmultiqueries=true&characterencoding=utf-8&usefastdateparsing=false&zerodatetimebehavior=converttonull"; string?username?=?"user"; string?password?=?"user"; connection?connection?=?drivermanager.getconnection(url,?username,?password); connection.setautocommit(false);?//?不自動提交 savepoint?one?=?connection.setsavepoint("one"); savepoint?two?=?null; try?{ statement?statement?=?connection.createstatement(); statement.execute("insert?into?t_good(good_name,?price)?values('iphone14',?9999)"); statement.close(); two?=?connection.setsavepoint("two"); }?catch?(exception?e)?{ e.printstacktrace(); connection.rollback(one);?//?回滾事務 } try?{ statement?statement?=?connection.createstatement(); statement.execute("insert?into?t_good(good_name,?price)?values('iphone15',?9999)"); statement.close(); boolean?flag?=?true; if(flag)?{ throw?new?runtimeexception("xxxx"); } }?catch?(exception?e)?{ e.printstacktrace(); connection.rollback(two);?//?回滾事務 } connection.commit(); } }
在一個事務中可以指定回滾事務到某一個階段,實現(xiàn)精確控制事務。
事務的傳播屬性nested
在spring中,要想使用事務中的回滾點,可以使用傳播屬性nested。
com.morris.spring.service.transactionservice#addgoodandarea
@transactional(propagation?=?propagation.required) public?void?addgoodandarea()?{ system.out.println("------addgoodandarea-------"); goodservice.addgood(); areaservice.addarea(0); }
com.morris.spring.service.areaserviceimpl#addarea
@transactional(propagation?=?propagation.nested) @override public?boolean?addarea(int?i)?{ int?y?=?1000000?/?i; area?area?=?new?area(); area.setareacode(y); area.setareaname("shenzhen"); return?areadao.insert(area); }
com.morris.spring.service.goodserviceimpl#addgood
@transactional(propagation?=?propagation.nested) @override public?boolean?addgood()?{ good?good?=?new?good(); good.setgoodname("iphone"); good.setprice(bigdecimal.valueof(99999)); return?gooddao.insert(good); }
運行結果如下:
debug?datasourcetransactionmanager:384?-?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:267?-?acquired?connection?[com.mysql.cj.jdbc.connectionimpl@8ef162]?for?jdbc?transaction debug?datasourcetransactionmanager:285?-?switching?jdbc?connection?[com.mysql.cj.jdbc.connectionimpl@8ef162]?to?manual?commit ------addgoodandarea------- debug?datasourcetransactionmanager:477?-?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:767?-?releasing?transaction?savepoint debug?datasourcetransactionmanager:477?-?creating?nested?transaction?with?name?[com.morris.spring.service.areaserviceimpl.addarea] debug?datasourcetransactionmanager:870?-?rolling?back?transaction?to?savepoint debug?datasourcetransactionmanager:877?-?initiating?transaction?rollback debug?datasourcetransactionmanager:347?-?rolling?back?jdbc?transaction?on?connection?[com.mysql.cj.jdbc.connectionimpl@8ef162] debug?datasourcetransactionmanager:392?-?releasing?jdbc?connection?[com.mysql.cj.jdbc.connectionimpl@8ef162]?after?transaction java.lang.arithmeticexception:?/?by?zero ...?...
發(fā)現(xiàn)整個事務都已經回滾了,按照回滾點的邏輯,addarea()方法拋出異常,不是應該只回滾到addarea()前嗎,也就是addgood()應該被提交,這是為什么呢?
如果我們將addarea()方法try catch起來,就能得到我們想要的結果,addgood()被提交,而addarea()回滾,這又是為什么呢?我們帶著這幾個問題來分析源碼。
addareaandgood()開啟事務
addareaandgood()開啟事務,最外層方法使用傳播屬性propagation_required、propagation_requires_new、propagation_nested效果都一樣,都是開啟一個新的事務。
org.springframework.transaction.support.abstractplatformtransactionmanager#gettransaction
else?if?(def.getpropagationbehavior()?==?transactiondefinition.propagation_required?|| def.getpropagationbehavior()?==?transactiondefinition.propagation_requires_new?|| def.getpropagationbehavior()?==?transactiondefinition.propagation_nested)?{ //?第一次進來 suspendedresourcesholder?suspendedresources?=?suspend(null); if?(debugenabled)?{ logger.debug("creating?new?transaction?with?name?["?+?def.getname()?+?"]:?"?+?def); } try?{ //?開啟新事務 return?starttransaction(def,?transaction,?debugenabled,?suspendedresources); } catch?(runtimeexception?|?error?ex)?{ resume(null,?suspendedresources); throw?ex; } }
addgood()獲得事務并創(chuàng)建回滾點
addgood()從threadlocal中獲得addareaandgood()創(chuàng)建的事務,然后發(fā)現(xiàn)自己的傳播屬性為propagation_nested,就創(chuàng)建了一個回滾點。
org.springframework.transaction.support.abstractplatformtransactionmanager#handleexistingtransaction
if?(definition.getpropagationbehavior()?==?transactiondefinition.propagation_nested)?{ if?(!isnestedtransactionallowed())?{ throw?new?nestedtransactionnotsupportedexception( "transaction?manager?does?not?allow?nested?transactions?by?default?-?"?+ "specify?'nestedtransactionallowed'?property?with?value?'true'"); } if?(debugenabled)?{ logger.debug("creating?nested?transaction?with?name?["?+?definition.getname()?+?"]"); } if?(usesavepointfornestedtransaction())?{ //?create?savepoint?within?existing?spring-managed?transaction, //?through?the?savepointmanager?api?implemented?by?transactionstatus. //?usually?uses?jdbc?3.0?savepoints.?never?activates?spring?synchronization. defaulttransactionstatus?status?= preparetransactionstatus(definition,?transaction,?false,?false,?debugenabled,?null); //?創(chuàng)建回滾點 status.createandholdsavepoint(); return?status; } else?{ //?nested?transaction?through?nested?begin?and?commit/rollback?calls. //?usually?only?for?jta:?spring?synchronization?might?get?activated?here //?in?case?of?a?pre-existing?jta?transaction. return?starttransaction(definition,?transaction,?debugenabled,?null); } }
addgood()提交事務時釋放回滾點
addgood()并不會真正的提交事務,因為事務并不是addgood()創(chuàng)建的,只是在提交時會將之前創(chuàng)建的回滾點釋放。
org.springframework.transaction.support.abstractplatformtransactionmanager#processcommit
if?(status.hassavepoint())?{ //?nested的提交 if?(status.isdebug())?{ logger.debug("releasing?transaction?savepoint"); } unexpectedrollback?=?status.isglobalrollbackonly(); //?只是釋放回滾點 status.releaseheldsavepoint(); }
addarea()獲得事務并創(chuàng)建回滾點
流程與addgood()一致。
addarea()回滾事務釋放回滾點
addarea()發(fā)生異常,會執(zhí)行回滾事務的邏輯,并沒有真正的回滾事務,因為事務并不是addarea()創(chuàng)建的,,只是將之前創(chuàng)建的回滾點釋放。 org.springframework.transaction.support.abstractplatformtransactionmanager#processrollback
if?(status.hassavepoint())?{ //?用于nested傳播機制,發(fā)生異常 //?回滾至回滾點 if?(status.isdebug())?{ logger.debug("rolling?back?transaction?to?savepoint"); } status.rollbacktoheldsavepoint(); }
addareaandgood()回滾這個事務
addarea()發(fā)生異常后繼續(xù)往外拋,addareaandgood()也會捕獲到異常,然后執(zhí)行回滾邏輯,這樣整個事務都回滾了。 org.springframework.transaction.support.abstractplatformtransactionmanager#processrollback
else?if?(status.isnewtransaction())?{ //?只有最外層的事務newtransaction=true if?(status.isdebug())?{ logger.debug("initiating?transaction?rollback"); } //?事務的回滾 /** ?*?@see?org.springframework.jdbc.datasource.datasourcetransactionmanager#dorollback(org.springframework.transaction.support.defaulttransactionstatus) ?*/ dorollback(status); }
為什么將addarea()方法try catch起來,整個事務就不會回滾了呢?
因為將addarea()方法try catch起來后,addareaandgood()就會執(zhí)行提交事務的邏輯,這樣addgood()就被提交了。
關于 "spring的事務傳播屬性required_nested的原理介紹" 就介紹到此。希望多多支持碩編程。