Bukkit插件SQL ResultSet问题:无法检测玩家已存在于SQL表中
问题排查与修复方案
我帮你找到了导致hasPlayer()方法无法正确检测玩家存在的几个核心问题,正是这些错误让插件反复尝试插入已存在的玩家,触发了数据库的唯一约束错误。咱们一步步拆解并修复:
1. 字符串比较用错了方法
Java里==是用来比较对象引用地址的,不是比字符串内容的!你写的pUUID.toString() == rs.toString()永远不会返回true(除非是同一个字符串对象),必须用equals()方法来对比字符串内容才行。
2. ResultSet取值完全错误
你用rs.toString()拿到的是ResultSet这个对象本身的字符串描述,根本不是数据库里playerID列的UUID值!得用rs.getString("playerID")才能取出对应列的实际数据。
3. 查询逻辑太冗余,效率还低
现在你是把整个playerInfo表的所有playerID都查出来,再挨个循环对比,这既慢又容易出错。直接在SQL里加WHERE条件,只查当前玩家的UUID不就行了?数据库本身就擅长做这种检索,比你自己循环高效多了。
修复后的完整代码
修正后的hasPlayer()方法
public boolean hasPlayer() { UUID pUUID = p.getUniqueId(); // 直接通过WHERE条件定位目标玩家,避免全表扫描 String query = "SELECT playerID FROM playerInfo WHERE playerID = ?;"; // 用try-with-resources自动关闭资源,不用手动写close() try (Connection conn = sqlConnection.getDatabaseConnection()) { if (conn == null) { Bukkit.broadcastMessage("Database connection is null"); return false; } // 用PreparedStatement防SQL注入,更安全 try (PreparedStatement st = conn.prepareStatement(query)) { st.setString(1, pUUID.toString()); try (ResultSet rs = st.executeQuery()) { // rs.next()如果返回true,说明查到了玩家,直接返回结果 return rs.next(); } } } catch (SQLException e) { e.printStackTrace(); Bukkit.broadcastMessage("SQL Exception occurred"); return false; } }
额外优化建议
我顺便给你的addPlayer()方法也做了点优化,用try-with-resources自动关闭数据库资源,避免资源泄漏:
public boolean addPlayer() { UUID pUUID = p.getUniqueId(); String insertQuery = "INSERT INTO playerInfo (playerID, playerName, playerDiamonds) VALUES (?, ?, ?)"; try (Connection conn = sqlConnection.getDatabaseConnection(); PreparedStatement st = conn.prepareStatement(insertQuery)) { if (conn == null) { Bukkit.broadcastMessage("Database connection is null"); return false; } st.setString(1, pUUID.toString()); st.setString(2, p.getDisplayName()); st.setInt(3, 0); st.executeUpdate(); return true; } catch (SQLException e) { e.printStackTrace(); return false; } }
修复之后,玩家再次加入服务器时,hasPlayer()就能正确识别出数据库里已有的玩家,会正常提示"You are in our database",不会再触发重复插入的错误啦。
内容的提问来源于stack exchange,提问作者Oliver Huth
相关产品推荐
相关产品推荐

