2012-02-22 59 views
0

我有一個使用Spring JDBC訪問SQLite數據庫的DAO類。我已經在DAO方法本身上聲明瞭事務,因爲我的服務層從不在事務中組合查詢。春季交易及其與同步關鍵字的互動

因爲我並行使用一些工作線程,但只有一個線程可以同時更新SQLite數據庫,我使用​​序列化訪問DAO。

起初,我從我的服務類外部同步,例如:

synchronized (dao) { 
    dao.update(...); 
} 

然後,我想我也可以擺脫外部同步,並把​​在DAO方法本身:

public synchronized void update(...) { 
    // Spring JDBC calls here 
} 

奇怪的是:我的查詢現在需要兩倍的時間!

爲什麼?

+0

自從將服務方法同步到DAO方法後,它們需要兩倍的時間? – MarianP 2012-02-22 09:02:42

+0

@MarianP:正確。 – 2012-02-22 09:15:31

回答

0

我的猜測是你的更新方法或整個類被註釋爲Transactional或被事務代理通過其他方式包裝。這意味着每當你調用dao的方法時,事務代理從池中檢索數據庫連接,打開一個事務,然後調用真正的方法。

在第一種情況下,您甚至在到達代理之前進行同步,因此無法進行連接和事務處理。在第二種情況下,您在此之後等待電話。

如果有多個線程試圖執行同時更新,則只有一個線程正在執行更新,其餘的將首先打開新的連接,然後等待dao訪問。結果,而不是一個連接不斷重複使用,你將有多個連接使用。我只能猜測這是如何真正影響性能的,但你可以從一開始就嘗試不同的池大小。

+0

我使用了一個界限爲4的BoundedExecutor,因此有4個線程正在進行計算,然後並行更新數據庫。我用C3p0連接池做了一些測試,結果如下:池中有1個連接 - > 7秒,2個conns - > 13s,3個conns - > 13s,10個conns - > 13s和256 conns-> 13s。因此,當連接池大小大於1時,性能實際上會降低。有任何想法嗎? – 2012-02-22 10:04:26

+0

如果您只進行更新,您可以嘗試擺脫同步並使用一個連接使用池。至於執行比單個更糟糕的多個連接是非常清楚的。您實際上只允許在一次交易中使用,因此您不需要管理這些額外連接的開銷。雖然我寧願預計時間增加到4個連接,但保持不變。 – mrembisz 2012-02-22 10:22:26

1

嘛,一個區別是顯而易見的:

synchronized (dao) { 
    // here you are synchronizing on the transactional proxy 
} 

public synchronized void update(...) { 
    // and here you are synchronizing on the target class, *inside* the proxy 
} 

這是什麼是影響取決於你的其他代碼,但是這是有明顯區別。

+0

我猜在DAO的update()方法返回的**後面的情況下,1)其中的'synchronized'塊結束,2)事務代理提交它的事務,所以它仍然有效同時更新SQLite數據庫,即完全是我試圖阻止的東西。這聽起來似乎合理嗎? – 2012-02-26 10:16:35