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)。然后在他们真正加入服务器(PlayerLoginEventPlayerJoinEvent)时将其存储在内存中,并在他们退出时将其删除。通过这种方式,您可以在登录时通过内存而不是数据库访问数据。这要复杂得多,而且还需要大量代码才能正确实现,所以我不打算在这里详细介绍。