被標記為事務的方法互相呼叫的坑(上)

2021-09-11 15:00:53 字數 2813 閱讀 8914

相信大家一定用過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...