我在加载/存储MySQL数据时遇到问题,这是我的代码
public void loadPlayer(Player p) {
if (isPlayerInDataBase(p)) {
Bukkit.getScheduler().runTaskAsynchronously(Main.getInstance(), new Runnable() {
@Override
public void run() {
Connection connection = sql.getConnection();
try {
PreparedStatement select = connection
.prepareStatement("SELECT * FROM `MurderData` WHERE playername='" + p.getName() + "'");
ResultSet result = select.executeQuery();
if (getPlayerData(p) != null) {
while (result.next()) {
getPlayerData(p).setdeaths(result.getInt("deaths"));
getPlayerData(p).setkills(result.getInt("kills"));
getPlayerData(p).setwins(result.getInt("wins"));
getPlayerData(p).setlose(result.getInt("loses"));
getPlayerData(p).setscore(result.getInt("score"));
getPlayerData(p).setcoins(result.getInt("coins"));
}
CloseResultSet(result);
}
} catch (SQLException e) {
e.printStackTrace();
}
}
});
} else {
Connection connection = sql.getConnection();
Bukkit.getScheduler().runTaskAsynchronously(Main.getInstance(), new Runnable() {
@Override
public void run() {
try {
PreparedStatement insert = connection.prepareStatement(
"INSERT INTO `MurderData` (playername, wins, deaths, loses, kills, coins, score) VALUES (?, ?, ?, ?, ?, ?, ?)");
insert.setString(1, p.getName());
insert.setInt(2, 0);
insert.setInt(3, 0);
insert.setInt(4, 0);
insert.setInt(5, 0);
insert.setInt(6, 0);
insert.setInt(7, 0);
insert.executeUpdate();
ClosePreparedStatement(insert);
} catch (SQLException e) {
e.printStackTrace();
}
}
public boolean isPlayerInDataBase(Player p) {
Connection connection = sql.getConnection();
try {
PreparedStatement select = connection
.prepareStatement("SELECT * FROM `MurderData` WHERE playername='" + p.getName() + "'");
ResultSet result = select.executeQuery();
if (result.next()) {
CloseResultSet(result);
return true;
}
} catch (SQLException e) {
e.printStackTrace();
}
return false;
}
所以基本上问题是,我应该在更新MySQL数据后关闭准备好的语句吗?我应该让它有一个像5秒后关闭它的延迟?我可以优化此代码以使其更好吗?
数据库中的播放器是否正常?
这是我的两个关闭方法:
public void CloseResultSet(ResultSet s) {
new BukkitRunnable() {
@Override
public void run() {
if (s != null) {
try {
s.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}.runTaskLater(this, 20 * getConfig().getInt("close-sql-statements-after"));
}
public void ClosePreparedStatement(PreparedStatement s) {
new BukkitRunnable() {
@Override
public void run() {
if (s != null) {
try {
s.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}.runTaskLater(this, 20 * getConfig().getInt("close-sql-statements-after"));
}
更新:这是第二个问题,第一个问题是小延迟峰值第二个问题是在第252行存储数据
public void setSQLData(Player p, int kills, int deaths, int loses, int wins, int coins, int score) {
Bukkit.getScheduler().runTaskAsynchronously(plugin, new Runnable() {
@Override
public void run() {
Connection connection = plugin.sql.getConnection();
try {
PreparedStatement insert = connection.prepareStatement(
"INSERT INTO `MurderData` (playername, wins, deaths, loses, kills, coins, score) VALUES (?, ?, ?, ?, ?, ?, ?)");
insert.setString(1, p.getName());
insert.setInt(2, wins);
insert.setInt(3, deaths);
insert.setInt(4, loses);
insert.setInt(5, kills);
insert.setInt(6, coins);
insert.setInt(7, score);
insert.executeUpdate();// error line 252
plugin.ClosePreparedStatement(insert);
} catch (SQLException e) {
e.printStackTrace();
}
}
});
}
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
[22:31:18] [Craft Scheduler Thread - 71/WARN]: at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
[22:31:18] [Craft Scheduler Thread - 71/WARN]: at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
[22:31:18] [Craft Scheduler Thread - 71/WARN]: at java.lang.reflect.Constructor.newInstance(Unknown Source)
[22:31:18] [Craft Scheduler Thread - 71/WARN]: at com.mysql.jdbc.Util.handleNewInstance(Util.java:407)
[22:31:18] [Craft Scheduler Thread - 71/WARN]: at com.mysql.jdbc.SQLError.createCommunicationsException(SQLError.java:1116)
[22:31:18] [Craft Scheduler Thread - 71/WARN]: at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:3082)
[22:31:18] [Craft Scheduler Thread - 71/WARN]: at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:2968)
[22:31:18] [Craft Scheduler Thread - 71/WARN]: at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3516)
[22:31:18] [Craft Scheduler Thread - 71/WARN]: at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1986)
[22:31:18] [Craft Scheduler Thread - 71/WARN]: at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2140)
[22:31:18] [Craft Scheduler Thread - 71/WARN]: at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2626)
[22:31:18] [Craft Scheduler Thread - 71/WARN]: at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:2111)
[22:31:18] [Craft Scheduler Thread - 71/WARN]: at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2407)
[22:31:18] [Craft Scheduler Thread - 71/WARN]: at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2325)
[22:31:18] [Craft Scheduler Thread - 71/WARN]: at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2310)
[22:31:18] [Craft Scheduler Thread - 71/WARN]: at me.joseph.murder.api.MurderAPI$1.run(MurderAPI.java:252)
[22:31:18] [Craft Scheduler Thread - 71/WARN]: at org.bukkit.craftbukkit.v1_8_R3.scheduler.CraftTask.run(CraftTask.java:71)
[22:31:18] [Craft Scheduler Thread - 71/WARN]: at org.bukkit.craftbukkit.v1_8_R3.scheduler.CraftAsyncTask.run(CraftAsyncTask.java:53)
[22:31:18] [Craft Scheduler Thread - 71/WARN]: at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
[22:31:18] [Craft Scheduler Thread - 71/WARN]: at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
[22:31:18] [Craft Scheduler Thread - 71/WARN]: at java.lang.Thread.run(Unknown Source)
[22:31:18] [Craft Scheduler Thread - 71/WARN]: Caused by: java.io.EOFException: Can not read response from server. Expected to read 4 bytes, read 0 bytes before connection was unexpectedly lost.
[22:31:18] [Craft Scheduler Thread - 71/WARN]: at com.mysql.jdbc.MysqlIO.readFully(MysqlIO.java:2529)
[22:31:18] [Craft Scheduler Thread - 71/WARN]: at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:2979)
答案 0 :(得分:1)
首先:
据我所见,每次执行Query / Update后都会关闭连接。不幸的是,这非常不合适。如果在插件启动时打开MySQL连接并在插件停止时再次关闭它会更好。
我个人这样做:(并不意味着你必须这样做)
连接变量:
private static Connection connection;
连接功能:
public static void connect(String host, String user, String password, String database) {
Bukkit.getScheduler().runTaskAsynchronously(Main.getInstance(), () -> {
//close Connection if still active
if (connection != null) {
close();
}
//connect to database host
try {
Class.forName("com.mysql.jdbc.Driver");
connection = DriverManager.getConnection("jdbc:mysql://" + host + "/" + database, user, password);
} catch (SQLException e) {
System.out.println(e.getMessage());
}
});
}
我将数据更新/写入数据库的功能:
public void Update(final String qry) {
Bukkit.getScheduler().runTaskAsynchronously(Main.getInstance(), () -> {
try {
Statement stnt = connection.createStatement();
stnt.executeUpdate(qry);
} catch (SQLException e) {
e.printStackTrace();
}
});
}
我从数据库查询信息的功能:
正如您所看到的,此功能不是异步的。遗憾的是,我现在没有管理它以使这个函数异步。但是你可以通过使函数调用异步来轻松解决这个问题。例如:
Bukkit.getScheduler().runTaskAsynchronously(Main.getInstance(), () -> { Query("your query");
});
public ResultSet Query(String qry) {
ResultSet rs = null;
try {
Statement stnt = connection.createStatement();
rs = stnt.executeQuery(qry);
} catch (SQLException e) {
e.printStackTrace();
}
return rs;
}
关闭功能:
public static void close() {
Bukkit.getScheduler().runTaskAsynchronously(Main.getInstance(), () -> {
try {
connection.close();
} catch (SQLException e) {
System.out.println(e.getMessage());
}
});
}
这种方式的缺点是你一次只能连接一个数据库(在我的情况下就好了)。
希望它对你有所帮助。我也因为奇怪的MySQL错误而苦苦挣扎。幸运的是,使用此代码一切正常。
回答你的问题:
[22:31:18] [Craft Scheduler Thread - 71/WARN]: Caused by: java.io.EOFException: Can not read response from server. Expected to read 4 bytes, read 0 bytes before connection was unexpectedly lost.
据我所知,这意味着即使插件尝试使用它,也会关闭与MySQL服务器的连接。 如上所述,在开始时打开一个连接并保持打开直到插件停止应该解决这个问题。
答案 1 :(得分:0)
感谢所有帮助我解决问题的人
public void setSQLData(Player p, int kills, int deaths, int loses, int wins, int coins, int score) {
Bukkit.getScheduler().runTaskAsynchronously(plugin, new Runnable() {
@Override
public void run() {
Connection connection = plugin.sql.getConnection();
try {
PreparedStatement insert = connection.prepareStatement(
"INSERT INTO `MurderData` (playername, wins, deaths, loses, kills, coins, score) VALUES (?, ?, ?, ?, ?, ?, ?)");
应该是UPDATE而不是插入