diff --git a/pom.xml b/pom.xml index 13b794059..6a1de4990 100755 --- a/pom.xml +++ b/pom.xml @@ -76,6 +76,7 @@ com.turt2live.metrics:MetricsExtension + net.snaq:dbpool @@ -83,6 +84,10 @@ com.turt2live.metrics com.gmail.nossr50.metrics.mcstats + + net.snaq + com.gmail.nossr50.dbpool + @@ -136,6 +141,11 @@ MetricsExtension 0.0.5-SNAPSHOT + + net.snaq + dbpool + 5.1 + diff --git a/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java b/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java index 0ee9e1b90..09d256167 100644 --- a/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java @@ -1,6 +1,7 @@ package com.gmail.nossr50.database; import java.sql.Connection; +import java.sql.Driver; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; @@ -15,6 +16,8 @@ import java.util.Map; import java.util.Properties; import java.util.UUID; +import snaq.db.ConnectionPool; + import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.MobHealthbarType; @@ -25,44 +28,53 @@ import com.gmail.nossr50.datatypes.player.PlayerProfile; import com.gmail.nossr50.datatypes.skills.AbilityType; import com.gmail.nossr50.datatypes.skills.SkillType; import com.gmail.nossr50.runnables.database.SQLDatabaseKeepaliveTask; -import com.gmail.nossr50.runnables.database.SQLReconnectTask; import com.gmail.nossr50.runnables.database.UUIDUpdateAsyncTask; import com.gmail.nossr50.util.Misc; public final class SQLDatabaseManager implements DatabaseManager { private String connectionString; private String tablePrefix = Config.getInstance().getMySQLTablePrefix(); - private Connection connection = null; - - // Scale waiting time by this much per failed attempt - private final double SCALING_FACTOR = 40.0; - - // Minimum wait in nanoseconds (default 500ms) - private final long MIN_WAIT = 500L * 1000000L; - - // Maximum time to wait between reconnects (default 5 minutes) - private final long MAX_WAIT = 5L * 60L * 1000L * 1000000L; // How long to wait when checking if connection is valid (default 3 seconds) private final int VALID_TIMEOUT = 3; - // When next to try connecting to Database in nanoseconds - private long nextReconnectTimestamp = 0L; - - // How many connection attempts have failed - private int reconnectAttempt = 0; + private ConnectionPool connectionPool; protected SQLDatabaseManager() { + connectionString = "jdbc:mysql://" + Config.getInstance().getMySQLServerName() + ":" + Config.getInstance().getMySQLServerPort() + "/" + Config.getInstance().getMySQLDatabaseName(); + + try { + // Force driver to load if not yet loaded + Class c = Class.forName("com.mysql.jdbc.Driver"); + Driver driver = (Driver) c.newInstance(); + DriverManager.registerDriver(driver); + Properties connectionProperties = new Properties(); + connectionProperties.put("user", Config.getInstance().getMySQLUserName()); + connectionProperties.put("password", Config.getInstance().getMySQLUserPassword()); + connectionProperties.put("autoReconnect", "false"); + connectionPool = new ConnectionPool("mcMMO-Pool", 1 /*Minimum of one*/, 10 /*max pool size Configurable?*/, 10/*max num connections Configurable?*/, 0 /* idle timeout of connections */, connectionString, connectionProperties); + connectionPool.init(); // Init first connection + connectionPool.registerShutdownHook(); // Auto release when done + } catch (ClassNotFoundException e) { + // TODO tft do something here + e.printStackTrace(); + } catch (SQLException e) { + // TODO tft do something here + e.printStackTrace(); + } catch (InstantiationException e) { + // TODO tft do something here + e.printStackTrace(); + } catch (IllegalAccessException e) { + // TODO tft do something here + e.printStackTrace(); + } + checkStructure(); new SQLDatabaseKeepaliveTask(this).runTaskTimerAsynchronously(mcMMO.p, 10, 60L * 60 * Misc.TICK_CONVERSION_FACTOR); } public void purgePowerlessUsers() { - if (!checkConnected()) { - return; - } - mcMMO.p.getLogger().info("Purging powerless users..."); Collection> usernames = read("SELECT u.user FROM " + tablePrefix + "skills AS s, " + tablePrefix + "users AS u WHERE s.user_id = u.id AND (s.taming+s.mining+s.woodcutting+s.repair+s.unarmed+s.herbalism+s.excavation+s.archery+s.swords+s.axes+s.acrobatics+s.fishing) = 0").values(); @@ -79,10 +91,6 @@ public final class SQLDatabaseManager implements DatabaseManager { } public void purgeOldUsers() { - if (!checkConnected()) { - return; - } - long currentTime = System.currentTimeMillis(); mcMMO.p.getLogger().info("Purging old users..."); @@ -101,10 +109,6 @@ public final class SQLDatabaseManager implements DatabaseManager { } public boolean removeUser(String playerName) { - if (!checkConnected()) { - return false; - } - boolean success = update("DELETE FROM u, e, h, s, c " + "USING " + tablePrefix + "users u " + "JOIN " + tablePrefix + "experience e ON (u.id = e.user_id) " + @@ -119,10 +123,6 @@ public final class SQLDatabaseManager implements DatabaseManager { } public boolean saveUser(PlayerProfile profile) { - if (!checkConnected()) { - return false; - } - int userId = readId(profile.getPlayerName()); if (userId == -1) { newUser(profile.getPlayerName(), profile.getUniqueId().toString()); @@ -197,38 +197,42 @@ public final class SQLDatabaseManager implements DatabaseManager { public List readLeaderboard(SkillType skill, int pageNumber, int statsPerPage) { List stats = new ArrayList(); - if (checkConnected()) { - String query = skill == null ? "taming+mining+woodcutting+repair+unarmed+herbalism+excavation+archery+swords+axes+acrobatics+fishing+alchemy" : skill.name().toLowerCase(); - ResultSet resultSet; - PreparedStatement statement = null; + String query = skill == null ? "taming+mining+woodcutting+repair+unarmed+herbalism+excavation+archery+swords+axes+acrobatics+fishing+alchemy" : skill.name().toLowerCase(); + ResultSet resultSet; + PreparedStatement statement = null; + Connection connection = null; - try { - statement = connection.prepareStatement("SELECT " + query + ", user, NOW() FROM " + tablePrefix + "users JOIN " + tablePrefix + "skills ON (user_id = id) WHERE " + query + " > 0 ORDER BY " + query + " DESC, user LIMIT ?, ?"); - statement.setInt(1, (pageNumber * statsPerPage) - statsPerPage); - statement.setInt(2, statsPerPage); - resultSet = statement.executeQuery(); + try { + connection = connectionPool.getConnection(VALID_TIMEOUT); + statement = connection.prepareStatement("SELECT " + query + ", user, NOW() FROM " + tablePrefix + "users JOIN " + tablePrefix + "skills ON (user_id = id) WHERE " + query + " > 0 ORDER BY " + query + " DESC, user LIMIT ?, ?"); + statement.setInt(1, (pageNumber * statsPerPage) - statsPerPage); + statement.setInt(2, statsPerPage); + resultSet = statement.executeQuery(); - while (resultSet.next()) { - ArrayList column = new ArrayList(); + while (resultSet.next()) { + ArrayList column = new ArrayList(); - for (int i = 1; i <= resultSet.getMetaData().getColumnCount(); i++) { - column.add(resultSet.getString(i)); - } + for (int i = 1; i <= resultSet.getMetaData().getColumnCount(); i++) { + column.add(resultSet.getString(i)); + } - stats.add(new PlayerStat(column.get(1), Integer.valueOf(column.get(0)))); + stats.add(new PlayerStat(column.get(1), Integer.valueOf(column.get(0)))); + } + } catch (SQLException ex) { + printErrors(ex); + } finally { + if (statement != null) { + try { + statement.close(); + } catch (SQLException e) { + // Ignore } } - catch (SQLException ex) { - printErrors(ex); - } - finally { - if (statement != null) { - try { - statement.close(); - } - catch (SQLException e) { - // Ignore - } + if (connection != null) { + try { + connection.close(); + } catch (SQLException e) { + // Ignore } } } @@ -239,48 +243,16 @@ public final class SQLDatabaseManager implements DatabaseManager { public Map readRank(String playerName) { Map skills = new HashMap(); - if (checkConnected()) { - ResultSet resultSet; + ResultSet resultSet; + Connection connection = null; - try { - for (SkillType skillType : SkillType.NON_CHILD_SKILLS) { - String skillName = skillType.name().toLowerCase(); - String sql = "SELECT COUNT(*) AS rank FROM " + tablePrefix + "users JOIN " + tablePrefix + "skills ON user_id = id WHERE " + skillName + " > 0 " + - "AND " + skillName + " > (SELECT " + skillName + " FROM " + tablePrefix + "users JOIN " + tablePrefix + "skills ON user_id = id " + - "WHERE user = ?)"; - - PreparedStatement statement = connection.prepareStatement(sql); - statement.setString(1, playerName); - resultSet = statement.executeQuery(); - - resultSet.next(); - - int rank = resultSet.getInt("rank"); - - sql = "SELECT user, " + skillName + " FROM " + tablePrefix + "users JOIN " + tablePrefix + "skills ON user_id = id WHERE " + skillName + " > 0 " + - "AND " + skillName + " = (SELECT " + skillName + " FROM " + tablePrefix + "users JOIN " + tablePrefix + "skills ON user_id = id " + - "WHERE user = '" + playerName + "') ORDER BY user"; - - statement.close(); - - statement = connection.prepareStatement(sql); - resultSet = statement.executeQuery(); - - while (resultSet.next()) { - if (resultSet.getString("user").equalsIgnoreCase(playerName)) { - skills.put(skillType, rank + resultSet.getRow()); - break; - } - } - - statement.close(); - } - - String sql = "SELECT COUNT(*) AS rank FROM " + tablePrefix + "users JOIN " + tablePrefix + "skills ON user_id = id " + - "WHERE taming+mining+woodcutting+repair+unarmed+herbalism+excavation+archery+swords+axes+acrobatics+fishing+alchemy > 0 " + - "AND taming+mining+woodcutting+repair+unarmed+herbalism+excavation+archery+swords+axes+acrobatics+fishing+alchemy > " + - "(SELECT taming+mining+woodcutting+repair+unarmed+herbalism+excavation+archery+swords+axes+acrobatics+fishing+alchemy " + - "FROM " + tablePrefix + "users JOIN " + tablePrefix + "skills ON user_id = id WHERE user = ?)"; + try { + connection = connectionPool.getConnection(VALID_TIMEOUT); + for (SkillType skillType : SkillType.NON_CHILD_SKILLS) { + String skillName = skillType.name().toLowerCase(); + String sql = "SELECT COUNT(*) AS rank FROM " + tablePrefix + "users JOIN " + tablePrefix + "skills ON user_id = id WHERE " + skillName + " > 0 " + + "AND " + skillName + " > (SELECT " + skillName + " FROM " + tablePrefix + "users JOIN " + tablePrefix + "skills ON user_id = id " + + "WHERE user = ?)"; PreparedStatement statement = connection.prepareStatement(sql); statement.setString(1, playerName); @@ -290,30 +262,69 @@ public final class SQLDatabaseManager implements DatabaseManager { int rank = resultSet.getInt("rank"); + sql = "SELECT user, " + skillName + " FROM " + tablePrefix + "users JOIN " + tablePrefix + "skills ON user_id = id WHERE " + skillName + " > 0 " + + "AND " + skillName + " = (SELECT " + skillName + " FROM " + tablePrefix + "users JOIN " + tablePrefix + "skills ON user_id = id " + + "WHERE user = '" + playerName + "') ORDER BY user"; + statement.close(); - sql = "SELECT user, taming+mining+woodcutting+repair+unarmed+herbalism+excavation+archery+swords+axes+acrobatics+fishing+alchemy " + - "FROM " + tablePrefix + "users JOIN " + tablePrefix + "skills ON user_id = id " + - "WHERE taming+mining+woodcutting+repair+unarmed+herbalism+excavation+archery+swords+axes+acrobatics+fishing+alchemy > 0 " + - "AND taming+mining+woodcutting+repair+unarmed+herbalism+excavation+archery+swords+axes+acrobatics+fishing+alchemy = " + - "(SELECT taming+mining+woodcutting+repair+unarmed+herbalism+excavation+archery+swords+axes+acrobatics+fishing+alchemy " + - "FROM " + tablePrefix + "users JOIN " + tablePrefix + "skills ON user_id = id WHERE user = ?) ORDER BY user"; - statement = connection.prepareStatement(sql); - statement.setString(1, playerName); resultSet = statement.executeQuery(); while (resultSet.next()) { if (resultSet.getString("user").equalsIgnoreCase(playerName)) { - skills.put(null, rank + resultSet.getRow()); + skills.put(skillType, rank + resultSet.getRow()); break; } } statement.close(); } - catch (SQLException ex) { - printErrors(ex); + + String sql = "SELECT COUNT(*) AS rank FROM " + tablePrefix + "users JOIN " + tablePrefix + "skills ON user_id = id " + + "WHERE taming+mining+woodcutting+repair+unarmed+herbalism+excavation+archery+swords+axes+acrobatics+fishing+alchemy > 0 " + + "AND taming+mining+woodcutting+repair+unarmed+herbalism+excavation+archery+swords+axes+acrobatics+fishing+alchemy > " + + "(SELECT taming+mining+woodcutting+repair+unarmed+herbalism+excavation+archery+swords+axes+acrobatics+fishing+alchemy " + + "FROM " + tablePrefix + "users JOIN " + tablePrefix + "skills ON user_id = id WHERE user = ?)"; + + PreparedStatement statement = connection.prepareStatement(sql); + statement.setString(1, playerName); + resultSet = statement.executeQuery(); + + resultSet.next(); + + int rank = resultSet.getInt("rank"); + + statement.close(); + + sql = "SELECT user, taming+mining+woodcutting+repair+unarmed+herbalism+excavation+archery+swords+axes+acrobatics+fishing+alchemy " + + "FROM " + tablePrefix + "users JOIN " + tablePrefix + "skills ON user_id = id " + + "WHERE taming+mining+woodcutting+repair+unarmed+herbalism+excavation+archery+swords+axes+acrobatics+fishing+alchemy > 0 " + + "AND taming+mining+woodcutting+repair+unarmed+herbalism+excavation+archery+swords+axes+acrobatics+fishing+alchemy = " + + "(SELECT taming+mining+woodcutting+repair+unarmed+herbalism+excavation+archery+swords+axes+acrobatics+fishing+alchemy " + + "FROM " + tablePrefix + "users JOIN " + tablePrefix + "skills ON user_id = id WHERE user = ?) ORDER BY user"; + + statement = connection.prepareStatement(sql); + statement.setString(1, playerName); + resultSet = statement.executeQuery(); + + while (resultSet.next()) { + if (resultSet.getString("user").equalsIgnoreCase(playerName)) { + skills.put(null, rank + resultSet.getRow()); + break; + } + } + + statement.close(); + } catch (SQLException ex) { + printErrors(ex); + } finally { + if (connection != null) { + try { + connection.close(); + } catch (SQLException e) { + // Ignore + } } } @@ -321,13 +332,11 @@ public final class SQLDatabaseManager implements DatabaseManager { } public void newUser(String playerName, String uuid) { - if (!checkConnected()) { - return; - } - PreparedStatement statement = null; + Connection connection = null; try { + connection = connectionPool.getConnection(VALID_TIMEOUT); statement = connection.prepareStatement("INSERT INTO " + tablePrefix + "users (user, uuid, lastlogin) VALUES (?, ?, ?)", Statement.RETURN_GENERATED_KEYS); statement.setString(1, playerName); statement.setString(2, uuid); @@ -336,16 +345,20 @@ public final class SQLDatabaseManager implements DatabaseManager { int id = readId(playerName); writeMissingRows(id); - } - catch (SQLException ex) { + } catch (SQLException ex) { printErrors(ex); - } - finally { + } finally { if (statement != null) { try { statement.close(); + } catch (SQLException e) { + // Ignore } - catch (SQLException e) { + } + if (connection != null) { + try { + connection.close(); + } catch (SQLException e) { // Ignore } } @@ -353,22 +366,15 @@ public final class SQLDatabaseManager implements DatabaseManager { } /** - * This is a fallback method to provide the old way of getting a PlayerProfile - * in case there is no UUID match found + * This is a fallback method to provide the old way of getting a + * PlayerProfile in case there is no UUID match found */ private PlayerProfile loadPlayerNameProfile(String playerName, String uuid, boolean create, boolean retry) { - if (!checkConnected()) { - // return fake profile if not connected - if (uuid.isEmpty()) { - return new PlayerProfile(playerName, false); - } - - return new PlayerProfile(playerName, UUID.fromString(uuid), false); - } - PreparedStatement statement = null; + Connection connection = null; try { + connection = connectionPool.getConnection(VALID_TIMEOUT); statement = connection.prepareStatement( "SELECT " + "s.taming, s.mining, s.repair, s.woodcutting, s.unarmed, s.herbalism, s.excavation, s.archery, s.swords, s.axes, s.acrobatics, s.fishing, s.alchemy, " @@ -390,21 +396,24 @@ public final class SQLDatabaseManager implements DatabaseManager { PlayerProfile ret = loadFromResult(playerName, result); result.close(); return ret; - } - catch (SQLException e) { + } catch (SQLException e) { } } result.close(); - } - catch (SQLException ex) { + } catch (SQLException ex) { printErrors(ex); - } - finally { + } finally { if (statement != null) { try { statement.close(); + } catch (SQLException e) { + // Ignore } - catch (SQLException e) { + } + if (connection != null) { + try { + connection.close(); + } catch (SQLException e) { // Ignore } } @@ -451,18 +460,11 @@ public final class SQLDatabaseManager implements DatabaseManager { } private PlayerProfile loadPlayerProfile(String playerName, String uuid, boolean create, boolean retry) { - if (!checkConnected()) { - // return fake profile if not connected - if (uuid.isEmpty()) { - return new PlayerProfile(playerName, false); - } - - return new PlayerProfile(playerName, UUID.fromString(uuid), false); - } - PreparedStatement statement = null; + Connection connection = null; try { + connection = connectionPool.getConnection(VALID_TIMEOUT); statement = connection.prepareStatement( "SELECT " + "s.taming, s.mining, s.repair, s.woodcutting, s.unarmed, s.herbalism, s.excavation, s.archery, s.swords, s.axes, s.acrobatics, s.fishing, s.alchemy, " @@ -483,6 +485,7 @@ public final class SQLDatabaseManager implements DatabaseManager { try { PlayerProfile profile = loadFromResult(playerName, result); result.close(); + statement.close(); if (!playerName.isEmpty() && !profile.getPlayerName().isEmpty()) { statement = connection.prepareStatement( @@ -496,21 +499,24 @@ public final class SQLDatabaseManager implements DatabaseManager { } return profile; - } - catch (SQLException e) { + } catch (SQLException e) { } } result.close(); - } - catch (SQLException ex) { + } catch (SQLException ex) { printErrors(ex); - } - finally { + } finally { if (statement != null) { try { statement.close(); + } catch (SQLException e) { + // Ignore } - catch (SQLException e) { + } + if (connection != null) { + try { + connection.close(); + } catch (SQLException e) { // Ignore } } @@ -544,13 +550,11 @@ public final class SQLDatabaseManager implements DatabaseManager { } public void convertUsers(DatabaseManager destination) { - if (!checkConnected()) { - return; - } - PreparedStatement statement = null; + Connection connection = null; try { + connection = connectionPool.getConnection(VALID_TIMEOUT); statement = connection.prepareStatement( "SELECT " + "s.taming, s.mining, s.repair, s.woodcutting, s.unarmed, s.herbalism, s.excavation, s.archery, s.swords, s.axes, s.acrobatics, s.fishing, s.alchemy, " @@ -574,23 +578,26 @@ public final class SQLDatabaseManager implements DatabaseManager { resultSet.next(); destination.saveUser(loadFromResult(playerName, resultSet)); resultSet.close(); - } - catch (SQLException e) { + } catch (SQLException e) { // Ignore } convertedUsers++; Misc.printProgress(convertedUsers, progressInterval, startMillis); } - } - catch (SQLException e) { + } catch (SQLException e) { printErrors(e); - } - finally { + } finally { if (statement != null) { try { statement.close(); + } catch (SQLException e) { + // Ignore } - catch (SQLException e) { + } + if (connection != null) { + try { + connection.close(); + } catch (SQLException e) { // Ignore } } @@ -599,14 +606,11 @@ public final class SQLDatabaseManager implements DatabaseManager { } public boolean saveUserUUID(String userName, UUID uuid) { - if (!checkConnected()) { - // return false - return false; - } - PreparedStatement statement = null; + Connection connection = null; try { + connection = connectionPool.getConnection(VALID_TIMEOUT); statement = connection.prepareStatement( "UPDATE `" + tablePrefix + "users` SET " + " uuid = ? WHERE user = ?"); @@ -614,17 +618,21 @@ public final class SQLDatabaseManager implements DatabaseManager { statement.setString(2, userName); statement.execute(); return true; - } - catch (SQLException ex) { + } catch (SQLException ex) { printErrors(ex); return false; - } - finally { + } finally { if (statement != null) { try { statement.close(); + } catch (SQLException e) { + // Ignore } - catch (SQLException e) { + } + if (connection != null) { + try { + connection.close(); + } catch (SQLException e) { // Ignore } } @@ -634,14 +642,13 @@ public final class SQLDatabaseManager implements DatabaseManager { } public boolean saveUserUUIDs(Map fetchedUUIDs) { - if (!checkConnected()) { - return false; - } - PreparedStatement statement = null; int count = 0; + Connection connection = null; + try { + connection = connectionPool.getConnection(VALID_TIMEOUT); statement = connection.prepareStatement("UPDATE " + tablePrefix + "users SET uuid = ? WHERE user = ?"); for (Map.Entry entry : fetchedUUIDs.entrySet()) { @@ -663,137 +670,56 @@ public final class SQLDatabaseManager implements DatabaseManager { } return true; - } - catch (SQLException ex) { + } catch (SQLException ex) { printErrors(ex); return false; - } - finally { + } finally { if (statement != null) { try { statement.close(); + } catch (SQLException e) { + // Ignore } - catch (SQLException e) { + } + if (connection != null) { + try { + connection.close(); + } catch (SQLException e) { // Ignore } } } } - /** - * Check connection status and re-establish if dead or stale. - *

- * If the very first immediate attempt fails, further attempts - * will be made in progressively larger intervals up to MAX_WAIT - * intervals. - *

- * This allows for MySQL to time out idle connections as needed by - * server operator, without affecting McMMO, while still providing - * protection against a database outage taking down Bukkit's tick - * processing loop due to attempting a database connection each - * time McMMO needs the database. - * - * @return the boolean value for whether or not we are connected - */ - public boolean checkConnected() { - boolean isClosed = true; - boolean isValid = false; - boolean exists = (connection != null); - - // If we're waiting for server to recover then leave early - if (nextReconnectTimestamp > 0 && nextReconnectTimestamp > System.nanoTime()) { - return false; - } - - if (exists) { - try { - isClosed = connection.isClosed(); - } - catch (SQLException e) { - isClosed = true; - e.printStackTrace(); - printErrors(e); - } - - if (!isClosed) { - try { - isValid = connection.isValid(VALID_TIMEOUT); - } - catch (SQLException e) { - // Don't print stack trace because it's valid to lose idle connections to the server and have to restart them. - isValid = false; - } - } - } - - // Leave if all ok - if (exists && !isClosed && isValid) { - // Housekeeping - nextReconnectTimestamp = 0; - reconnectAttempt = 0; - return true; - } - - // Cleanup after ourselves for GC and MySQL's sake - if (exists && !isClosed) { - try { - connection.close(); - } - catch (SQLException ex) { - // This is a housekeeping exercise, ignore errors - } - } - - // Try to connect again - connect(); - - // Leave if connection is good - try { - if (connection != null && !connection.isClosed()) { - // Schedule a database save if we really had an outage - if (reconnectAttempt > 1) { - new SQLReconnectTask().runTaskLater(mcMMO.p, 5); - } - nextReconnectTimestamp = 0; - reconnectAttempt = 0; - return true; - } - } - catch (SQLException e) { - // Failed to check isClosed, so presume connection is bad and attempt later - e.printStackTrace(); - printErrors(e); - } - - reconnectAttempt++; - nextReconnectTimestamp = (long) (System.nanoTime() + Math.min(MAX_WAIT, (reconnectAttempt * SCALING_FACTOR * MIN_WAIT))); - return false; - } - public List getStoredUsers() { ArrayList users = new ArrayList(); - if (checkConnected()) { - Statement stmt = null; - try { - stmt = connection.createStatement(); - ResultSet result = stmt.executeQuery("SELECT user FROM " + tablePrefix + "users"); - while (result.next()) { - users.add(result.getString("user")); + Statement stmt = null; + Connection connection = null; + + try { + connection = connectionPool.getConnection(VALID_TIMEOUT); + stmt = connection.createStatement(); + ResultSet result = stmt.executeQuery("SELECT user FROM " + tablePrefix + "users"); + while (result.next()) { + users.add(result.getString("user")); + } + result.close(); + } catch (SQLException e) { + printErrors(e); + } finally { + if (stmt != null) { + try { + stmt.close(); + } catch (SQLException e) { + // Ignore } - result.close(); } - catch (SQLException e) { - printErrors(e); - } - finally { - if (stmt != null) { - try { - stmt.close(); - } - catch (SQLException e) { - // Ignore - } + if (connection != null) { + try { + connection.close(); + } catch (SQLException e) { + // Ignore } } } @@ -801,50 +727,10 @@ public final class SQLDatabaseManager implements DatabaseManager { return users; } - /** - * Attempt to connect to the mySQL database. - */ - private void connect() { - connectionString = "jdbc:mysql://" + Config.getInstance().getMySQLServerName() + ":" + Config.getInstance().getMySQLServerPort() + "/" + Config.getInstance().getMySQLDatabaseName(); - - try { - mcMMO.p.getLogger().info("Attempting connection to MySQL..."); - - // Force driver to load if not yet loaded - Class.forName("com.mysql.jdbc.Driver"); - Properties connectionProperties = new Properties(); - connectionProperties.put("user", Config.getInstance().getMySQLUserName()); - connectionProperties.put("password", Config.getInstance().getMySQLUserPassword()); - connectionProperties.put("autoReconnect", "false"); - connection = DriverManager.getConnection(connectionString, connectionProperties); - - mcMMO.p.getLogger().info("Connection to MySQL was a success!"); - } - catch (SQLException ex) { - connection = null; - - if (reconnectAttempt == 0 || reconnectAttempt >= 11) { - mcMMO.p.getLogger().severe("Connection to MySQL failed!"); - printErrors(ex); - } - } - catch (ClassNotFoundException ex) { - connection = null; - - if (reconnectAttempt == 0 || reconnectAttempt >= 11) { - mcMMO.p.getLogger().severe("MySQL database driver not found!"); - } - } - } - /** * Checks that the database structure is present and correct */ private void checkStructure() { - if (!checkConnected()) { - return; - } - write("CREATE TABLE IF NOT EXISTS `" + tablePrefix + "users` (" + "`id` int(10) unsigned NOT NULL AUTO_INCREMENT," + "`user` varchar(40) NOT NULL," @@ -921,14 +807,11 @@ public final class SQLDatabaseManager implements DatabaseManager { /** * Check database structure for necessary upgrades. - * - * @param upgrade Upgrade to attempt to apply + * + * @param upgrade + * Upgrade to attempt to apply */ private void checkDatabaseStructure(UpgradeType upgrade) { - if (!checkConnected()) { - return; - } - if (!mcMMO.getUpgradeManager().shouldUpgrade(upgrade)) { mcMMO.p.debug("Skipping " + upgrade.name() + " upgrade (unneeded)"); return; @@ -936,7 +819,10 @@ public final class SQLDatabaseManager implements DatabaseManager { Statement statement = null; + Connection connection = null; + try { + connection = connectionPool.getConnection(VALID_TIMEOUT); statement = connection.createStatement(); switch (upgrade) { @@ -978,16 +864,20 @@ public final class SQLDatabaseManager implements DatabaseManager { } mcMMO.getUpgradeManager().setUpgradeCompleted(upgrade); - } - catch (SQLException ex) { + } catch (SQLException ex) { printErrors(ex); - } - finally { + } finally { if (statement != null) { try { statement.close(); + } catch (SQLException e) { + // Ignore } - catch (SQLException e) { + } + if (connection != null) { + try { + connection.close(); + } catch (SQLException e) { // Ignore } } @@ -996,34 +886,38 @@ public final class SQLDatabaseManager implements DatabaseManager { /** * Attempt to write the SQL query. - * - * @param sql Query to write. - * + * + * @param sql + * Query to write. + * * @return true if the query was successfully written, false otherwise. */ private boolean write(String sql) { - if (!checkConnected()) { - return false; - } - PreparedStatement statement = null; + Connection connection = null; + try { + connection = connectionPool.getConnection(VALID_TIMEOUT); statement = connection.prepareStatement(sql); statement.executeUpdate(); return true; - } - catch (SQLException ex) { + } catch (SQLException ex) { if (!sql.contains("DROP COLUMN")) { printErrors(ex); } return false; - } - finally { + } finally { if (statement != null) { try { statement.close(); + } catch (SQLException e) { + // Ignore } - catch (SQLException e) { + } + if (connection != null) { + try { + connection.close(); + } catch (SQLException e) { // Ignore } } @@ -1032,32 +926,37 @@ public final class SQLDatabaseManager implements DatabaseManager { /** * Returns the number of rows affected by either a DELETE or UPDATE query - * - * @param sql SQL query to execute - * + * + * @param sql + * SQL query to execute + * * @return the number of rows affected */ private int update(String sql) { int rows = 0; - if (checkConnected()) { - PreparedStatement statement = null; + PreparedStatement statement = null; + Connection connection = null; - try { - statement = connection.prepareStatement(sql); - rows = statement.executeUpdate(); + try { + connection = connectionPool.getConnection(VALID_TIMEOUT); + statement = connection.prepareStatement(sql); + rows = statement.executeUpdate(); + } catch (SQLException ex) { + printErrors(ex); + } finally { + if (statement != null) { + try { + statement.close(); + } catch (SQLException e) { + // Ignore + } } - catch (SQLException ex) { - printErrors(ex); - } - finally { - if (statement != null) { - try { - statement.close(); - } - catch (SQLException e) { - // Ignore - } + if (connection != null) { + try { + connection.close(); + } catch (SQLException e) { + // Ignore } } } @@ -1067,43 +966,49 @@ public final class SQLDatabaseManager implements DatabaseManager { /** * Read SQL query. - * - * @param sql SQL query to read - * + * + * @param sql + * SQL query to read + * * @return the rows in this SQL query */ private HashMap> read(String sql) { HashMap> rows = new HashMap>(); - if (checkConnected()) { - PreparedStatement statement = null; - ResultSet resultSet; + PreparedStatement statement = null; + ResultSet resultSet; - try { - statement = connection.prepareStatement(sql); - resultSet = statement.executeQuery(); + Connection connection = null; - while (resultSet.next()) { - ArrayList column = new ArrayList(); + try { + connection = connectionPool.getConnection(VALID_TIMEOUT); + statement = connection.prepareStatement(sql); + resultSet = statement.executeQuery(); - for (int i = 1; i <= resultSet.getMetaData().getColumnCount(); i++) { - column.add(resultSet.getString(i)); - } + while (resultSet.next()) { + ArrayList column = new ArrayList(); - rows.put(resultSet.getRow(), column); + for (int i = 1; i <= resultSet.getMetaData().getColumnCount(); i++) { + column.add(resultSet.getString(i)); + } + + rows.put(resultSet.getRow(), column); + } + } catch (SQLException ex) { + printErrors(ex); + } finally { + if (statement != null) { + try { + statement.close(); + } catch (SQLException e) { + // Ignore } } - catch (SQLException ex) { - printErrors(ex); - } - finally { - if (statement != null) { - try { - statement.close(); - } - catch (SQLException e) { - // Ignore - } + if (connection != null) { + try { + connection.close(); + } catch (SQLException e) { + // Ignore } } } @@ -1113,35 +1018,31 @@ public final class SQLDatabaseManager implements DatabaseManager { /** * Get the Integer. Only return first row / first field. - * - * @param statement SQL query to execute - * + * + * @param statement + * SQL query to execute + * * @return the value in the first row / first field */ private int readInt(PreparedStatement statement) { int result = -1; - if (checkConnected()) { - ResultSet resultSet; + ResultSet resultSet; - try { - resultSet = statement.executeQuery(); + try { + resultSet = statement.executeQuery(); - if (resultSet.next()) { - result = resultSet.getInt(1); - } + if (resultSet.next()) { + result = resultSet.getInt(1); } - catch (SQLException ex) { - printErrors(ex); - } - finally { - if (statement != null) { - try { - statement.close(); - } - catch (SQLException e) { - // Ignore - } + } catch (SQLException ex) { + printErrors(ex); + } finally { + if (statement != null) { + try { + statement.close(); + } catch (SQLException e) { + // Ignore } } } @@ -1152,7 +1053,10 @@ public final class SQLDatabaseManager implements DatabaseManager { private void writeMissingRows(int id) { PreparedStatement statement = null; + Connection connection = null; + try { + connection = connectionPool.getConnection(VALID_TIMEOUT); statement = connection.prepareStatement("INSERT IGNORE INTO " + tablePrefix + "experience (user_id) VALUES (?)"); statement.setInt(1, id); statement.execute(); @@ -1172,16 +1076,20 @@ public final class SQLDatabaseManager implements DatabaseManager { statement.setInt(1, id); statement.execute(); statement.close(); - } - catch (SQLException ex) { + } catch (SQLException ex) { printErrors(ex); - } - finally { + } finally { if (statement != null) { try { statement.close(); + } catch (SQLException e) { + // Ignore } - catch (SQLException e) { + } + if (connection != null) { + try { + connection.close(); + } catch (SQLException e) { // Ignore } } @@ -1196,8 +1104,10 @@ public final class SQLDatabaseManager implements DatabaseManager { private boolean saveIntegers(String sql, int... args) { PreparedStatement statement = null; + Connection connection = null; try { + connection = connectionPool.getConnection(VALID_TIMEOUT); statement = connection.prepareStatement(sql); int i = 1; @@ -1207,17 +1117,21 @@ public final class SQLDatabaseManager implements DatabaseManager { statement.execute(); return true; - } - catch (SQLException ex) { + } catch (SQLException ex) { printErrors(ex); return false; - } - finally { + } finally { if (statement != null) { try { statement.close(); + } catch (SQLException e) { + // Ignore } - catch (SQLException e) { + } + if (connection != null) { + try { + connection.close(); + } catch (SQLException e) { // Ignore } } @@ -1227,7 +1141,10 @@ public final class SQLDatabaseManager implements DatabaseManager { private boolean saveLongs(String sql, int id, long... args) { PreparedStatement statement = null; + Connection connection = null; + try { + connection = connectionPool.getConnection(VALID_TIMEOUT); statement = connection.prepareStatement(sql); int i = 1; @@ -1238,17 +1155,21 @@ public final class SQLDatabaseManager implements DatabaseManager { statement.setInt(i++, id); statement.execute(); return true; - } - catch (SQLException ex) { + } catch (SQLException ex) { printErrors(ex); return false; - } - finally { + } finally { if (statement != null) { try { statement.close(); + } catch (SQLException e) { + // Ignore } - catch (SQLException e) { + } + if (connection != null) { + try { + connection.close(); + } catch (SQLException e) { // Ignore } } @@ -1257,21 +1178,32 @@ public final class SQLDatabaseManager implements DatabaseManager { /** * Retrieve the database id for a player - * - * @param playerName The name of the user to retrieve the id for - * + * + * @param playerName + * The name of the user to retrieve the id for + * * @return the requested id or -1 if not found */ private int readId(String playerName) { int id = -1; + Connection connection = null; + try { + connection = connectionPool.getConnection(VALID_TIMEOUT); PreparedStatement statement = connection.prepareStatement("SELECT id FROM " + tablePrefix + "users WHERE user = ?"); statement.setString(1, playerName); id = readInt(statement); - } - catch (SQLException ex) { + } catch (SQLException ex) { printErrors(ex); + } finally { + if (connection != null) { + try { + connection.close(); + } catch (SQLException e) { + // Ignore + } + } } return id; @@ -1280,23 +1212,30 @@ public final class SQLDatabaseManager implements DatabaseManager { private boolean saveUniqueId(int id, String uuid) { PreparedStatement statement = null; + Connection connection = null; + try { + connection = connectionPool.getConnection(VALID_TIMEOUT); statement = connection.prepareStatement("UPDATE " + tablePrefix + "users SET uuid = ? WHERE id = ?"); statement.setString(1, uuid); statement.setInt(2, id); statement.execute(); return true; - } - catch (SQLException ex) { + } catch (SQLException ex) { printErrors(ex); return false; - } - finally { + } finally { if (statement != null) { try { statement.close(); + } catch (SQLException e) { + // Ignore } - catch (SQLException e) { + } + if (connection != null) { + try { + connection.close(); + } catch (SQLException e) { // Ignore } } @@ -1306,23 +1245,30 @@ public final class SQLDatabaseManager implements DatabaseManager { private boolean saveLogin(int id, long login) { PreparedStatement statement = null; + Connection connection = null; + try { + connection = connectionPool.getConnection(VALID_TIMEOUT); statement = connection.prepareStatement("UPDATE " + tablePrefix + "users SET lastlogin = ? WHERE id = ?"); statement.setLong(1, login); statement.setInt(2, id); statement.execute(); return true; - } - catch (SQLException ex) { + } catch (SQLException ex) { printErrors(ex); return false; - } - finally { + } finally { if (statement != null) { try { statement.close(); + } catch (SQLException e) { + // Ignore } - catch (SQLException e) { + } + if (connection != null) { + try { + connection.close(); + } catch (SQLException e) { // Ignore } } @@ -1332,23 +1278,30 @@ public final class SQLDatabaseManager implements DatabaseManager { private boolean saveHuds(int userId, String mobHealthBar) { PreparedStatement statement = null; + Connection connection = null; + try { + connection = connectionPool.getConnection(VALID_TIMEOUT); statement = connection.prepareStatement("UPDATE " + tablePrefix + "huds SET mobhealthbar = ? WHERE user_id = ?"); statement.setString(1, mobHealthBar); statement.setInt(2, userId); statement.execute(); return true; - } - catch (SQLException ex) { + } catch (SQLException ex) { printErrors(ex); return false; - } - finally { + } finally { if (statement != null) { try { statement.close(); + } catch (SQLException e) { + // Ignore } - catch (SQLException e) { + } + if (connection != null) { + try { + connection.close(); + } catch (SQLException e) { // Ignore } } @@ -1356,13 +1309,20 @@ public final class SQLDatabaseManager implements DatabaseManager { } private PlayerProfile loadFromResult(String playerName, ResultSet result) throws SQLException { - Map skills = new HashMap(); // Skill & Level - Map skillsXp = new HashMap(); // Skill & XP - Map skillsDATS = new HashMap(); // Ability & Cooldown + Map skills = new HashMap(); // Skill + // & + // Level + Map skillsXp = new HashMap(); // Skill + // & + // XP + Map skillsDATS = new HashMap(); // Ability + // & + // Cooldown MobHealthbarType mobHealthbarType; UUID uuid; - final int OFFSET_SKILLS = 0; // TODO update these numbers when the query changes (a new skill is added) + final int OFFSET_SKILLS = 0; // TODO update these numbers when the query + // changes (a new skill is added) final int OFFSET_XP = 13; final int OFFSET_DATS = 26; final int OFFSET_OTHER = 38; @@ -1410,15 +1370,13 @@ public final class SQLDatabaseManager implements DatabaseManager { try { mobHealthbarType = MobHealthbarType.valueOf(result.getString(OFFSET_OTHER + 2)); - } - catch (Exception e) { + } catch (Exception e) { mobHealthbarType = Config.getInstance().getMobHealthbarDefault(); } try { uuid = UUID.fromString(result.getString(OFFSET_OTHER + 3)); - } - catch (Exception e) { + } catch (Exception e) { uuid = null; } @@ -1438,8 +1396,7 @@ public final class SQLDatabaseManager implements DatabaseManager { private void checkUpgradeAddAlchemy(final Statement statement) throws SQLException { try { statement.executeQuery("SELECT `alchemy` FROM `" + tablePrefix + "skills` LIMIT 1"); - } - catch (SQLException ex) { + } catch (SQLException ex) { mcMMO.p.getLogger().info("Updating mcMMO MySQL tables for Alchemy..."); statement.executeUpdate("ALTER TABLE `" + tablePrefix + "skills` ADD `alchemy` int(10) NOT NULL DEFAULT '0'"); statement.executeUpdate("ALTER TABLE `" + tablePrefix + "experience` ADD `alchemy` int(10) NOT NULL DEFAULT '0'"); @@ -1449,8 +1406,7 @@ public final class SQLDatabaseManager implements DatabaseManager { private void checkUpgradeAddBlastMiningCooldown(final Statement statement) throws SQLException { try { statement.executeQuery("SELECT `blast_mining` FROM `" + tablePrefix + "cooldowns` LIMIT 1"); - } - catch (SQLException ex) { + } catch (SQLException ex) { mcMMO.p.getLogger().info("Updating mcMMO MySQL tables for Blast Mining..."); statement.executeUpdate("ALTER TABLE `" + tablePrefix + "cooldowns` ADD `blast_mining` int(32) NOT NULL DEFAULT '0'"); } @@ -1459,8 +1415,7 @@ public final class SQLDatabaseManager implements DatabaseManager { private void checkUpgradeAddFishing(final Statement statement) throws SQLException { try { statement.executeQuery("SELECT `fishing` FROM `" + tablePrefix + "skills` LIMIT 1"); - } - catch (SQLException ex) { + } catch (SQLException ex) { mcMMO.p.getLogger().info("Updating mcMMO MySQL tables for Fishing..."); statement.executeUpdate("ALTER TABLE `" + tablePrefix + "skills` ADD `fishing` int(10) NOT NULL DEFAULT '0'"); statement.executeUpdate("ALTER TABLE `" + tablePrefix + "experience` ADD `fishing` int(10) NOT NULL DEFAULT '0'"); @@ -1470,8 +1425,7 @@ public final class SQLDatabaseManager implements DatabaseManager { private void checkUpgradeAddMobHealthbars(final Statement statement) throws SQLException { try { statement.executeQuery("SELECT `mobhealthbar` FROM `" + tablePrefix + "huds` LIMIT 1"); - } - catch (SQLException ex) { + } catch (SQLException ex) { mcMMO.p.getLogger().info("Updating mcMMO MySQL tables for mob healthbars..."); statement.executeUpdate("ALTER TABLE `" + tablePrefix + "huds` ADD `mobhealthbar` varchar(50) NOT NULL DEFAULT '" + Config.getInstance().getMobHealthbarDefault() + "'"); } @@ -1492,22 +1446,18 @@ public final class SQLDatabaseManager implements DatabaseManager { try { statement.executeUpdate("ALTER TABLE `" + tablePrefix + "skills` ADD INDEX `idx_" + skill_name + "` (`" + skill_name + "`) USING BTREE"); - } - catch (SQLException ex) { + } catch (SQLException ex) { // Ignore } } } - } - catch (SQLException ex) { + } catch (SQLException ex) { printErrors(ex); - } - finally { + } finally { if (resultSet != null) { try { resultSet.close(); - } - catch (SQLException e) { + } catch (SQLException e) { // Ignore } } @@ -1535,16 +1485,13 @@ public final class SQLDatabaseManager implements DatabaseManager { mcMMO.p.getLogger().info("Adding UUIDs to mcMMO MySQL user table..."); statement.executeUpdate("ALTER TABLE `" + tablePrefix + "users` ADD `uuid` varchar(36) NOT NULL DEFAULT ''"); } - } - catch (SQLException ex) { + } catch (SQLException ex) { printErrors(ex); - } - finally { + } finally { if (resultSet != null) { try { resultSet.close(); - } - catch (SQLException e) { + } catch (SQLException e) { // Ignore } } @@ -1556,16 +1503,13 @@ public final class SQLDatabaseManager implements DatabaseManager { while (resultSet.next()) { names.add(resultSet.getString("user")); } - } - catch (SQLException ex) { + } catch (SQLException ex) { printErrors(ex); - } - finally { + } finally { if (resultSet != null) { try { resultSet.close(); - } - catch (SQLException e) { + } catch (SQLException e) { // Ignore } } @@ -1596,16 +1540,13 @@ public final class SQLDatabaseManager implements DatabaseManager { mcMMO.p.getLogger().info("Removing party name from users table..."); statement.executeUpdate("ALTER TABLE `" + tablePrefix + "users` DROP COLUMN `party`"); } - } - catch (SQLException ex) { + } catch (SQLException ex) { printErrors(ex); - } - finally { + } finally { if (resultSet != null) { try { resultSet.close(); - } - catch (SQLException e) { + } catch (SQLException e) { // Ignore } } @@ -1632,16 +1573,13 @@ public final class SQLDatabaseManager implements DatabaseManager { mcMMO.p.getLogger().info("Removing Spout HUD type from huds table..."); statement.executeUpdate("ALTER TABLE `" + tablePrefix + "huds` DROP COLUMN `hudtype`"); } - } - catch (SQLException ex) { + } catch (SQLException ex) { printErrors(ex); - } - finally { + } finally { if (resultSet != null) { try { resultSet.close(); - } - catch (SQLException e) { + } catch (SQLException e) { // Ignore } }