• 周年纪念勋章活动已圆满结束,如有已购买但仍未申请的用户,可以通过对应勋章的下载链接申请~

已解决 我该如何更流畅的从数据库获取数据?

JiuRanX

【Lv:2】

正式会员
注册
2025/01/11
消息
6
金粒
281金粒
本服务器运行这经过修改的Spigot1.8.8核心,并且在CraftPlayer中添加了getPrefix、getSuffix、getGroup方法以便我们的开发者更容易的开发。
但是如果在一个子服务器中,服务器中人较多(大于10人),此时进入服务器就会卡顿,然后才会好,卡顿时长与当前服务器内玩家人数成正比例关系。
我们使用了HikariCP作为连接池。
以下是获取Prefix代码,其他与其类似:

Java:
@Override
    public String getPrefix() {
        try (Connection connection = Bukkit.getSugar().getLemonPermsDatabase().getDataSource().getConnection();
             Statement statement = connection.createStatement()) {
            ResultSet rs = statement.executeQuery("SELECT * FROM player_data WHERE uuid = '" + getUniqueId() + "'");
            if (rs.next()) {
                if (rs.getString("prefix") != null) {
                    return rs.getString("prefix");
                } else {
                    return getGroup().getPrefix();
                }
            } else {
                statement.executeUpdate("INSERT INTO player_data (uuid, name, group_name) VALUES ('" + getUniqueId() + "', '" + getName() + "', '默认')");
                return getGroup().getPrefix();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return new Group("默认").getPrefix();
    }

一下是对连接池的配置:
Java:
public Database(String url, int port, String db, String username, String password){
  HikariConfig APIConfig = new HikariConfig();
        APIConfig.setJdbcUrl("jdbc:mysql://" + url + ":" + port + "/" + db);
        APIConfig.setUsername(username);
        APIConfig.setPassword(password);
        APIConfig.addDataSourceProperty("verifyServerCertificate", String.valueOf(false));
        APIConfig.addDataSourceProperty("characterEncoding", "utf8");
        APIConfig.addDataSourceProperty("encoding", "UTF-8");
        APIConfig.addDataSourceProperty("useUnicode", "true");
        APIConfig.addDataSourceProperty("rewriteBatchedStatements", "true");
        APIConfig.addDataSourceProperty("jdbcCompliantTruncation", "false");
        APIConfig.addDataSourceProperty("cachePrepStmts", "true");
        APIConfig.addDataSourceProperty("prepStmtCacheSize", "275");
        APIConfig.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
        APIConfig.addDataSourceProperty("socketTimeout", String.valueOf(TimeUnit.SECONDS.toMillis(30)));
        APIConfig.setMaximumPoolSize(50);
        dataSource = new HikariDataSource(APIConfig);
}


除了通过异步获取还有更好的解决方案吗?
 
解决方案
嗯,我们试验过了,确实奏效,但是由于异步,在玩家刚刚加入服务器调用方法时会直接返回默认值,所以我们团队的人必须把一些代码修改,而且大部分人都不愿意这么做:(还有其他更好的方法吗
使用 AsyncPlayerPreLoginEvent

补充:优先级为 MONITOR,并且判断满足 event.getLoginResult() == Result.ALLOWED 时才执行。这个事件本身就是异步执行,不需要再 runTaskAsynchronously
增加缓存机制。

将从数据库拿取到的数据存到 Map,写入数据库的时候也存到 Map,然后通过 BungeeCord 消息等方式通知其它服务器更新缓存。
如果这些数据是玩家相关,并且离线了数据就可以不要了,也可以在玩家上线或下线时清除缓存。

尽可能不要在事件中调用数据库(比如 PlayerJoinEvent),如果确实需要调用,请异步执行(Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> { /*do sth*/ });

具体如何实现缓存可以参考我的插件:https://github.com/MrXiaoM/SweetAda...weet/adaptiveshop/database/OrderDatabase.java
 
增加缓存机制。

将从数据库拿取到的数据存到 Map,写入数据库的时候也存到 Map,然后通过 BungeeCord 消息等方式通知其它服务器更新缓存。
如果这些数据是玩家相关,并且离线了数据就可以不要了,也可以在玩家上线或下线时清除缓存。

尽可能不要在事件中调用数据库(比如 PlayerJoinEvent),如果确实需要调用,请异步执行(Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> { /*do sth*/ });
嗯,我们试验过了,确实奏效,但是由于异步,在玩家刚刚加入服务器调用方法时会直接返回默认值,所以我们团队的人必须把一些代码修改,而且大部分人都不愿意这么做:(还有其他更好的方法吗
 
嗯,我们试验过了,确实奏效,但是由于异步,在玩家刚刚加入服务器调用方法时会直接返回默认值,所以我们团队的人必须把一些代码修改,而且大部分人都不愿意这么做:(还有其他更好的方法吗
使用 AsyncPlayerPreLoginEvent

补充:优先级为 MONITOR,并且判断满足 event.getLoginResult() == Result.ALLOWED 时才执行。这个事件本身就是异步执行,不需要再 runTaskAsynchronously
 
解决方案
使用 AsyncPlayerPreLoginEvent

补充:优先级为 MONITOR,并且判断满足 event.getLoginResult() == Result.ALLOWED 时才执行。这个事件本身就是异步执行,不需要再 runTaskAsynchronously
感谢
 

在线会员

  • 嚣兮
  • Fing
  • hynss
  • 泡泡茶壶
  • 云澜
  • piaopiao
  • 蜘蛛耳钉
  • liucan
  • 大逍遥
  • Reiyans
  • Sabrita
  • XiaoDou_
  • suxiaolin
  • Ivan_Xu_
  • 子邪
  • a28592040
  • linghun91
  • I IKUN2004
  • Tosucceeds
  • superhacker
...和 50 更多。
后退
顶部 底部