2011-09-26 76 views
0

我有一個sql類,連接到數據庫並更新來自我的遊戲服務器的信息。我想知道這裏是否有什麼會導致僵局,以及防止死鎖的好方法。我是新來的很多的東西,所以任何提示將是巨大的:)死鎖預防(Java + MySQL)

package server.util; 

import java.sql.*; 
import java.security.MessageDigest; 

import server.model.players.Client; 

public class SQL { 

public static Connection con = null; 
public static Statement stmt; 
public static boolean connectionMade; 
public static void createConnection() { 
    try { 
     Class.forName("com.mysql.jdbc.Driver").newInstance(); 
     con = DriverManager.getConnection("jdbc:mysql://URL/DATABASE", "USERNAME", "PASS"); 
     stmt = con.createStatement(); 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 
} 
public static ResultSet query(String s) throws SQLException { 
    try { 
     if (s.toLowerCase().startsWith("select")) { 
      ResultSet rs = stmt.executeQuery(s); 
      return rs; 
     } else { 
      stmt.executeUpdate(s); 
     } 
     return null; 
    } catch (Exception e) { 
     destroyConnection(); 
     createConnection(); 
     e.printStackTrace(); 
    } 
    return null; 
} 

public static void destroyConnection() { 
    try { 
     stmt.close(); 
     con.close(); 
     connectionMade = false; 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 
} 

public static boolean saveHighScore(Client clientToSave) { 
    try { 
     query("DELETE FROM `skills` WHERE playerName = '"+clientToSave.playerName+"';"); 
     query("DELETE FROM `skillsoverall` WHERE playerName = '"+clientToSave.playerName+"';"); 
     //query("DELETE FROM `scores` WHERE playerName = '"+clientToSave.playerName+"';"); 
     query("INSERT INTO `skills` (`playerName`,`Attacklvl`,`Attackxp`,`Defencelvl`,`Defencexp`,`Strengthlvl`,`Strengthxp`,`Hitpointslvl`,`Hitpointsxp`,`Rangelvl`,`Rangexp`,`Prayerlvl`,`Prayerxp`,`Magiclvl`,`Magicxp`,`Cookinglvl`,`Cookingxp`,`Woodcuttinglvl`,`Woodcuttingxp`,`Fletchinglvl`,`Fletchingxp`,`Fishinglvl`,`Fishingxp`,`Firemakinglvl`,`Firemakingxp`,`Craftinglvl`,`Craftingxp`,`Smithinglvl`,`Smithingxp`,`Mininglvl`,`Miningxp`,`Herblorelvl`,`Herblorexp`,`Agilitylvl`,`Agilityxp`,`Thievinglvl`,`Thievingxp`,`Slayerlvl`,`Slayerxp`,`Farminglvl`,`Farmingxp`,`Runecraftlvl`,`Runecraftxp`,`Hunterlvl`,`Hunterxp`,`Summonlvl`,`Summonxp`) VALUES ('"+clientToSave.playerName+"',"+clientToSave.playerLevel[0]+","+clientToSave.playerXP[0]+","+clientToSave.playerLevel[1]+","+clientToSave.playerXP[1]+","+clientToSave.playerLevel[2]+","+clientToSave.playerXP[2]+","+clientToSave.playerLevel[3]+","+clientToSave.playerXP[3]+","+clientToSave.playerLevel[4]+","+clientToSave.playerXP[4]+","+clientToSave.playerLevel[5]+","+clientToSave.playerXP[5]+","+clientToSave.playerLevel[6]+","+clientToSave.playerXP[6]+","+clientToSave.playerLevel[7]+","+clientToSave.playerXP[7]+","+clientToSave.playerLevel[8]+","+clientToSave.playerXP[8]+","+clientToSave.playerLevel[9]+","+clientToSave.playerXP[9]+","+clientToSave.playerLevel[10]+","+clientToSave.playerXP[10]+","+clientToSave.playerLevel[11]+","+clientToSave.playerXP[11]+","+clientToSave.playerLevel[12]+","+clientToSave.playerXP[12]+","+clientToSave.playerLevel[13]+","+clientToSave.playerXP[13]+","+clientToSave.playerLevel[14]+","+clientToSave.playerXP[14]+","+clientToSave.playerLevel[15]+","+clientToSave.playerXP[15]+","+clientToSave.playerLevel[16]+","+clientToSave.playerXP[16]+","+clientToSave.playerLevel[17]+","+clientToSave.playerXP[17]+","+clientToSave.playerLevel[18]+","+clientToSave.playerXP[18]+","+clientToSave.playerLevel[19]+","+clientToSave.playerXP[19]+","+clientToSave.playerLevel[20]+","+clientToSave.playerXP[20]+","+clientToSave.playerLevel[21]+","+clientToSave.playerXP[21]+","+clientToSave.playerLevel[22]+","+clientToSave.playerXP[22]+");"); 
     query("INSERT INTO `skillsoverall` (`playerName`,`lvl`,`xp`) VALUES ('"+clientToSave.playerName+"',"+(clientToSave.getLevelForXP(clientToSave.playerXP[0]) + clientToSave.getLevelForXP(clientToSave.playerXP[1]) + clientToSave.getLevelForXP(clientToSave.playerXP[2]) + clientToSave.getLevelForXP(clientToSave.playerXP[3]) + clientToSave.getLevelForXP(clientToSave.playerXP[4]) + clientToSave.getLevelForXP(clientToSave.playerXP[5]) + clientToSave.getLevelForXP(clientToSave.playerXP[6]) + clientToSave.getLevelForXP(clientToSave.playerXP[7]) + clientToSave.getLevelForXP(clientToSave.playerXP[8]) + clientToSave.getLevelForXP(clientToSave.playerXP[9]) + clientToSave.getLevelForXP(clientToSave.playerXP[10]) + clientToSave.getLevelForXP(clientToSave.playerXP[11]) + clientToSave.getLevelForXP(clientToSave.playerXP[12]) + clientToSave.getLevelForXP(clientToSave.playerXP[13]) + clientToSave.getLevelForXP(clientToSave.playerXP[14]) + clientToSave.getLevelForXP(clientToSave.playerXP[15]) + clientToSave.getLevelForXP(clientToSave.playerXP[16]) + clientToSave.getLevelForXP(clientToSave.playerXP[17]) + clientToSave.getLevelForXP(clientToSave.playerXP[18]) + clientToSave.getLevelForXP(clientToSave.playerXP[19]) + clientToSave.getLevelForXP(clientToSave.playerXP[20]) + clientToSave.getLevelForXP(clientToSave.playerXP[21]) + clientToSave.getLevelForXP(clientToSave.playerXP[22]))+","+((clientToSave.playerXP[0]) + (clientToSave.playerXP[1]) + (clientToSave.playerXP[2]) + (clientToSave.playerXP[3]) + (clientToSave.playerXP[4]) + (clientToSave.playerXP[5]) + (clientToSave.playerXP[6]) + (clientToSave.playerXP[7]) + (clientToSave.playerXP[8]) + (clientToSave.playerXP[9]) + (clientToSave.playerXP[10]) + (clientToSave.playerXP[11]) + (clientToSave.playerXP[12]) + (clientToSave.playerXP[13]) + (clientToSave.playerXP[14]) + (clientToSave.playerXP[15]) + (clientToSave.playerXP[16]) + (clientToSave.playerXP[17]) + (clientToSave.playerXP[18]) + (clientToSave.playerXP[19]) + (clientToSave.playerXP[20]) + (clientToSave.playerXP[21]) + (clientToSave.playerXP[22]))+");"); 
     //query("INSERT INTO `scores` (`playerName`,`killcount`,`pkpoints`,`pcpoints`) VALUES ('"+clientToSave.playerName+"',"+clientToSave.KC+","+clientToSave.pkPoints+","+clientToSave.pcPoints+");"); 
     } catch (Exception e) { 
     e.printStackTrace(); 
     return false; 
    } 
    return true; 
} 
} 
+1

它爲什麼是靜態的?這是否有充分的理由?如果你不需要記住狀態,你應該使用靜態的東西。 – Ibolit

回答

2

你需要擔心在Java端同步,因爲java.sql中的實現是不是線程安全的。而且您需要考慮數據庫服務器上的隔離,以平衡ACID的響應能力。

我推薦一些其他的東西對你的Java類:

  1. 使用連接池。破壞和創建連接非常昂貴。你的SQL類不應該處理這些雜事。
  2. 使用PreparedStatement並綁定變量。創建一個查詢字符串是一個壞主意。
  3. 關閉finally塊中的資源。

所有那些靜態字符串...我正在手機上閱讀此內容,但我所看到的並不好。你可能會嚴重違反第一範式。

0

死鎖通常是由同步不佳的代碼造成的。最典型的情況是,線程A獲取資源X的鎖,線程B獲取資源Y的鎖,然後兩個線程都等待,而每個線程都試圖獲取它們尚未鎖定的資源。

因爲你的代碼根本沒有同步,所以應該沒問題。

爲了避免死鎖問題,儘量在同步塊內部儘可能少的工作量。對於在同步塊內的類外部調用代碼時要非常小心,因爲此外部代碼可能會嘗試獲取鎖併產生死鎖。請記住,執行數據庫查詢是對外部代碼的調用,並且數據庫查詢鎖定數據庫內的資源並不罕見。

你實際上是否看到了僵局,還是你只是謹慎?

+0

許多人在他們的服務器中使用mysql來保存信息到數據庫有死鎖,我想知道如果MySQL造成它。比如,假設他們在用戶登錄時創建了他們的mysql連接,並且如果兩個用戶同時登錄,會給出任何問題嗎? – Aleksandr

+0

我不知道數據庫中死鎖的原因是否能夠智能地回答。希望其他人可以跳進來幫助你。祝你好運。 –