0

在我們的一個遺留應用程序中有一個數據庫連接泄漏,我追蹤到這個小寶石。從調試,我可以看到多個線程返回相同的邏輯連接(不好!)。但我正在努力理解爲什麼會這樣。發現併發問題

我們使用ojdbc6驅動程序,使用連接池在WebLogic數據源上進行設置。產生問題

public class MyDummyDaoUtil { 

    //note: this is a public field in a singleton (not a static field though...) 
    public Connection conn; 

    private MyDummyDaoUtil() { 
    } 

    public static MyDummyDaoUtil getInstance() { 
     if (instance == null) { 
      instance = new MyDummyDaoUtil(); 
     } 

     return instance; 
    } 

    private DataSource getDataSource(final String dsName) 
     throws NamingException { 
     return ServiceLocator.getInstance().getDataSource(dsName); 
    } 

    public static Connection getConnection(final String source) 
     throws NamingException { 
     return MyDummyDaoUtil.getInstance().getDBConnection(source); 
    } 

    private Connection getDBConnection(final String source) 
     throws NamingException { 

     //the same logical connection is produced by the data source or something else happening? 
     conn = getDataSource(source).getConnection(); 

     conn.setAutoCommit(false); 

     return conn; 
    } 
} 

更新修復

public class MyDummyDaoUtil { 

    private MyDummyDaoUtil() { 
    } 

    public static MyDummyDaoUtil getInstance() { 
     if (instance == null) { 
      instance = new MyDummyDaoUtil(); 
     } 

     return instance; 
    } 

    private DataSource getDataSource(final String dsName) 
     throws NamingException { 
     return ServiceLocator.getInstance().getDataSource(dsName); 
    } 

    public static Connection getConnection(final String source) 
     throws NamingException { 
     return MyDummyDaoUtil.getInstance().getDBConnection(source); 
    } 

    private Connection getDBConnection(final String source) 
     throws NamingException { 

     Connection conn = getDataSource(source).getConnection(); 
     conn.setAutoCommit(false); 

     return conn; 
    } 
} 

摘要修復

  1. 不正確的懶惰initializa的

    代碼實例的重刑

  2. 連接應該是方法的局部變量,而不是單例類
+0

你說MyDummyDaoUtil是一個單身人士。如果這是在多個線程之間共享的,那麼將有兩個連接被請求的機會,這兩個連接被請求變異引用和兩次調用getDBConnection返回的相同引用(最後一個)。不能返回的連接永遠不能關閉。這段代碼沒有結束耗盡可用連接? – Yoztastic 2014-10-08 17:57:07

+0

@Yoztastic當他們被垃圾收集時,連接可能被他們的終結者擊落,隱藏了這個問題。 – Durandal 2014-10-08 19:28:08

+0

@Yoztastic - 是的,那是最初的症狀。我們的連接已經耗盡,我們不得不打開無效超時來幫助回收這些泄露的連接,同時我們追查問題。從我所知道的情況來看,代碼是從第1天開始實施的(這很嚇人......)目前還不清楚這個問題沒有在我們的舊系統上顯示出來。我的猜測是連接被以某種方式回收,並且我們沒有意識到存在這個問題。 – user1766760 2014-10-10 16:19:21

回答

0

您正在使用Singleton模式,你必須處理在同步方式的對象實例中多使用時螺紋環境。

嘗試任何一個選項:

  • 使用getInstance()同步方法

    public static synchronized MyDummyDaoUtil getInstance() { 
        if (instance == null) { 
         instance = new MyDummyDaoUtil(); 
        } 
        return instance; 
    } 
    
  • 初始化它熱切

    private static MyDummyDaoUtil instance = new MyDummyDaoUtil(); 
    public static MyDummyDaoUtil getInstance() { 
        return instance; 
    } 
    
  • 使用DOUB樂檢查鎖定機制

    public static MyDummyDaoUtil getInstance() { 
    
        if (instance == null) { 
         synchronized(MyDummyDaoUtil.class){ 
          if (instance == null) { 
           instance = new MyDummyDaoUtil(); 
          } 
         } 
        } 
        return instance; 
    } 
    

注:不要忘記關閉一個它完成連接。

Read more...

+0

好點,我錯過了實例的不正確的懶惰初始化 – user1766760 2014-10-10 16:45:26

0

假設你所要求的是「爲什麼更改此代碼修復getDBConnection的返回上的多個線程對同一對象的問題」 ......

你有可變狀態( MyDummyDaoUtil.conn)您正在使用。請考慮以下情形 - 兩個線程(A和B)都呼籲在同一時間你原來的功能:

private Connection getDBConnection(final String source) 
    throws NamingException { 
    conn = getDataSource(source).getConnection(); //line 1 
    conn.setAutoCommit(false);     //line 2 
    return conn;         //line 3 
} 

這裏有很多可能的序列,但這裏有一個樣品有問題之一:

  • 線程A執行第1行。您的數據源會返回一個新連接(我們將其稱爲connectionA),並且MyDummyDaoUtil.conn設置爲connectionA
  • 線程B執行第1行。您的數據源返回一個新連接(我們稱之爲connectionB),MyDummyDaoUtil.conn設置爲connectionB
  • 線程A執行第2行。conn現在是connectionB,所以這會導致在connectionB上將自動提交設置爲false。
  • 線程A執行第3行,返回connectionB(這是從另一個線程創建的線程)。
  • 線程B執行2號線,設置自動提交爲false connectionB(這是一個空操作,因爲線程A已經做到了事故)
  • 線程B執行3號線,返回connectionB

問題是,MyDummyDaoUtil.conn,因爲它是一個單身成員變量,在兩個線程中引用相同的變量。在第二個示例中,有一個局部變量的事實意味着每次調用該函數都有一個單獨的變量,因此您不會在調用之間發生交叉污染。