簡體   English   中英

MySql連接太多了

[英]MySql too many connections

我討厭提出一個在網絡上被廣泛詢問的問題,但我似乎無法解決它。

我在一段時間后開始了一個項目,經過一個月的測試后,我遇到了“Too many connections”錯誤。 我調查了它,並通過增加max_connections來“解決”它。 然后這工作。

從那時起,越來越多的人開始使用它,它再次受到重創。 當我是網站上唯一的用戶時,我輸入“show processlist”,它會出現大約50個仍然打開的連接(在命令中說“Sleep”)。 現在,我不知道為什么這些是開放的,但在我的代碼中,我檢查並檢查每個連接,我關閉。

即。

public int getSiteIdFromName(String name, String company)throws DataAccessException,java.sql.SQLException{

Connection conn = this.getSession().connection();
Statement smt = conn.createStatement();
ResultSet rs=null;
String query="SELECT id FROM site WHERE name='"+name+"' and company_id='"+company+"'";

rs=smt.executeQuery(query);
rs.next();

int id=rs.getInt("id");

rs.close();
smt.close();
conn.close();
return id;
}

每次我在網站上做其他事情時,都會打開另一個連接,但不會關閉。 我的代碼有問題嗎? 如果沒有,可能是什么問題?

使用您的方法,如果調用conn.close() 之前拋出任何異常,則永遠不會關閉連接。 您需要在try塊中獲取它(以及語句和結果集)並在finally塊中將其關閉。 無論是否拋出異常,都將始終執行finally任何代碼。 有了這個,您可以確保關閉昂貴的資源。

這是一個重寫:

public int getSiteIdFromName(String name, String company) throws DataAccessException, java.sql.SQLException {
    Connection conn = null;
    Statement smt = null;
    ResultSet rs = null;
    int id = 0;
    try {
        conn = this.getSession().connection();
        smt = conn.createStatement();
        String query = "SELECT id FROM site WHERE name='" + name + "' and company_id='" + company + "'";
        rs = smt.executeQuery(query);
        rs.next();
        id = rs.getInt("id");
    } finally {
        if (rs != null) try { rs.close(); } catch (SQLException logOrIgnore) {}
        if (smt != null) try { smt.close(); } catch (SQLException logOrIgnore) {}
        if (conn != null) try { conn.close(); } catch (SQLException logOrIgnore) {}
    }
    return id;
}

也就是說,此代碼對SQL注入 攻擊很敏感。 使用PreparedStatement而不是Statement

另見

此代碼可能泄漏連接的一個可能流程是:

  1. Stmt.executeQuery()導致空結果集
  2. 您不檢查rs.next()是返回true還是false
  3. rs.getInt(“id”)拋出異常,因為resultset中沒有當前行
  4. 跳過conn.close()

請執行下列操作:

  1. 使rs.getInt()以rs.next()為條件
  2. 關閉finally塊中的連接,並在try塊中進行所有數據訪問

編輯:

此外,在某處記錄所有異常也是一個好主意,這樣您就可以在故障排除中找到一個很好的起點。

如果代碼拋出DataAccessException或java.sql.SQLException,則連接將不會關閉,導致許多打開的睡眠連接;)創建一個try-finally-Block,它將關閉連接。

Connection conn = this.getSession().connection();
try {
  // all code
} finally {
  rs.close();
  smt.close();
  conn.close();
}

這是一個簡單的例子,但有點復雜,因為你必須檢查這些對象是否真正被創建和使用。

這個問題的臨時解決方案可以增加mysql允許的最大連接數。你可以通過下面提到的兩種方式之一來做到這一點。

第一:

登錄到mysql服務器並輸入以下給定的命令。

mysql> SET GLOBAL max_connections = 200;

這將增加最大連接數。但是,如果重新啟動服務器,此設置將更改。

第二:

編輯文件/etc/mysql/my.cnf並增加此文件中的max_connection。

[mysqld]
local-infile=0
datadir=/var/lib/mysql
user=mysql
symbolic-links=0

max_connections = 100

保存更改並鍵入以下內容以重新啟動mysqld:

/etc/init.d/mysqld restart

但是這個問題通常是由於未正確關閉且無法使用的打開連接而出現的。

只需嘗試查看訪問數據庫的所有資源,並檢查是否正確處理了所有連接。

查看代碼可以看出,您沒有將代碼放在try和catch中。

根據您的代碼,如果在獲取數據時發生異常,您的連接將不會被關閉,因此這將浪費資源。因為編碼標准建議使用try和catch來最終處理連接。

try{
//your code 
}
catch(Exception e){

//handle the exceptions here
}

finally{
        try{
            channel.close();
        } catch(Exception e){
            log.error("Error is "+e.getMessage(),e);
            e.printStackTrace();
        }
        try {
            connection.close();
        } catch (IOException e) {
            log.error("Error is "+e.getMessage(),e);
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        catch(Exception e){
            log.error("Error is "+e.getMessage(),e);
            e.printStackTrace();
        }
    }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM