2015-02-17 90 views
0

以前的信息:數據庫遠程託管,平均延遲92ms連接。Java mysql - SELECT語句延遲主線程

我有一個小小的MySQL數據庫,它爲我的遊戲存放玩家數據。

當遍歷結果集時,每個玩家返回250行,在玩家登錄遊戲時分配玩家變量。

我的問題是,每次玩家登錄時,我的遊戲主線程會延遲一段時間,大約200毫秒。 (每個遊戲週期有600ms)。

我發現這只是發生在SELECT語句中,所有其他查詢如UPDATE,DELETE或任何不返回ResultSet的查詢都很好。

我使用的C3P0 MySQL的游泳池,這是我的configs它:

cpds.setInitialPoolSize(100); 
    cpds.setMinPoolSize(100); 
    cpds.setNumHelperThreads(200); 
    cpds.setMaxIdleTime(0); 
    cpds.setAcquireIncrement(10); 
    cpds.setMaxPoolSize(200); 
    cpds.setMaxStatements(0); 

每次在大約10查詢執行,各地請求其他玩家的信息,他們當前聊天服務器玩家登錄等等。這些查詢不能在單個語句中發佈,這就是c3p0中多個線程和連接的原因,以減少滯後,這非常有效。

正如我所說,它只發生在期望ResultSet的SELECT查詢中。

問題是:我將如何運行該查詢,將結果賦予播放器變量,所有這些都不會將主線程搞亂200ms?

200ms可能會顯示「ok」,但如果50個玩家同時登錄,該怎麼辦?這只是將時間乘以創建一個巨大的線程鎖。

我是怎麼裝的玩家:

在登錄,這要求:

PlayerLoader.load(username);  

所以它返回Player實例下面的方法,被稱爲:

public static Player load(String name) { 
    ResultSet result = null; 
    PreparedStatement ps = null; 
    Player player = new Player(); 
    Connection con = null; 
    try { 
     con = World.database().getConnection(); 
     ps =con.prepareStatement("SELECT * FROM " + PLAYER_TABLE + " WHERE username='" + name + "' LIMIT 1"); 
     result = ps.executeQuery(); 
     if (result.next()) { 
      return player.playerSaving().load(result); 
     } 
    } catch (Exception e) { 
     System.err.println("Error Loading the account: "+name); 
     e.printStackTrace(); 
    } finally { 
     try { 
      if (result != null) { 
       result.close(); 
      } 
      result = null; 
      ps.close(); 
      ps = null; 
      con.close(); 
     } catch (SQLException e) { 
     } 
    } 
    return null; 
}  

後獲取ResultSet,另一個方法被調用,它將變量分配給播放器實例。

該方法包括:

 player.getPlayerDefinition().getIndex(result.getShort("id")).setDisplayName(result.getString("displayName")); 
     player.getPlayerDefinition().setRights(result.getShort("rights")); 
     player.getPlayerDefinition().setPlayTime(result.getLong("playTime")); 
     player.getPlayerDefinition().setMuted(result.getInt("mute")).setMuteDuration(Long.parseLong(result.getString("muteTill"))); 
     player.getPlayerDefinition().setBanned(result.getLong("banned")); 
     player.getPlayerDefinition().setPermBanned(result.getString("permBanned").equals("true")); 
     player.getPlayerDefinition().setMemberDays2(result.getLong("member_days"));  

這是它只是一個短版。目前它加載全部250行。

該方法還返回Player實例,所以第一個Load方法將返回它。 (請參閱:public Player load(ResultSet result)

經過該過程後,創建實例並準備繼續,現在玩家請求關於他們的世界,聊天服務器等的信息,這就是大約6-7個執行得非常快的小查詢。大約2-3個查詢是帶有簡短結果的SELECT語句。

同樣,有什麼辦法可以在異步線程中運行該加載過程嗎?如果是的話,怎麼樣?

謝謝。

回答

0

您的問題是JDBC阻塞。

如果您將應用程序部署到Web服務器,則可以通過使用線程池來減少阻塞時尚的影響。在這種情況下,可以同時處理的請求數量取決於線程池的大小。

+0

我目前使用五個專用服務器。其中4家位於加拿大,主要的一家,即主辦的數據庫位於美國。 我試圖讓遠程性能很好,因爲我正要在亞洲獲得更多的服務器,因爲在那個位置有ping。但是,無論客戶端位於何處,數據庫加載都必須快速。 – 2015-02-17 23:37:52

1

我已經解決了問題,只需創建另一個專用線程來處理登錄。

線程工作原理:

  • 播放器請求登錄
  • 請求被排隊等待執行其在專用線程需要小於10ms。
  • 線程執行Runnable,而不是延遲主線程。