diff --git a/TabooLib.iml b/TabooLib.iml index e1d93e7..abc9fff 100644 --- a/TabooLib.iml +++ b/TabooLib.iml @@ -8,23 +8,41 @@ - + - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - diff --git a/pom.xml b/pom.xml index 287e3fc..14b6dc3 100644 --- a/pom.xml +++ b/pom.xml @@ -6,10 +6,13 @@ me.skymc TabooLib - 4.01 + 4.02 UTF-8 + 1.5 + 1.5 + off clean install package @@ -30,23 +33,9 @@ maven-compiler-plugin 3.7.0 - eclipse - 1.8 - 1.8 - UTF-8 + 8 + 8 - - - org.codehaus.plexus - plexus-compiler-eclipse - 2.8.4 - - - org.eclipse.jdt - ecj - 3.13.102 - - org.apache.maven.plugins @@ -79,6 +68,21 @@ + + org.apache.cassandra + cassandra-all + 0.8.1 + + + org.slf4j + slf4j-log4j12 + + + log4j + log4j + + + com.zaxxer HikariCP diff --git a/src/main/java/com/ilummc/tlib/config/TLibConfig.java b/src/main/java/com/ilummc/tlib/config/TLibConfig.java index 5aeb6c0..9ecb9de 100644 --- a/src/main/java/com/ilummc/tlib/config/TLibConfig.java +++ b/src/main/java/com/ilummc/tlib/config/TLibConfig.java @@ -9,7 +9,7 @@ import java.util.Map; * @author sky * @since 2018-04-22 14:31:11 */ -@TConfig(name = "tlib.yml", listenChanges = true) +@TConfig(name = "tlib.yml") public class TLibConfig { private String dataSourceClassName; diff --git a/src/main/java/me/skymc/taboolib/Main.java b/src/main/java/me/skymc/taboolib/Main.java index a866bb4..5eefd71 100644 --- a/src/main/java/me/skymc/taboolib/Main.java +++ b/src/main/java/me/skymc/taboolib/Main.java @@ -23,6 +23,7 @@ import me.skymc.taboolib.javashell.JavaShell; import me.skymc.taboolib.listener.*; import me.skymc.taboolib.message.ChatCatcher; import me.skymc.taboolib.message.MsgUtils; +import me.skymc.taboolib.mysql.hikari.HikariHandler; import me.skymc.taboolib.mysql.protect.MySQLConnection; import me.skymc.taboolib.nms.item.DabItemUtils; import me.skymc.taboolib.other.NumberUtils; @@ -191,7 +192,7 @@ public class Main extends JavaPlugin implements Listener { } } else { // 提示 - TLocale.Logger.error("NOTIFY.ERROR-CONNECTION-FALL"); + TLocale.Logger.error("NOTIFY.ERROR-CONNECTION-FAIL"); // 关服 Bukkit.shutdown(); } @@ -281,7 +282,7 @@ public class Main extends JavaPlugin implements Listener { // 如果插件尚未启动完成 if (!started) { - TLocale.Logger.error("NOTIFY.FALL-DISABLE"); + TLocale.Logger.error("NOTIFY.FAIL-DISABLE"); return; } @@ -299,6 +300,8 @@ public class Main extends JavaPlugin implements Listener { SpecialItem.getInst().unloadItems(); // 注销 TLM 接口 TabooLibraryModule.getInst().unloadModules(); + // 注销连接池 + HikariHandler.closeDataSourceForce(); // 结束数据库储存方法 if (getStorageType() == StorageType.SQL) { diff --git a/src/main/java/me/skymc/taboolib/TabooLib.java b/src/main/java/me/skymc/taboolib/TabooLib.java index 21ced84..beceeff 100644 --- a/src/main/java/me/skymc/taboolib/TabooLib.java +++ b/src/main/java/me/skymc/taboolib/TabooLib.java @@ -8,8 +8,24 @@ import org.bukkit.plugin.Plugin; import java.util.Arrays; import java.util.UUID; +/** + * @author sky + */ public class TabooLib { + private static boolean spigot = false; + + static { + try { + spigot = Bukkit.getConsoleSender() != null; + } catch (Exception ignored) { + } + } + + public static boolean isSpigot() { + return spigot; + } + public static boolean isDebug() { return Main.getInst().getConfig().getBoolean("DEBUG"); } diff --git a/src/main/java/me/skymc/taboolib/commands/plugin/TabooLibPluginMainCommand.java b/src/main/java/me/skymc/taboolib/commands/plugin/TabooLibPluginMainCommand.java index 74bf64a..d3d12b4 100644 --- a/src/main/java/me/skymc/taboolib/commands/plugin/TabooLibPluginMainCommand.java +++ b/src/main/java/me/skymc/taboolib/commands/plugin/TabooLibPluginMainCommand.java @@ -82,7 +82,7 @@ public class TabooLibPluginMainCommand extends BaseMainCommand { break; } default: { - TLocale.sendTo(sender, "COMMANDS.TPLUGIN.LOAD.LOAD-FALL", name); + TLocale.sendTo(sender, "COMMANDS.TPLUGIN.LOAD.LOAD-FAIL", name); } } } @@ -123,7 +123,7 @@ public class TabooLibPluginMainCommand extends BaseMainCommand { break; } default: { - TLocale.sendTo(sender, "COMMANDS.TPLUGIN.UNLOAD.UNLOAD-FALL", name); + TLocale.sendTo(sender, "COMMANDS.TPLUGIN.UNLOAD.UNLOAD-FAIL", name); } } } @@ -190,16 +190,20 @@ public class TabooLibPluginMainCommand extends BaseMainCommand { if (plugin == null) { TLocale.sendTo(sender, "COMMANDS.TPLUGIN.INFO.INVALID-PLUGIN", name); } else { - TLocale.sendTo(sender, "COMMANDS.TPLUGIN.INFO.INFO-PLUGIN", - plugin.getName(), - String.valueOf(plugin.getDescription().getDescription()), - String.valueOf(plugin.getDescription().getAuthors()), - String.valueOf(plugin.getDescription().getDepend()), - String.valueOf(plugin.getDescription().getSoftDepend()), - String.valueOf(plugin.getDescription().getMain()), - String.valueOf(plugin.getDescription().getVersion()), - String.valueOf(plugin.getDescription().getWebsite()), - String.valueOf(plugin.getDescription().getCommands().keySet())); + try { + TLocale.sendTo(sender, "COMMANDS.TPLUGIN.INFO.INFO-PLUGIN", + plugin.getName(), + String.valueOf(plugin.getDescription().getDescription()), + String.valueOf(plugin.getDescription().getAuthors()), + String.valueOf(plugin.getDescription().getDepend()), + String.valueOf(plugin.getDescription().getSoftDepend()), + String.valueOf(plugin.getDescription().getMain()), + String.valueOf(plugin.getDescription().getVersion()), + String.valueOf(plugin.getDescription().getWebsite()), + String.valueOf(plugin.getDescription().getCommands().keySet())); + } catch (Exception ignored) { + TLocale.sendTo(sender, "COMMANDS.TPLUGIN.INFO.INVALID-PLUGIN", name); + } } } }); diff --git a/src/main/java/me/skymc/taboolib/fileutils/ConfigUtils.java b/src/main/java/me/skymc/taboolib/fileutils/ConfigUtils.java index 4e886e0..e989d52 100644 --- a/src/main/java/me/skymc/taboolib/fileutils/ConfigUtils.java +++ b/src/main/java/me/skymc/taboolib/fileutils/ConfigUtils.java @@ -35,7 +35,7 @@ public class ConfigUtils { @SuppressWarnings("unchecked") public static Map yamlToMap(String yamlText) { - return YAML.loadAs(yamlText, LinkedHashMap.class); + return (Map) YAML.load(yamlText); } public static MemoryConfiguration objToConf(Object object) { @@ -199,7 +199,7 @@ public class ConfigUtils { configuration.loadFromString(yaml); return configuration; } catch (Exception e) { - TLocale.Logger.error("FILE-UTILS.FALL-LOAD-CONFIGURATION", plugin.getName(), file.getName()); + TLocale.Logger.error("FILE-UTILS.FAIL-LOAD-CONFIGURATION", plugin.getName(), file.getName()); } return configuration; } diff --git a/src/main/java/me/skymc/taboolib/inventory/ItemUtils.java b/src/main/java/me/skymc/taboolib/inventory/ItemUtils.java index 1ccf48c..54008d0 100644 --- a/src/main/java/me/skymc/taboolib/inventory/ItemUtils.java +++ b/src/main/java/me/skymc/taboolib/inventory/ItemUtils.java @@ -100,7 +100,7 @@ public class ItemUtils { reloadItemCache(); itemdir = YamlConfiguration.loadConfiguration(new File(Main.getInst().getConfig().getString("DATAURL.ITEMDIR"))); } catch (Exception e) { - TLocale.Logger.error("ITEM-UTILS.FALL-LOAD-ITEMS", e.toString()); + TLocale.Logger.error("ITEM-UTILS.FAIL-LOAD-ITEMS", e.toString()); } } @@ -108,7 +108,7 @@ public class ItemUtils { FileConfiguration conf = ConfigUtils.load(Main.getInst(), file); for (String name : conf.getConfigurationSection("").getKeys(false)) { if (isExists(name)) { - TLocale.Logger.error("ITEM-UTILS.FALL-LOAD-ITEMS", name); + TLocale.Logger.error("ITEM-UTILS.FAIL-LOAD-ITEMS", name); } else if (finalFile) { itemCachesFinal.put(name, loadItem(conf, name)); } else { @@ -424,7 +424,7 @@ public class ItemUtils { if (enchant != null) { meta.addEnchant(enchant, section.getInt("enchants." + preEnchant), true); } else { - TLocale.Logger.error("ITEM-UTILS.FALL-LOAD-ENCHANTS", preEnchant); + TLocale.Logger.error("ITEM-UTILS.FAIL-LOAD-ENCHANTS", preEnchant); } } } @@ -435,7 +435,7 @@ public class ItemUtils { if (flag != null) { meta.addItemFlags(flag); } else { - TLocale.Logger.error("ITEM-UTILS.FALL-LOAD-FLAG", preFlag); + TLocale.Logger.error("ITEM-UTILS.FAIL-LOAD-FLAG", preFlag); } } } @@ -454,7 +454,7 @@ public class ItemUtils { NumberUtils.getInteger(section.getString("potions." + prePotionName).split("-")[0]), NumberUtils.getInteger(section.getString("potions." + prePotionName).split("-")[1]) - 1), true); } else { - TLocale.Logger.error("ITEM-UTILS.FALL-LOAD-POTION", prePotionName); + TLocale.Logger.error("ITEM-UTILS.FAIL-LOAD-POTION", prePotionName); } } } @@ -505,7 +505,7 @@ public class ItemUtils { } catch (Exception ignored) { } } else { - TLocale.Logger.error("ITEM-UTILS.FALL-LOAD-POTION", name); + TLocale.Logger.error("ITEM-UTILS.FAIL-LOAD-POTION", name); } } } @@ -544,7 +544,7 @@ public class ItemUtils { } catch (NumberFormatException ignored) { } } else { - TLocale.Logger.error("ITEM-UTILS.FALL-LOAD-POTION", name); + TLocale.Logger.error("ITEM-UTILS.FAIL-LOAD-POTION", name); } return nbt; } diff --git a/src/main/java/me/skymc/taboolib/listener/ListenerPluginDisable.java b/src/main/java/me/skymc/taboolib/listener/ListenerPluginDisable.java index 37732f9..5c9d258 100644 --- a/src/main/java/me/skymc/taboolib/listener/ListenerPluginDisable.java +++ b/src/main/java/me/skymc/taboolib/listener/ListenerPluginDisable.java @@ -1,5 +1,6 @@ package me.skymc.taboolib.listener; +import com.ilummc.tlib.resources.TLocale; import me.skymc.taboolib.Main; import me.skymc.taboolib.message.MsgUtils; import me.skymc.taboolib.mysql.MysqlUtils; @@ -41,7 +42,7 @@ public class ListenerPluginDisable implements Listener { i++; } if (i > 0) { - MsgUtils.send("已停止插件 &f" + e.getPlugin().getName() + "&7 的 &f" + i + "&7 条数据库连接"); + TLocale.Logger.info("MYSQL-CONNECTION.SUCCESS-CONNECTION-CANCEL", e.getPlugin().getName(), String.valueOf(i)); } } }; @@ -50,7 +51,7 @@ public class ListenerPluginDisable implements Listener { try { runnable.runTaskLater(Main.getInst(), 40); } catch (Exception err) { - MsgUtils.warn("异步任务失败, 执行方式改为同步执行"); + TLocale.Logger.error("MYSQL-CONNECTION.FAIL-EXECUTE-TASK"); runnable.run(); } } diff --git a/src/main/java/me/skymc/taboolib/mysql/MysqlUtils.java b/src/main/java/me/skymc/taboolib/mysql/MysqlUtils.java index e1e73a6..e7aaf4a 100644 --- a/src/main/java/me/skymc/taboolib/mysql/MysqlUtils.java +++ b/src/main/java/me/skymc/taboolib/mysql/MysqlUtils.java @@ -6,12 +6,14 @@ import me.skymc.taboolib.mysql.protect.MySQLConnection; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.plugin.Plugin; +import java.sql.Connection; import java.util.concurrent.CopyOnWriteArrayList; public class MysqlUtils { public final static CopyOnWriteArrayList CONNECTIONS = new CopyOnWriteArrayList<>(); + @Deprecated public static MysqlConnection getMysqlConnectionFromConfiguration(FileConfiguration conf, String key) { return new MysqlConnection(conf.getString(key + ".host"), conf.getString(key + ".port"), conf.getString(key + ".database"), conf.getString(key + ".user"), conf.getString(key + ".pass")); } @@ -21,17 +23,28 @@ public class MysqlUtils { } public static MySQLConnection getMySQLConnectionFromConfiguration(FileConfiguration conf, String key, int recheck, Plugin plugin) { - MySQLConnection conn = new MySQLConnection( - conf.getString(key + ".url"), - conf.getString(key + ".user"), - conf.getString(key + ".port"), - conf.getString(key + ".password"), - conf.getString(key + ".database"), recheck, plugin); - - if (conn.isConnection()) { - CONNECTIONS.add(conn); - TLocale.Logger.info("MYSQL-CONNECTION.SUCCESS-REGISTERED", plugin.getName()); + MySQLConnection connection = getMySQLConnectionExists(conf, key); + if (connection == null) { + connection = new MySQLConnection(conf.getString(key + ".url"), conf.getString(key + ".user"), conf.getString(key + ".port"), conf.getString(key + ".password"), conf.getString(key + ".database"), recheck, plugin); + if (connection.isConnection()) { + CONNECTIONS.add(connection); + TLocale.Logger.info("MYSQL-CONNECTION.SUCCESS-REGISTERED", plugin.getName()); + } + } else { + TLocale.Logger.info("MYSQL-CONNECTION.SUCCESS-REGISTERED-EXISTS", plugin.getName(), connection.getPlugin().getName()); } - return conn; + return connection; + } + + private static MySQLConnection getMySQLConnectionExists(FileConfiguration conf, String key) { + return CONNECTIONS.stream().filter(connection -> isSameConnection(conf, key, connection)).findFirst().orElse(null); + } + + private static boolean isSameConnection(FileConfiguration conf, String key, MySQLConnection connection) { + return conversionHost(connection.getUrl()).equals(conversionHost(conf.getString(key + ".url", "localhost"))) && connection.getDatabase().equals(conf.getString(key + ".database")); + } + + private static String conversionHost(String host) { + return "localhost".equals(host) ? "127.0.0.1" : host; } } diff --git a/src/main/java/me/skymc/taboolib/mysql/builder/SQLColumn.java b/src/main/java/me/skymc/taboolib/mysql/builder/SQLColumn.java new file mode 100644 index 0000000..cf5da50 --- /dev/null +++ b/src/main/java/me/skymc/taboolib/mysql/builder/SQLColumn.java @@ -0,0 +1,144 @@ +package me.skymc.taboolib.mysql.builder; + +import com.ilummc.tlib.util.Strings; + +import java.util.Arrays; + +/** + * @Author sky + * @Since 2018-05-14 19:09 + */ +public class SQLColumn { + + public static void main(String[] args) { + SQLColumn column2 = new SQLColumn(SQLColumnType.INT, "player_title", "无"); + System.out.println(column2.convertToCommand()); + } + + /** + * 类型 + */ + private SQLColumnType columnType; + private int m; + private int d; + + /** + * 名称 + */ + private String columnName; + + /** + * 默认值 + */ + private Object defaultValue; + + /** + * 属性值 + */ + private SQLColumnOption[] columnOptions; + + /** + * 文本类型常用构造器 + * new SQLColumn(SQLColumnType.TEXT, "username"); + */ + public SQLColumn(SQLColumnType columnType, String columnName) { + this(columnType, 0, 0, columnName, null); + } + + /** + * 主键类型常用构造器 + * new SQLColumn(SQLColumnType.TEXT, "username", SQLColumnOption.PRIMARY_KEY, SQLColumnOption.AUTO_INCREMENT); + */ + public SQLColumn(SQLColumnType columnType, String columnName, SQLColumnOption... columnOptions) { + this(columnType, 0, 0, columnName, null, columnOptions); + } + + /** + * 数据类型常用构造器 + * new SQLColumn(SQLColumnType.TEXT, "player_group", "PLAYER"); + */ + public SQLColumn(SQLColumnType columnType, String columnName, Object defaultValue) { + this(columnType, 0, 0, columnName, defaultValue); + } + + /** + * 完整构造器 + * + * @param columnType 类型 + * @param m m值 + * @param d d值 + * @param columnName 名称 + * @param defaultValue 默认值 + * @param columnOptions 属性值 + */ + public SQLColumn(SQLColumnType columnType, int m, int d, String columnName, Object defaultValue, SQLColumnOption... columnOptions) { + this.columnType = columnType; + this.m = m; + this.d = d; + this.columnName = columnName; + this.defaultValue = defaultValue; + this.columnOptions = columnOptions; + } + + public SQLColumn m(int m) { + this.m = m; + return this; + } + + public SQLColumn d(int d) { + this.d = d; + return this; + } + + public SQLColumn defaultValue(Object defaultValue) { + this.defaultValue = defaultValue; + return this; + } + + public SQLColumn columnOptions(SQLColumnOption... columnOptions) { + this.columnOptions = columnOptions; + return this; + } + + public String convertToCommand() { + if (this.m == 0 && this.d == 0) { + return Strings.replaceWithOrder("`{0}` {1}{2}", columnName, columnType.name().toLowerCase(), convertToOptions()); + } else if (this.d == 0) { + return Strings.replaceWithOrder("`{0}` {1}({2}){3}", columnName, columnType.name().toLowerCase(), m, convertToOptions()); + } else { + return Strings.replaceWithOrder("`{0}` {1}({2},{3}){4}", columnName, columnType.name().toLowerCase(), m, d, convertToOptions()); + } + } + + private String convertToOptions() { + StringBuilder stringBuilder = new StringBuilder(); + for (SQLColumnOption options : columnOptions) { + switch (options) { + case NOTNULL: + stringBuilder.append(" not null"); + break; + case PRIMARY_KEY: + stringBuilder.append(" primary key"); + break; + case AUTO_INCREMENT: + stringBuilder.append(" auto_increment"); + break; + case UNIQUE_KEY: + stringBuilder.append(" unique key"); + break; + default: + } + } + if (defaultValue instanceof String) { + stringBuilder.append(" default '").append(defaultValue).append("'"); + } else { + stringBuilder.append(" default ").append(defaultValue); + } + return stringBuilder.toString(); + } + + @Override + public String toString() { + return "columnType=" + "SQLColumn{" + columnType + ", m=" + m + ", d=" + d + ", columnName='" + columnName + '\'' + ", defaultValue=" + defaultValue + ", columnOptions=" + Arrays.toString(columnOptions) + '}'; + } +} diff --git a/src/main/java/me/skymc/taboolib/mysql/builder/SQLColumnOption.java b/src/main/java/me/skymc/taboolib/mysql/builder/SQLColumnOption.java new file mode 100644 index 0000000..8e9dee4 --- /dev/null +++ b/src/main/java/me/skymc/taboolib/mysql/builder/SQLColumnOption.java @@ -0,0 +1,29 @@ +package me.skymc.taboolib.mysql.builder; + +/** + * @Author sky + * @Since 2018-05-14 21:43 + */ +public enum SQLColumnOption { + + /** + * 不能为空 + */ + NOTNULL, + + /** + * 唯一 + */ + UNIQUE_KEY, + + /** + * 主键 + */ + PRIMARY_KEY, + + /** + * 递增 + */ + AUTO_INCREMENT + +} diff --git a/src/main/java/me/skymc/taboolib/mysql/builder/SQLColumnType.java b/src/main/java/me/skymc/taboolib/mysql/builder/SQLColumnType.java new file mode 100644 index 0000000..a882ac8 --- /dev/null +++ b/src/main/java/me/skymc/taboolib/mysql/builder/SQLColumnType.java @@ -0,0 +1,122 @@ +package me.skymc.taboolib.mysql.builder; + +/** + * @Author sky + * @Since 2018-05-14 19:13 + */ +public enum SQLColumnType { + + /** + * 有符号值:-128 到127(- 27 到27 - 1) + * 无符号值:0到255(0 到28 - 1) 1个字节 + */ + TINYINT, + + /** + * 有符号值:-32768 到32767(- 215 到215 - 1) + * 无符号值:0到65535(0 到21 6 - 1) 2个字节 + */ + SMALLINT, + + /** + * 有符号值:-8388608 到8388607(- 22 3 到22 3 - 1 ) + * 无符号值:0到16777215(0 到22 4 - 1) 3个字节 + */ + MEDIUMINT, + + /** + * 有符号值:-2147683648 到2147683647(- 231 到231- 1) + * 无符号值:0到4294967295(0 到232 - 1) 4个字节 + */ + INT, + + /** + * 有符号值:-9223372036854775808 到9223373036854775807(- 263到263-1) + * 无符号值:0到18446744073709551615(0到264 – 1) 8个字节 + */ + BIGINT, + + /** + * 最小非零值:±1.175494351e - 38 + */ + FLOAT, + + /** + * 最小非零值:±2.2250738585072014e - 308 + */ + DOUBLE, + + /** + * 可变:其值的范围依赖于m 和d + */ + DECIMAL, + + /** + * 定长:磁盘空间比较浪费,但是效率高,确定数据长度都一样,就使用定长 + * 比如:电话号码,身份证号 + * 最长可取255 + */ + CHAR, + + /** + * 边长:比较节省空间,但是效率低,数据不能确定长度(不同数据长度有变化) + * 比如:地址 + * 最长可取65535 + */ + VARCHAR, + + /** + * 0~255字节值的长度+2字节 + */ + TINYTEXT, + + /** + * 0~65535字节值的长度+2字节 + */ + TEXT, + + /** + * 0~167772150字节值的长度+3字节 + */ + MEDIUMTEXT, + + /** + * 0~4294967295字节值的长度+4字节 + */ + LONGTEXT, + + /** + * 字节数为M,允许长度为0~M的定长二进制字符串 + */ + BINARY, + + /** + * 允许长度为0~M的变长二进制字符串,字节数为值的长度加1 + */ + VARBINARY, + + /** + * M位二进制数据,M最大值为64 + */ + BIT, + + /** + * 可变长二进制数据,最多255个字节 + */ + TINYBLOB, + + /** + * 可变长二进制数据,最多2的16次方-1个字节 + */ + BLOB, + + /** + * 可变长二进制数据,最多2的24次方-1个字节 + */ + MEDIUMBLOB, + + /** + * 可变长二进制数据,最多2的32次方-1个字节 + */ + LONGBLOB +} diff --git a/src/main/java/me/skymc/taboolib/mysql/builder/SQLHost.java b/src/main/java/me/skymc/taboolib/mysql/builder/SQLHost.java new file mode 100644 index 0000000..718fc5a --- /dev/null +++ b/src/main/java/me/skymc/taboolib/mysql/builder/SQLHost.java @@ -0,0 +1,89 @@ +package me.skymc.taboolib.mysql.builder; + +import com.ilummc.tlib.util.Ref; +import com.ilummc.tlib.util.Strings; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.plugin.Plugin; + +import java.util.Objects; + +/** + * @Author sky + * @Since 2018-05-14 19:01 + */ +public class SQLHost { + + private String host; + private String user; + private String port; + private String password; + private String database; + private Plugin plugin; + + public SQLHost(ConfigurationSection section, Plugin plugin) { + this(section.getString("host", "localhost"), section.getString("user", "root"), section.getString("port", "3306"), section.getString("password", ""), section.getString("database", "test"), plugin); + } + + public SQLHost(String host, String user, String port, String password, String database, Plugin plugin) { + this.host = host; + this.user = user; + this.port = port; + this.password = password; + this.database = database; + this.plugin = plugin; + } + + public String getHost() { + return host; + } + + public String getUser() { + return user; + } + + public String getPort() { + return port; + } + + public String getPassword() { + return password; + } + + public String getDatabase() { + return database; + } + + public Plugin getPlugin() { + return plugin; + } + + public String getConnectionUrl() { + return Strings.replaceWithOrder("jdbc:mysql://{0}:{1}/{2}?characterEncoding=utf-8&useSSL=false", this.host, this.port, this.database); + } + + public String getConnectionUrlSimple() { + return Strings.replaceWithOrder("jdbc:mysql://{0}:{1}/{2}", this.host, this.port, this.database); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof SQLHost)) { + return false; + } + SQLHost sqlHost = (SQLHost) o; + return Objects.equals(getHost(), sqlHost.getHost()) && Objects.equals(getPort(), sqlHost.getPort()) && Objects.equals(getUser(), sqlHost.getUser()) && Objects.equals(getPassword(), sqlHost.getPassword()) && Objects.equals(getDatabase(), sqlHost.getDatabase()); + } + + @Override + public int hashCode() { + return Objects.hash(getHost(), getUser(), getPort(), getPassword(), getDatabase()); + } + + @Override + public String toString() { + return "host='" + "SQLHost{" + host + '\'' + ", user='" + user + '\'' + ", port='" + port + '\'' + ", password='" + password + '\'' + ", database='" + database + '\'' + '}'; + } +} diff --git a/src/main/java/me/skymc/taboolib/mysql/builder/SQLTable.java b/src/main/java/me/skymc/taboolib/mysql/builder/SQLTable.java new file mode 100644 index 0000000..3c07bba --- /dev/null +++ b/src/main/java/me/skymc/taboolib/mysql/builder/SQLTable.java @@ -0,0 +1,24 @@ +package me.skymc.taboolib.mysql.builder; + +/** + * @Author sky + * @Since 2018-05-14 19:07 + */ +public class SQLTable { + + private final String tableName; + private final SQLColumn[] columns; + + public SQLTable(String tableName, SQLColumn... columns) { + this.tableName = tableName; + this.columns = columns; + } + + public String getTableName() { + return tableName; + } + + public SQLColumn[] getColumns() { + return columns; + } +} diff --git a/src/main/java/me/skymc/taboolib/mysql/hikari/HikariHandler.java b/src/main/java/me/skymc/taboolib/mysql/hikari/HikariHandler.java new file mode 100644 index 0000000..089d1ed --- /dev/null +++ b/src/main/java/me/skymc/taboolib/mysql/hikari/HikariHandler.java @@ -0,0 +1,106 @@ +package me.skymc.taboolib.mysql.hikari; + +import com.google.common.base.Preconditions; +import com.ilummc.tlib.resources.TLocale; +import com.zaxxer.hikari.HikariConfig; +import com.zaxxer.hikari.HikariDataSource; +import me.skymc.taboolib.Main; +import me.skymc.taboolib.mysql.builder.SQLHost; + +import java.util.concurrent.ConcurrentHashMap; + +/** + * @Author sky + * @Since 2018-05-16 21:59 + */ +public class HikariHandler { + + private static ConcurrentHashMap dataSource = new ConcurrentHashMap<>(); + + /** + * 根据数据库地址创建连接池,如果已经存在则返回引用 + * + * @param host 数据库地址 + * @return {@link HikariDataSource} + */ + public static HikariDataSource createDataSource(SQLHost host, HikariConfig hikariConfig) { + MapDataSource mapDataSource = dataSource.computeIfAbsent(host, x -> new MapDataSource(x, new HikariDataSource(hikariConfig == null ? createConfig(host) : hikariConfig))); + mapDataSource.getActivePlugin().getAndIncrement(); + if (mapDataSource.getActivePlugin().get() == 1) { + TLocale.Logger.info("MYSQL-HIKARI.CREATE-SUCCESS", host.getPlugin().getName(), host.getConnectionUrlSimple()); + } else { + TLocale.Logger.info("MYSQL-HIKARI.CREATE-EXISTS", host.getPlugin().getName(), mapDataSource.getSqlHost().getPlugin().getName()); + } + return mapDataSource.getHikariDataSource(); + } + + /** + * 强制注销所有已注册的连接池 + * 只能在 TabooLib 卸载后调用 + */ + public static void closeDataSourceForce() { + Preconditions.checkArgument(Main.isDisable(), "Cannot be invoked when the server is running."); + dataSource.values().forEach(x -> x.getHikariDataSource().close()); + } + + /** + * 注销连接池 + * 如果连接池有 1 个以上的插件正在使用则跳过,反之则注销并从缓存中移除 + * + * @param host 地址 + */ + public static void closeDataSource(SQLHost host) { + if (dataSource.containsKey(host)) { + MapDataSource mapDataSource = dataSource.get(host); + if (mapDataSource.getActivePlugin().getAndDecrement() <= 1) { + mapDataSource.getHikariDataSource().close(); + dataSource.remove(host); + TLocale.Logger.info("MYSQL-HIKARI.CLOSE-SUCCESS", host.getPlugin().getName(), host.getConnectionUrlSimple()); + } else { + TLocale.Logger.info("MYSQL-HIKARI.CLOSE-FAIL", host.getPlugin().getName(), String.valueOf(mapDataSource.getActivePlugin().get())); + } + } + } + + /** + * 根据数据库地址创建 HikariConfig 对象 + * + * @param sqlHost 数据库地址 + * @return {@link HikariConfig} + */ + public static HikariConfig createConfig(SQLHost sqlHost) { + HikariConfig config = new HikariConfig(); + config.setDriverClassName("com.mysql.jdbc.Driver"); + config.setJdbcUrl(sqlHost.getConnectionUrl()); + config.setUsername(sqlHost.getUser()); + config.setPassword(sqlHost.getPassword()); + config.setConnectionTestQuery("SELECT 1"); + config.setAutoCommit(true); + config.setMinimumIdle(1); + config.setMaximumPoolSize(10); + // 用来指定验证连接有效性的超时时间(毫秒/默认: 5秒) + config.setValidationTimeout(3000); + // 等待连接池分配连接的最大时长(毫秒/默认: 30秒),超过这个时长还没可用的连接则发生 SQLException + config.setConnectionTimeout(10000); + // 一个连接idle状态的最大时长(毫秒/默认: 10分钟),超时则被释放 + config.setIdleTimeout(60000); + // 一个连接的生命时长(毫秒/默认: 30分钟),超时而且没被使用则被释放 + config.setMaxLifetime(60000); + // 是否自定义配置,为true时下面两个参数才生效 + config.addDataSourceProperty("cachePrepStmts", "true"); + // 连接池大小默认25,官方推荐250-500 + config.addDataSourceProperty("prepStmtCacheSize", "250"); + // 单条语句最大长度默认256,官方推荐2048 + config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048"); + // 新版本MySQL支持服务器端准备,开启能够得到显著性能提升 + config.addDataSourceProperty("useServerPrepStmts", "true"); + config.addDataSourceProperty("useLocalSessionState", "true"); + config.addDataSourceProperty("useLocalTransactionState", "true"); + config.addDataSourceProperty("rewriteBatchedStatements", "true"); + config.addDataSourceProperty("cacheResultSetMetadata", "true"); + config.addDataSourceProperty("cacheServerConfiguration", "true"); + config.addDataSourceProperty("elideSetAutoCommits", "true"); + config.addDataSourceProperty("maintainTimeStats", "false"); + return config; + } +} diff --git a/src/main/java/me/skymc/taboolib/mysql/hikari/MapDataSource.java b/src/main/java/me/skymc/taboolib/mysql/hikari/MapDataSource.java new file mode 100644 index 0000000..d53a503 --- /dev/null +++ b/src/main/java/me/skymc/taboolib/mysql/hikari/MapDataSource.java @@ -0,0 +1,35 @@ +package me.skymc.taboolib.mysql.hikari; + +import com.zaxxer.hikari.HikariDataSource; +import me.skymc.taboolib.mysql.builder.SQLHost; + +import java.util.concurrent.atomic.AtomicInteger; + +/** + * @Author sky + * @Since 2018-05-17 23:47 + */ +public class MapDataSource { + + private SQLHost sqlHost; + private AtomicInteger activePlugin; + private HikariDataSource hikariDataSource; + + MapDataSource(SQLHost sqlHost, HikariDataSource hikariDataSource) { + this.sqlHost = sqlHost; + this.activePlugin = new AtomicInteger(); + this.hikariDataSource = hikariDataSource; + } + + public SQLHost getSqlHost() { + return sqlHost; + } + + public AtomicInteger getActivePlugin() { + return activePlugin; + } + + public HikariDataSource getHikariDataSource() { + return hikariDataSource; + } +} diff --git a/src/main/java/me/skymc/taboolib/mysql/protect/MySQLConnection.java b/src/main/java/me/skymc/taboolib/mysql/protect/MySQLConnection.java index c39b0c3..3a00da6 100644 --- a/src/main/java/me/skymc/taboolib/mysql/protect/MySQLConnection.java +++ b/src/main/java/me/skymc/taboolib/mysql/protect/MySQLConnection.java @@ -32,7 +32,7 @@ public class MySQLConnection { public MySQLConnection(String url, String user, String port, String password, String database, int recheck, Plugin plugin) { // 检查驱动 if (!loadDriverMySQL()) { - TLocale.Logger.error("MYSQL-CONNECTION.FALL-NOTFOUND-DRIVE"); + TLocale.Logger.error("MYSQL-CONNECTION.FAIL-NOTFOUND-DRIVE"); return; } @@ -58,12 +58,12 @@ public class MySQLConnection { Thread.sleep(getReCheckSeconds() * 1000); if (connection == null) { - TLocale.Logger.error("MYSQL-CONNECTION.FALL-NOTFOUND-CONNECTION", plugin.getName()); + TLocale.Logger.error("MYSQL-CONNECTION.FAIL-NOTFOUND-CONNECTION", plugin.getName()); } else { isExists("taboolib"); } } catch (Exception e) { - TLocale.Logger.error("MYSQL-CONNECTION.FALL-COMMAND-NORMAL", e.toString()); + TLocale.Logger.error("MYSQL-CONNECTION.FAIL-COMMAND-NORMAL", e.toString()); } } }); @@ -657,12 +657,12 @@ public class MySQLConnection { } private void printException(Exception e) { - TLocale.Logger.error("MYSQL-CONNECTION.FALL-COMMAND-NORMAL", e.toString()); + TLocale.Logger.error("MYSQL-CONNECTION.FAIL-COMMAND-NORMAL", e.toString()); reconnection(e); } private void printExceptionDetail(SQLException e) { - TLocale.Logger.error("MYSQL-CONNECTION.FALL-COMMAND-DETAIL", String.valueOf(e.getErrorCode()), e.toString()); + TLocale.Logger.error("MYSQL-CONNECTION.FAIL-COMMAND-DETAIL", String.valueOf(e.getErrorCode()), e.toString()); reconnection(e); } diff --git a/src/main/java/me/skymc/taboolib/object/WeightCollection.java b/src/main/java/me/skymc/taboolib/object/WeightCollection.java index cb6d491..d5d48f9 100644 --- a/src/main/java/me/skymc/taboolib/object/WeightCollection.java +++ b/src/main/java/me/skymc/taboolib/object/WeightCollection.java @@ -48,7 +48,7 @@ public class WeightCollection { return null; } - class WeightObject { + public static class WeightObject { private int weightNumber; private B weightObject; diff --git a/src/main/java/me/skymc/taboolib/playerdata/DataUtils.java b/src/main/java/me/skymc/taboolib/playerdata/DataUtils.java index 54687f5..a5de455 100644 --- a/src/main/java/me/skymc/taboolib/playerdata/DataUtils.java +++ b/src/main/java/me/skymc/taboolib/playerdata/DataUtils.java @@ -57,7 +57,7 @@ public class DataUtils implements Listener { try { conf.save(file); } catch (IOException e) { - TLocale.Logger.error("DATA-UTILS.FALL-SAVE-FILE", file.getName(), e.toString()); + TLocale.Logger.error("DATA-UTILS.FAIL-SAVE-FILE", file.getName(), e.toString()); } } diff --git a/src/main/java/me/skymc/taboolib/string/language2/Language2.java b/src/main/java/me/skymc/taboolib/string/language2/Language2.java index 0e5ec1c..7516212 100644 --- a/src/main/java/me/skymc/taboolib/string/language2/Language2.java +++ b/src/main/java/me/skymc/taboolib/string/language2/Language2.java @@ -74,7 +74,7 @@ public class Language2 { languageFile = new File(languageFolder, languageName); if (!languageFile.exists()) { if (plugin.getResource("Language2/" + languageName) == null) { - TLocale.Logger.error("LANGUAGE2.FALL-NOTFOUND-FILE", languageName); + TLocale.Logger.error("LANGUAGE2.FAIL-NOTFOUND-FILE", languageName); } else { plugin.saveResource("Language2/" + languageName, true); } diff --git a/src/main/java/me/skymc/taboolib/team/TagManager.java b/src/main/java/me/skymc/taboolib/team/TagManager.java index e34fc4b..161a87d 100644 --- a/src/main/java/me/skymc/taboolib/team/TagManager.java +++ b/src/main/java/me/skymc/taboolib/team/TagManager.java @@ -172,9 +172,9 @@ public class TagManager implements Listener { } private Team getTeam(Scoreboard scoreboard, PlayerData data) { - Team team = scoreboard.getTeam(data.getName()); + Team team = scoreboard.getTeam(String.valueOf(data.getPrefix())); if (team == null) { - team = scoreboard.registerNewTeam(data.getName()); + team = scoreboard.registerNewTeam(String.valueOf(data.getPrefix())); team.addEntry(data.getName()); } return team; diff --git a/src/main/java/me/skymc/taboolib/timecycle/TimeCycleManager.java b/src/main/java/me/skymc/taboolib/timecycle/TimeCycleManager.java index 0f4c25a..6357156 100644 --- a/src/main/java/me/skymc/taboolib/timecycle/TimeCycleManager.java +++ b/src/main/java/me/skymc/taboolib/timecycle/TimeCycleManager.java @@ -59,7 +59,7 @@ public class TimeCycleManager { if (!cycles.containsKey(cycle.getName())) { cycles.put(cycle.getName(), cycle); } else { - TLocale.Logger.error("TIMECYCLE.FALL-CYCLE-EXISTS", cycle.getName()); + TLocale.Logger.error("TIMECYCLE.FAIL-CYCLE-EXISTS", cycle.getName()); } } diff --git a/src/main/java/me/skymc/tlm/TLM.java b/src/main/java/me/skymc/tlm/TLM.java index f885c6a..1578e34 100644 --- a/src/main/java/me/skymc/tlm/TLM.java +++ b/src/main/java/me/skymc/tlm/TLM.java @@ -93,10 +93,10 @@ public class TLM { } public void loadedFall(String moduleName, String result, String location) { - TLocale.Logger.error("TABOOLIB-MODULE.FALL-LOADED", moduleName, result, location); + TLocale.Logger.error("TABOOLIB-MODULE.FAIL-LOADED", moduleName, result, location); } public void runtimeFall(String moduleName, String result, String location) { - TLocale.Logger.error("TABOOLIB-MODULE.FALL-RUNTIME", moduleName, result, location); + TLocale.Logger.error("TABOOLIB-MODULE.FAIL-RUNTIME", moduleName, result, location); } } diff --git a/src/main/resources/lang/zh_CN.yml b/src/main/resources/lang/zh_CN.yml index 9bff7dd..a236c96 100644 --- a/src/main/resources/lang/zh_CN.yml +++ b/src/main/resources/lang/zh_CN.yml @@ -32,7 +32,7 @@ CONFIG: NOTIFY: ERROR-SERVER-KEY: '&4检测到本服序列号与其他服务器相同, 已重新生成!' - ERROR-CONNECTION-FALL: '&4数据库连接失败, 请检查配置是否正确!' + ERROR-CONNECTION-FAIL: '&4数据库连接失败, 请检查配置是否正确!' SUCCESS-LOADED: - '§7插件载入完成!' - '§7插件作者: §f{0}' @@ -41,7 +41,7 @@ NOTIFY: SUCCESS-DISABLE: - '&c插件已卸载, 感谢您使用&4禁忌书库' - '&c插件作者: &4坏黑' - FALL-DISABLE: + FAIL-DISABLE: - '&c插件尚未启动完成, 已跳过卸载代码' - '&c插件作者: &4坏黑' @@ -72,28 +72,28 @@ ENTITY-UTILS: NOTFOUND-PROTOCOLLIB: '缺少前置插件 ProtocolLib' FILE-UTILS: - FALL-LOAD-CONFIGURATION: '&4配置文件载入失败!, 插件: &c{0}&4, 文件: &c{1}' + FAIL-LOAD-CONFIGURATION: '&4配置文件载入失败!, 插件: &c{0}&4, 文件: &c{1}' DATA-UTILS: SUCCESS-SAVE-DATA: '&7保存 &f{0} &7条插件数据, 耗时: &f{1} &7(ms)' - FALL-SAVE-FILE: '&4文件 &c{0}&4 保存失败, 原因: &c{1}' + FAIL-SAVE-FILE: '&4文件 &c{0}&4 保存失败, 原因: &c{1}' ITEM-UTILS: - FALL-LOAD-ITEMS: '物品库载入失败: &4{0}' - FALL-LOAD-ATTRIBUTE: '&c{0} &4不是一个有效的属性名称, 输入 &c/tlib attributes&4 查看所有属性' - FALL-LOAD-ENCHANT: '&c{0} &4不是一个有效的附魔名称, 输入 &c/tlib enchants&4 查看所有附魔' - FALL-LOAD-POTION: '&c{0} &4不是一个有效的药水名称, 输入 &c/tlib potions&4 查看所有药水' - FALL-LOAD-FLAG: '&c{0} &4不是一个有效的标签名称, 输入 &c/tlib flags&4 查看所有标签' - FALL-SAVE-EXISTS: '无法载入载入物品 &4{0}&c, 因为它已经存在了' + FAIL-LOAD-ITEMS: '物品库载入失败: &4{0}' + FAIL-LOAD-ATTRIBUTE: '&c{0} &4不是一个有效的属性名称, 输入 &c/tlib attributes&4 查看所有属性' + FAIL-LOAD-ENCHANT: '&c{0} &4不是一个有效的附魔名称, 输入 &c/tlib enchants&4 查看所有附魔' + FAIL-LOAD-POTION: '&c{0} &4不是一个有效的药水名称, 输入 &c/tlib potions&4 查看所有药水' + FAIL-LOAD-FLAG: '&c{0} &4不是一个有效的标签名称, 输入 &c/tlib flags&4 查看所有标签' + FAIL-SAVE-EXISTS: '无法载入载入物品 &4{0}&c, 因为它已经存在了' SUCCESS-LOAD-CACHES: '&7载入 &f{0} &7项缓存物品' SUCCESS-LOAD-NAMES: '&7载入 &f{0} &7项物品名称' EMPTY-ITEM: '空' LANGUAGE2: - FALL-NOTFOUND-FILE: '语言文件 {0} 不存在' + FAIL-NOTFOUND-FILE: '语言文件 {0} 不存在' TIMECYCLE: - FALL-CYCLE-EXISTS: '注册周期管理器 &8{0}&c 失败, 原因: &4名称重复' + FAIL-CYCLE-EXISTS: '注册周期管理器 &8{0}&c 失败, 原因: &4名称重复' ANVIL-CONTAINER: NAME-EXAMPLE: '在这里输入文本' @@ -114,19 +114,29 @@ UPDATETASK: - '&8####################################################' MYSQL-CONNECTION: - FALL-NOTFOUND-DRIVE: '&7驱动器获取失败, 无法连接到数据库' - FALL-NOTFOUND-CONNECTION: '&7警告! 数据库尚未连接, 请检查配置文件后重启服务器! ({0})' - FALL-COMMAND-NORMAL: '&4数据库命令执行出错, 错误原因: &c{0}' - FALL-COMMAND-DETAIL: '&4数据库命令执行出错, 错误代码: &c{0}&4, 错误原因: &c{1}' - SUCCESS-REGISTERED: '&7已向书库注册插件 &f{0}&7 的数据库连接' + FAIL-CONNECT: '&4数据库 &c{0} &4连接失败, 原因: &c{0}' + FAIL-NOTFOUND-DRIVE: '&7驱动器获取失败, 无法连接到数据库' + FAIL-NOTFOUND-CONNECTION: '&7警告! 数据库尚未连接, 请检查配置文件后重启服务器! ({0})' + FAIL-COMMAND-NORMAL: '&4数据库命令执行出错, 错误原因: &c{0}' + FAIL-COMMAND-DETAIL: '&4数据库命令执行出错, 错误代码: &c{0}&4, 错误原因: &c{1}' + FAIL-EXECUTE-TASK: '异步任务失败, 执行方式改为同步执行' + SUCCESS-REGISTERED: '&7插件 &f{0}&7 注册新的数据库连接' + SUCCESS-REGISTERED-EXISTS: '&7插件 &f{0}&7 引用插件 &f{1}&7 注册的数据库连接' SUCCESS-REGISTERED-LISTENER: '&7启动数据库连接监控' + SUCCESS-CONNECTION-CANCEL: '已停止插件 &f{0}&7 的 &f{1}&7 条数据库连接' NOTIFY-CONNECTING: '&7正在连接数据库, 地址: &f{0}' - NOTIFY-CONNECTED: '数据库连接成功 ({0}ms)' + NOTIFY-CONNECTED: '&7数据库连接成功 ({0}ms)' + +MYSQL-HIKARI: + CREATE-SUCCESS: '&7插件 &f{0}&7 注册新的数据库连接: &f{1}' + CREATE-EXISTS: '&7插件 &f{0}&7 引用插件 &f{1}&7 注册的数据库连接' + CLOSE-SUCCESS: '&7插件 &f{0} &7注册的数据库连接 &f{1} &7已被注销!' + CLOSE-FAIL: '&7插件 &f{0} &7注册的数据库连接正在被 &f{1} &7个插件使用, 无法注销!' TABOOLIB-MODULE: SUCCESS-LOADED: '&7载入 &f{0} &7个 &fTLM &7模块' - FALL-LOADED: '&4模块载入异常: &c{0}&4, 模块: &c{1}&4, 位于: &c{2}' - FALL-RUNTIME: '&4模块运行异常: &c{0}&4, 模块: &c{1}&4, 位于: &c{2}' + FAIL-LOADED: '&4模块载入异常: &c{0}&4, 模块: &c{1}&4, 位于: &c{2}' + FAIL-RUNTIME: '&4模块运行异常: &c{0}&4, 模块: &c{1}&4, 位于: &c{2}' COMMANDS: GLOBAL: @@ -459,7 +469,7 @@ COMMANDS: 0: '名称' INVALID-PLUGIN: '&8[&3&lTabooLib&8] &4插件 &c{0} &4已经载入' LOAD-SUCCESS: '&8[&3&lTabooLib&8] &7插件已载入' - LOAD-FALL: '&8[&3&lTabooLib&8] &7插件载入失败' + LOAD-FAIL: '&8[&3&lTabooLib&8] &7插件载入失败' UNLOAD: DESCRIPTION: '卸载插件' ARGUMENTS: @@ -467,7 +477,7 @@ COMMANDS: INVALID-PLUGIN: '&8[&3&lTabooLib&8] &4插件 &c{0} &4不存在' INVALID-PLUGIN-IGNORED: '&8[&3&lTabooLib&8] &4插件 &c{0} &4无法操作' UNLOAD-SUCCESS: '&8[&3&lTabooLib&8] &7插件已卸载' - UNLOAD-FALL: '&8[&3&lTabooLib&8] &7插件卸载失败' + UNLOAD-FAIL: '&8[&3&lTabooLib&8] &7插件卸载失败' RELOAD: DESCRIPTION: '重载插件' ARGUMENTS: