Bukkit/Spigot) 更好的 MySQL 统计数据更新没有滞后?
Bukkit/Spigot) Better MySQL stats updating no lag?
您好,我在 SQL 更新玩家统计数据时遇到问题,这会造成很大的损失 lag/timings 我在服务器停止时更新统计数据 这是我的统计代码:
public int getDeaths(Player p) {
if (!plugin.getConfig().getBoolean("mysql")) {
return plugin.data.getConfig().getInt("Deaths." + p.getUniqueId() + ".death");
}
if (plugin.getConfig().getBoolean("mysql")) {
int res = 0;
ResultSet result = getMainSQLConnection()
.executeQuery("SELECT * FROM `Account` WHERE playername='" + p.getName() + "'", false);
try {
if (result.next()) {
res = Integer.parseInt(result.getString("deaths"));
}
} catch (SQLException localSQLException) {
}
return res;
}
return 0;
}
public void setDeaths(Player p, int number) {
if (!plugin.getConfig().getBoolean("mysql")) {
plugin.data.getConfig().set("Deaths." + p.getUniqueId() + ".death", number);
plugin.data.save();
}
if (plugin.getConfig().getBoolean("mysql")) {
plugin.sqlConnection.executeUpdate(
"UPDATE `Account` SET deaths='" + number + "' WHERE playername='" + p.getName() + "'");
}
}
如果您正在获取命令的死亡计数或不需要立即返回值的东西,请使用异步调度程序 运行 单独线程上的代码。对于一个命令,当它被执行时你会做这样的事情:
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
try {
int deaths = getMainSQLConnection()
.executeQuery("SELECT * FROM `Account` WHERE playername='" + p.getName() + "'", false)
.getInt("deaths");
player.sendMessage("Player Deaths: " + deaths);
} catch (SQLException ex) {
player.sendMessage(ChatColor.RED + "That player does not exist!");
}
});
否则,如果出于某种原因需要代码中的值,可以使用连接池,例如HikariCP。连接池将允许您维护与数据库的多个连接,因此当您需要执行查询时,您不必每次都建立一个新连接(这将导致大部分延迟)。
更好的是,将异步任务与连接池结合使用。这是学习如何将 HikariCP 与 Bukkit 结合使用的好教程:https://www.spigotmc.org/threads/tutorial-implement-mysql-in-your-plugin-with-pooling.61678
附带说明一下,为了对服务器的性能影响基本上为零,您可以在玩家登录时异步加载数据(使用 AsyncPlayerPreLoginEvent
)。然后在他们真正加入服务器(PlayerLoginEvent
或 PlayerJoinEvent
)时将其存储在内存中,并在他们退出时将其删除。通过这种方式,您可以在登录时通过内存而不是数据库访问数据。这要复杂得多,而且还需要大量代码才能正确实现,所以我不打算在这里详细介绍。
您好,我在 SQL 更新玩家统计数据时遇到问题,这会造成很大的损失 lag/timings 我在服务器停止时更新统计数据 这是我的统计代码:
public int getDeaths(Player p) {
if (!plugin.getConfig().getBoolean("mysql")) {
return plugin.data.getConfig().getInt("Deaths." + p.getUniqueId() + ".death");
}
if (plugin.getConfig().getBoolean("mysql")) {
int res = 0;
ResultSet result = getMainSQLConnection()
.executeQuery("SELECT * FROM `Account` WHERE playername='" + p.getName() + "'", false);
try {
if (result.next()) {
res = Integer.parseInt(result.getString("deaths"));
}
} catch (SQLException localSQLException) {
}
return res;
}
return 0;
}
public void setDeaths(Player p, int number) {
if (!plugin.getConfig().getBoolean("mysql")) {
plugin.data.getConfig().set("Deaths." + p.getUniqueId() + ".death", number);
plugin.data.save();
}
if (plugin.getConfig().getBoolean("mysql")) {
plugin.sqlConnection.executeUpdate(
"UPDATE `Account` SET deaths='" + number + "' WHERE playername='" + p.getName() + "'");
}
}
如果您正在获取命令的死亡计数或不需要立即返回值的东西,请使用异步调度程序 运行 单独线程上的代码。对于一个命令,当它被执行时你会做这样的事情:
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
try {
int deaths = getMainSQLConnection()
.executeQuery("SELECT * FROM `Account` WHERE playername='" + p.getName() + "'", false)
.getInt("deaths");
player.sendMessage("Player Deaths: " + deaths);
} catch (SQLException ex) {
player.sendMessage(ChatColor.RED + "That player does not exist!");
}
});
否则,如果出于某种原因需要代码中的值,可以使用连接池,例如HikariCP。连接池将允许您维护与数据库的多个连接,因此当您需要执行查询时,您不必每次都建立一个新连接(这将导致大部分延迟)。
更好的是,将异步任务与连接池结合使用。这是学习如何将 HikariCP 与 Bukkit 结合使用的好教程:https://www.spigotmc.org/threads/tutorial-implement-mysql-in-your-plugin-with-pooling.61678
附带说明一下,为了对服务器的性能影响基本上为零,您可以在玩家登录时异步加载数据(使用 AsyncPlayerPreLoginEvent
)。然后在他们真正加入服务器(PlayerLoginEvent
或 PlayerJoinEvent
)时将其存储在内存中,并在他们退出时将其删除。通过这种方式,您可以在登录时通过内存而不是数据库访问数据。这要复杂得多,而且还需要大量代码才能正确实现,所以我不打算在这里详细介绍。