Starting to implement async in db actions
This commit is contained in:
1 parent
35290a83da
commit
5ae7e8f819
8 files changed
+176
-65
No files matched your search
@@ -18,19 +18,19 @@ public class ThreadManager {
|
||||
|
||||
public static void shutdownExecutor() {
|
||||
try {
|
||||
System.out.println("[Executor] Shutting down...");
|
||||
MusicBot.LOGGER.info("[Executor] Shutting down...");
|
||||
executor.shutdown();
|
||||
executor.awaitTermination(5, TimeUnit.SECONDS);
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
System.err.println("[Executor] Running tasks interrupted");
|
||||
MusicBot.LOGGER.warn("[Executor] Running tasks interrupted");
|
||||
}
|
||||
finally {
|
||||
if (!executor.isTerminated()) {
|
||||
System.err.println("[Executor] Forcing shutdown of running tasks..");
|
||||
MusicBot.LOGGER.warn("[Executor] Forcing shutdown of running tasks..");
|
||||
}
|
||||
executor.shutdownNow();
|
||||
System.out.println("[Executor] Shutdown finished!");
|
||||
MusicBot.LOGGER.info("[Executor] Shutdown finished!");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -48,7 +48,7 @@ public class BlacklistCommand extends AbstractCommand {
|
||||
switch (parseArgs(args, 0)) {
|
||||
|
||||
case "get":
|
||||
event.getTextChannel().sendMessage("Retreiving list, please wait...").queue(t -> {
|
||||
event.getTextChannel().sendMessage("Retrieving list, please wait...").queue(t -> {
|
||||
|
||||
|
||||
try {
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
package netneutrality.db;
|
||||
|
||||
/*
|
||||
* Copyright (c) anthorob
|
||||
*
|
||||
* https://xtremcommunity.com/
|
||||
* https://discord.gg/CdFcyQ
|
||||
*/
|
||||
|
||||
import netneutrality.MusicBot;
|
||||
import netneutrality.ThreadManager;
|
||||
import netneutrality.db.models.MTableModel;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class AsyncMySqlAction {
|
||||
|
||||
private String sqlString;
|
||||
private Object[] params;
|
||||
private MysqlDatabase.CommandType type;
|
||||
private MysqlDatabase db;
|
||||
|
||||
public AsyncMySqlAction(MysqlDatabase db, String sql, Object... params) {
|
||||
this.db = db;
|
||||
this.sqlString = sql;
|
||||
this.params = params;
|
||||
|
||||
type = MysqlDatabase.CommandType.stringToType(sqlString.toUpperCase().split(" ")[0]);
|
||||
}
|
||||
|
||||
|
||||
public void async(Consumer<MTableModel> success) {
|
||||
switch (type) {
|
||||
case INSERT:
|
||||
ThreadManager.executor.submit(() -> {
|
||||
db.insert(this.sqlString, this.params);
|
||||
});
|
||||
break;
|
||||
case UPDATE:
|
||||
ThreadManager.executor.submit(() -> {
|
||||
db.update(this.sqlString, this.params);
|
||||
});
|
||||
break;
|
||||
|
||||
case DELETE:
|
||||
ThreadManager.executor.submit(() -> {
|
||||
db.delete(this.sqlString, this.params);
|
||||
});
|
||||
break;
|
||||
|
||||
case SELECT:
|
||||
ThreadManager.executor.submit(() -> {
|
||||
ResultSet result = db.prepareAndExecute(this.sqlString, this.params);
|
||||
MTableModel table = MysqlDatabase.convertToTableModel(result);
|
||||
|
||||
success.accept(table);
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void async() {
|
||||
async(o -> {
|
||||
});
|
||||
}
|
||||
|
||||
public MTableModel blocking() {
|
||||
switch (type) {
|
||||
case INSERT:
|
||||
db.insert(this.sqlString, this.params);
|
||||
|
||||
case UPDATE:
|
||||
db.update(this.sqlString, this.params);
|
||||
|
||||
case DELETE:
|
||||
db.delete(this.sqlString, this.params);
|
||||
|
||||
case SELECT:
|
||||
ResultSet result = db.prepareAndExecute(this.sqlString, this.params);
|
||||
|
||||
return MysqlDatabase.convertToTableModel(result);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,7 @@ import org.reflections.Reflections;
|
||||
|
||||
/**
|
||||
* When creating a controller, all database actions must be executed in another thread using an executor. One is provided in the {@link ThreadManager} class
|
||||
* A simple thread can't be used in this case because unpredictable errors might happen and some actions might not be executed.
|
||||
* A simple thread can't be used in this case because overlapping actions might happen and won't be executed.
|
||||
*/
|
||||
public class DBController {
|
||||
|
||||
@@ -23,7 +23,7 @@ public class DBController {
|
||||
private final static HashMap<String, AbstractController> controllers = new HashMap<>();
|
||||
|
||||
|
||||
private static MysqlDatabase database = new MysqlDatabase("discord");
|
||||
private static MysqlDatabase database = new MysqlDatabase("netneutrality");
|
||||
|
||||
/**
|
||||
* @param controller The name of the controller as defined in the {@link AbstractController#getControllerName()}'s method
|
||||
|
||||
@@ -9,8 +9,10 @@ import java.sql.Statement;
|
||||
import java.sql.Timestamp;
|
||||
import java.sql.Types;
|
||||
import java.util.Calendar;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import netneutrality.MusicBot;
|
||||
import netneutrality.ThreadManager;
|
||||
import netneutrality.db.models.MRowModel;
|
||||
import netneutrality.db.models.MTableModel;
|
||||
import netneutrality.exceptions.UnimplementedParameterException;
|
||||
@@ -18,10 +20,24 @@ import netneutrality.handler.LogHandler;
|
||||
|
||||
public class MysqlDatabase {
|
||||
|
||||
protected enum CommandType {
|
||||
SELECT("SELECT"), INSERT("INSERT"), UPDATE("UPDATE"), DELETE("DELETE");
|
||||
|
||||
private String type;
|
||||
|
||||
CommandType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public static CommandType stringToType(String str) {
|
||||
return CommandType.valueOf(str);
|
||||
}
|
||||
}
|
||||
|
||||
private Connection connection;
|
||||
private String dbName;
|
||||
|
||||
MysqlDatabase(String dbName) {
|
||||
protected MysqlDatabase(String dbName) {
|
||||
this.dbName = dbName;
|
||||
try {
|
||||
MusicBot.LOGGER.info("Connecting to database...");
|
||||
@@ -100,7 +116,6 @@ public class MysqlDatabase {
|
||||
}
|
||||
|
||||
private int executeUpdate(String sql, Object[] params) {
|
||||
MusicBot.LOGGER.debug("Query: " + sql);
|
||||
|
||||
try {
|
||||
PreparedStatement query = connection.prepareStatement(sql);
|
||||
@@ -119,7 +134,7 @@ public class MysqlDatabase {
|
||||
*
|
||||
* @param sql The SQL query to execute
|
||||
* @param params The parameters to include in the query
|
||||
* @return a ResultSet object, which can be converted to an model using {@link MysqlDatabase#convertToTableModel(ResultSet)}
|
||||
* @return a ResultSet object, which can be converted to a model using {@link MysqlDatabase#convertToTableModel(ResultSet)}
|
||||
*/
|
||||
public ResultSet prepareAndExecute(String sql, Object... params) {
|
||||
MusicBot.LOGGER.debug("Query: " + sql);
|
||||
@@ -129,12 +144,25 @@ public class MysqlDatabase {
|
||||
resolveParameters(query, params);
|
||||
return query.executeQuery();
|
||||
} catch (SQLException e) {
|
||||
MusicBot.LOGGER.error(e.toString());
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a SELECT statement with the specified parameters.
|
||||
* In the SQL query, where there is a parameter to be included, you need to replace it with ?
|
||||
*
|
||||
* @param sql The SQL query to execute
|
||||
* @param params The parameters to include in the query
|
||||
* @return a ResultSet object, which can be converted to a model using {@link MysqlDatabase#convertToTableModel(ResultSet)}
|
||||
*/
|
||||
public AsyncMySqlAction prepareAndExecuteAsync(String sql, Object... params) {
|
||||
return new AsyncMySqlAction(this, sql, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert parameters (specified with a ?) in the SQL statement
|
||||
* Taken from https://github.com/Kaaz/DiscordBot/blob/master/src/main/java/emily/db/MySQLAdapter.java#resolveParameters
|
||||
@@ -182,7 +210,7 @@ public class MysqlDatabase {
|
||||
* @throws SQLException
|
||||
*/
|
||||
public void close() throws SQLException {
|
||||
System.out.println("Closing database...");
|
||||
MusicBot.LOGGER.info("Closing database...");
|
||||
connection.close();
|
||||
}
|
||||
|
||||
|
||||
@@ -3,8 +3,10 @@ package netneutrality.db.controllers;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import netneutrality.MusicBot;
|
||||
import netneutrality.ThreadManager;
|
||||
import netneutrality.db.AbstractController;
|
||||
import netneutrality.db.DBController;
|
||||
@@ -28,26 +30,25 @@ public class DBBlacklist extends AbstractController {
|
||||
}
|
||||
|
||||
public void add(MBlacklist obj, Consumer<Boolean> success) {
|
||||
ThreadManager.executor.submit(() -> {
|
||||
if (!isAlreadyBlacklisted(obj.getWord(), obj.getServerId())) {
|
||||
database.insert("INSERT INTO blacklist VALUES(?,?,?,?)", obj.getWord(), obj.getServerId(), obj.isEnabled(), obj.getCreatorId());
|
||||
isAlreadyBlacklisted(obj.getWord(), obj.getServerId(), blacklisted -> {
|
||||
if (blacklisted == 0) {
|
||||
database.prepareAndExecuteAsync("INSERT INTO blacklist VALUES(?,?,?,?)", obj.getWord(), obj.getServerId(), obj.isEnabled(), obj.getCreatorId()).async();
|
||||
success.accept(true);
|
||||
} else {
|
||||
success.accept(false);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
public void delete(String word, String serverId, Consumer<Boolean> success) {
|
||||
ThreadManager.executor.submit(() -> {
|
||||
if (isAlreadyBlacklisted(word, serverId)) {
|
||||
System.out.println("true");
|
||||
database.delete("DELETE FROM blacklist WHERE word = ? AND serverId = ?", word, serverId);
|
||||
isAlreadyBlacklisted(word, serverId, blacklisted -> {
|
||||
if (blacklisted >= 1) {
|
||||
database.prepareAndExecuteAsync("DELETE FROM blacklist WHERE word = ? AND serverId = ?", word, serverId).async();
|
||||
MusicBot.LOGGER.info("blacklisted");
|
||||
success.accept(true);
|
||||
} else {
|
||||
MusicBot.LOGGER.info("not blacklisted");
|
||||
success.accept(false);
|
||||
}
|
||||
});
|
||||
@@ -56,26 +57,32 @@ public class DBBlacklist extends AbstractController {
|
||||
|
||||
public void enable(String word, String serverId, Consumer<Boolean> success) {
|
||||
|
||||
|
||||
ThreadManager.executor.submit(() -> {
|
||||
if (isAlreadyBlacklisted(word, serverId)) {
|
||||
database.update("UPDATE blacklist SET isEnabled = 1 WHERE word = ? AND serverId = ?", word, serverId);
|
||||
isAlreadyBlacklisted(word, serverId, blacklisted -> {
|
||||
if (blacklisted >= 1) {
|
||||
database.prepareAndExecuteAsync("UPDATE blacklist SET isEnabled = 1 WHERE word = ? AND serverId = ?", word, serverId).async();
|
||||
MusicBot.LOGGER.info("enabled");
|
||||
success.accept(true);
|
||||
} else {
|
||||
MusicBot.LOGGER.info("error enabling");
|
||||
success.accept(false);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public void disable(String word, String serverId, Consumer<Boolean> success) {
|
||||
ThreadManager.executor.submit(() -> {
|
||||
if (isAlreadyBlacklisted(word, serverId)) {
|
||||
database.update("UPDATE blacklist SET isEnabled = 0 WHERE word = ? AND serverId = ?", word, serverId);
|
||||
|
||||
isAlreadyBlacklisted(word, serverId, blacklisted -> {
|
||||
if (blacklisted >= 1) {
|
||||
database.prepareAndExecuteAsync("UPDATE blacklist SET isEnabled = 0 WHERE word = ? AND serverId = ?", word, serverId).async();
|
||||
MusicBot.LOGGER.info("disabled");
|
||||
success.accept(true);
|
||||
} else {
|
||||
MusicBot.LOGGER.info("error disabled");
|
||||
success.accept(false);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public void getBlacklistForWord(String word, String serverId, Consumer<MBlacklist> success) {
|
||||
@@ -84,7 +91,7 @@ public class DBBlacklist extends AbstractController {
|
||||
|
||||
if (isAlreadyBlacklisted(word, serverId)) {
|
||||
ResultSet rs = database.prepareAndExecute("SELECT * FROM blacklist WHERE word = ? AND serverId = ?", word, serverId);
|
||||
MTableModel table = database.convertToTableModel(rs);
|
||||
MTableModel table = MysqlDatabase.convertToTableModel(rs);
|
||||
|
||||
if (table.getNbRows() > 0) {
|
||||
blacklisted = new MBlacklist((String) table.getRow(0).get(0), (Boolean) table.getRow(0).get(2), (String) table.getRow(0).get(3),
|
||||
@@ -98,42 +105,44 @@ public class DBBlacklist extends AbstractController {
|
||||
}
|
||||
|
||||
public void getBlacklistFromServer(String serverId, Consumer<ArrayList<MBlacklist>> success) {
|
||||
ThreadManager.executor.submit(() -> {
|
||||
ArrayList<MBlacklist> output = new ArrayList<>();
|
||||
|
||||
try {
|
||||
ResultSet rs = database.prepareAndExecute("SELECT * FROM blacklist WHERE serverId = ? AND isEnabled = 1", serverId);
|
||||
MTableModel model = MysqlDatabase.convertToTableModel(rs);
|
||||
database.prepareAndExecuteAsync("SELECT * FROM blacklist WHERE serverId = ? AND isEnabled = 1", serverId).async(model -> {
|
||||
ArrayList<MBlacklist> output = new ArrayList<>();
|
||||
|
||||
if (model.getNbRows() != 0) {
|
||||
for (int row = 0; row < model.getNbRows(); row++) {
|
||||
output.add(new MBlacklist((String) model.getRow(row).get(0), (Boolean) model.getRow(row).get(2), (String) model.getRow(row).get(3),
|
||||
(String) model.getRow(row).get(1)));
|
||||
}
|
||||
} else {
|
||||
throw new RuntimeException("Blacklist is empty");
|
||||
}
|
||||
|
||||
} catch (NullPointerException | IndexOutOfBoundsException ignored) { }
|
||||
|
||||
success.accept(output);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public boolean isAlreadyBlacklisted(String word, String serverId) {
|
||||
ResultSet rs = database.prepareAndExecute("SELECT COUNT(*) FROM blacklist WHERE word = ? AND serverId = ?", word, serverId);
|
||||
@Deprecated
|
||||
private boolean isAlreadyBlacklisted(String word, String serverId) {
|
||||
AtomicBoolean result = new AtomicBoolean();
|
||||
|
||||
try {
|
||||
if (rs.next()) {
|
||||
return rs.getInt(1) != 0;
|
||||
database.prepareAndExecuteAsync("SELECT COUNT(*) FROM blacklist WHERE word = ? AND serverId = ?", word, serverId).async(table -> {
|
||||
if (!table.isEmpty()) {
|
||||
result.set((int) table.getRowModel(0).getItem(0) != 0);
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
//TODO: error log
|
||||
e.printStackTrace();
|
||||
});
|
||||
|
||||
return result.get();
|
||||
}
|
||||
|
||||
return false;
|
||||
private void isAlreadyBlacklisted(String word, String serverId, Consumer<Integer> result) {
|
||||
|
||||
database.prepareAndExecuteAsync("SELECT COUNT(*) FROM blacklist WHERE word = ? AND serverId = ?", word, serverId).async(table -> {
|
||||
if (!table.isEmpty()) {
|
||||
int count = Integer.parseInt(table.getRowModel(0).getItem(0).toString());
|
||||
|
||||
result.accept(count);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -28,18 +28,12 @@ public class DBMessage extends AbstractController {
|
||||
}
|
||||
|
||||
public void log(String servername, String channelname, String username, String datesent, String messageId, String message) {
|
||||
|
||||
ThreadManager.executor.submit(() -> {
|
||||
database.insert("INSERT INTO log_message VALUES(?,?,?,?,?,?,?)", servername, channelname, username, datesent, messageId, message, null);
|
||||
});
|
||||
database.prepareAndExecuteAsync("INSERT INTO log_message VALUES(?,?,?,?,?,?,?)", servername, channelname, username, datesent, messageId, message, null).async();
|
||||
|
||||
}
|
||||
|
||||
public void logEdit(String messageId, String newMessage) {
|
||||
|
||||
ThreadManager.executor.submit(() -> {
|
||||
database.update("UPDATE log_message SET editedMessage = ? WHERE messageId = ?", newMessage, messageId);
|
||||
});
|
||||
database.prepareAndExecuteAsync("UPDATE log_message SET editedMessage = ? WHERE messageId = ?", newMessage, messageId).async();
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
package netneutrality.db.controllers;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import netneutrality.ThreadManager;
|
||||
import netneutrality.db.AbstractController;
|
||||
import netneutrality.db.MysqlDatabase;
|
||||
import netneutrality.db.models.MTableModel;
|
||||
@@ -13,13 +11,9 @@ public class DBSettings extends AbstractController {
|
||||
|
||||
public void getSettingsByKey(String key, Consumer<Object> success) {
|
||||
|
||||
ThreadManager.executor.submit(() -> {
|
||||
database.prepareAndExecuteAsync("SELECT value FROM settings WHERE skey = ?", key).async(table -> {
|
||||
Object value = null;
|
||||
|
||||
ResultSet rs;
|
||||
rs = database.prepareAndExecute("SELECT value FROM settings WHERE skey = ?", key);
|
||||
MTableModel table = MysqlDatabase.convertToTableModel(rs);
|
||||
|
||||
if (table.getNbRows() == 1) {
|
||||
value = table.getRowModel(0).getItem(0);
|
||||
}
|
||||
@@ -28,11 +22,10 @@ public class DBSettings extends AbstractController {
|
||||
});
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public String getSettingsByKey(String key) {
|
||||
|
||||
ResultSet rs;
|
||||
rs = database.prepareAndExecute("SELECT value FROM settings WHERE skey = ?", key);
|
||||
MTableModel table = MysqlDatabase.convertToTableModel(rs);
|
||||
MTableModel table = database.prepareAndExecuteAsync("SELECT value FROM settings WHERE skey = ?", key).blocking();
|
||||
|
||||
if (table.getNbRows() == 1) {
|
||||
return table.getRow(0).get(0).toString();
|
||||
|
||||
Reference in new issue
Block a user