死锁预防(Java+MySQL)
我有一个 sql 类,它连接到数据库并更新游戏服务器中的信息。我想知道这里是否会导致死锁以及防止死锁的好方法是什么。我对很多事情都很陌生,所以任何建议都会很棒:)
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;
}
}
i have an sql class that connects to the database and updates the information from my game server. I was wondering if anything here would cause a deadlock and what are good ways to prevent deadlocks. I am new to alot of things so any tips would be great :)
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;
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您需要担心 Java 端的同步,因为 java.sql 实现不是线程安全的。您需要考虑数据库服务器上的隔离,平衡响应性与 ACID。
我会为您的 Java 类推荐一些其他内容:
所有这些静态字符串......我正在手机上阅读这篇文章,但我看到的并不好。您可能严重违反了第一范式。
You need to worry about synchronization on the Java side, because java.sql implementations are not thread safe. And you need to think about isolation on the database server, balancing responsiveness with ACID.
I'd recommend a few other things for your Java class:
All those static strings...I'm reading this on a mobile phone, but what I'm seeing is not good. You may have a serious violation of 1st normal form.
死锁通常是由同步不良的代码引起的。最典型的情况是线程 A 获取资源 X 的锁,线程 B 获取资源 Y 的锁,然后两个线程都等待,同时尝试获取尚未锁定的资源。
由于您的代码根本没有同步,所以应该没问题。
为了避免死锁问题,请尝试在同步块内执行尽可能少的工作。在同步块内调用类外部的代码时要非常小心,因为该外部代码可能会尝试获取锁并产生死锁。请记住,执行数据库查询是对外部代码的调用,并且数据库查询锁定数据库内部的资源并不罕见。
您是否真的看到了僵局,或者只是出于谨慎?
Deadlocks are generally cause by poorly synchronized code. The most typical case is that Thread A grabs a lock on resource X, Thread B grabs a lock on resource Y, and then both threads wait while they each try to grab the resource they don't yet have locked.
Since your code has no synchronization at all, it should be fine.
To avoid deadlock problems, try to do the minimum amount of work possible inside of synchronized blocks. Be very careful about calling code external to the class inside a synchronized block, as this external code may try to obtain a lock and produce a deadlock. Remember that doing a database query is a call to external code, and it is not unusual for a db query to lock on resources inside the database.
Are you actually seeing deadlocks, or are you just being cautious?