相信大家一定用過spring中的註解型事務,配合上spring boot,只需要在方法上打乙個@transactional 就可以完成,真香。
但是如果大家對其中的機制一知半解的話,可能一不小心就會掉進坑,然後久久無法爬出來。
下面我就分享下被標記為事務的方法互相呼叫的坑。
首先我寫兩個事務方法:
@autowired
@transactional
@override
public void insertcodebear
() @transactional
@override
public void insertcodemonkey
() 複製**
現在我想在insertcodebear方法裡面呼叫insertcodemonkey方法,但是insertcodemonkey不是很重要,就算失敗,也不能影響到insertcodebear方法的執行,但是insertcodemonkey該回滾的還是要回滾,我們很容易寫出如下**:
@autowired
@transactional
@override
public void insertcodebear
() catch (exception ex)
account account = new account();
account.setaccount("codebear");
account.setpassword("codebear");
}@transactional(propagation = propagation.requires_new)
@override
public void insertcodemonkey
() 複製**
在第二個方法中,用了自殺**,便於測試。
看上去一點問題都沒有:第乙個方法會成功,第二個方法會失敗並且回滾。但是僅僅是看上去,當我們執行一下,會發現奇怪的事情發生了:
兩個方法竟然都成功了!!why?
為了排查問題,需要開啟一下 有關事務 的日誌,在 配置檔案 中加上下面的配置:
logging.level.org.springframework.jdbc.datasource.datasourcetransactionmanager=debug
複製**
然後執行,看下控制台列印的內容:
可能有點模糊,大家可以在新標籤頁中開啟這,可以看到這裡分明只開了乙個事務,而且事務的傳播行為是propagation_required,這是事務的預設傳播行為,也就是這裡只開啟了insertcodebear方法的事務,並沒有開啟insertcodemonkey的事務。
這是什麼原因?為了更好的說明問題產生的原因,我需要手寫乙個aop。
在此之前大家要達成乙個共識,@transactional 其實也是通過aop去實現的。
aop有幾種實現方式,我這裡採用jdk動態**的方式:
**入口:
public class main
}複製**
介面:
public inte***ce ibookservice
複製**
實現類:
public class bookserviceimpl implements ibookservice
public void delete
() }
複製**
切面定義:
public class myinvocationhandler implements invocationhandler
public object invoke(object proxy, method method, object args) throws throwable
}複製**
在main入口裡面呼叫了實現類的**物件,呼叫了add方法,add方法裡面又呼叫了delete的方法。很簡單吧。按照我們的想法,應該是列印出兩次 切面中定義的話,但是事實是 只列印了一次:
讓我們在切面方法中加上這行**:
system.out.println("方法是" + method.getname());
複製**
看看是哪個方法進入到了這裡。
執行:
add方法進入到了這裡,但是delete方法卻沒有進來。
@restcontroller
public class helloworldcontroller
}複製**
accountservice 是乙個介面,裡面定義了insertcodebear和insertcodemonkey虛方法。 我們打乙個斷點在
service.insertcodebear();
複製**
這裡,然後除錯看下service是乙個什麼東西:
你會發現,service已經不是簡單的accountservice 的實現類了,而是實現類的**物件,從這裡也可以看出,其實@transactional也是通過aop去實現的。
通過兩個例子,可以得到乙個結論:只有呼叫**物件的方法才能被攔截,所以 在方法a中直接呼叫方法b,方法b是不會被攔截的。
這也就是為什麼insertcodemonkey的事務沒有被開啟的原因了,因為insertcodemonkey方法是insertcodebear直接呼叫的。
WPF繼續響應被標記為已處理事件的方法
wpf中在冒泡事件或者隧道事件會隨其層間關係在visual tree上層層傳遞,但是,某些事件傳遞到某些控制項是即會 終止 不再響應相應的註冊事件 給人一種事件終結者的印象。例如 textbox對mousdown事件。產生原因 事件處理到達該控制項後,其事件物件屬性handled被標記為true。w...
嘗試資料庫被標記為RESTORING的處理方式
嘗試資料庫被標記為restoring的處理方式 by select left claro 2 in 西安,2009 03 27 00 29 23.450 microsoft sql server 2005 9.00.1406.00 intel x86 mar 3 2007 18 40 02 ente...
嘗試資料庫被標記為RESTORING的處理方式
嘗試資料庫被標記為restoring的處理方式 by select left claro 2 in 西安,2009 03 27 00 29 23.450 microsoft sql server 2005 9.00.1406.00 intel x86 mar 3 2007 18 40 02 ente...