+ HikariHandler 新增 createDataSource 方法用于没有导入 HikariCP 库的项目使用。

+ 新增 /texecute 指令用于强制目标执行命令或发送聊天信息。
+ 新增 hikarisettings.yml 配置用于更改默认连接池设置。
o 修复 HikariHandler 重复创建连接池的问题。
o 修复 SQLTable 中 addColumn 方法无效的问题。
This commit is contained in:
坏黑 2018-07-04 21:59:08 +08:00
parent 33b90c64d2
commit 6cf9665d35
10 changed files with 223 additions and 80 deletions

View File

@ -8,11 +8,12 @@ import com.ilummc.tlib.util.IO;
import com.ilummc.tlib.util.Strings;
import me.skymc.taboolib.anvil.AnvilContainerAPI;
import me.skymc.taboolib.bstats.Metrics;
import me.skymc.taboolib.commands.TabooLibExecuteCommand;
import me.skymc.taboolib.commands.TabooLibMainCommand;
import me.skymc.taboolib.commands.internal.TBaseCommand;
import me.skymc.taboolib.commands.language.Language2Command;
import me.skymc.taboolib.commands.locale.TabooLibLocaleCommand;
import me.skymc.taboolib.commands.plugin.TabooLibPluginMainCommand;
import me.skymc.taboolib.commands.plugin.TabooLibPluginCommand;
import me.skymc.taboolib.commands.taboolib.listener.ListenerItemListCommand;
import me.skymc.taboolib.commands.taboolib.listener.ListenerSoundsCommand;
import me.skymc.taboolib.database.GlobalDataManager;
@ -45,6 +46,7 @@ import me.skymc.taboolib.update.UpdateTask;
import me.skymc.tlm.TLM;
import me.skymc.tlm.command.TLMCommands;
import me.skymc.tlm.module.TabooLibraryModule;
import net.milkbowl.vault.economy.Economy;
import org.bukkit.Bukkit;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.event.Listener;
@ -74,25 +76,15 @@ public class Main extends JavaPlugin implements Listener {
}
private static Plugin inst;
private static net.milkbowl.vault.economy.Economy Economy;
private static Economy economy;
private static File playerDataFolder;
private static File serverDataFolder;
private static StorageType storageType = StorageType.LOCAL;
private static boolean disable = false;
private static MySQLConnection connection = null;
private static Language2 exampleLanguage2;
private static boolean started;
private static boolean disable = false;
private static boolean started = false;
private static boolean isInternetOnline = false;
private FileConfiguration config = null;
@Override
@ -132,6 +124,8 @@ public class Main extends JavaPlugin implements Listener {
setupLibraries();
// 载入牛逼玩意儿
TLib.initPost();
// 注册连接池
HikariHandler.init();
}
@Override
@ -348,7 +342,8 @@ public class Main extends JavaPlugin implements Listener {
getCommand("taboolibrarymodule").setExecutor(new TLMCommands());
TBaseCommand.registerCommand("taboolib", new TabooLibMainCommand());
TBaseCommand.registerCommand("tabooliblocale", new TabooLibLocaleCommand());
TBaseCommand.registerCommand("taboolibplugin", new TabooLibPluginMainCommand());
TBaseCommand.registerCommand("taboolibplugin", new TabooLibPluginCommand());
TBaseCommand.registerCommand("taboolibexecute", new TabooLibExecuteCommand());
TBaseCommand.registerCommand("translateuuid", new TranslateUUIDCommand());
}
@ -390,11 +385,11 @@ public class Main extends JavaPlugin implements Listener {
}
public static net.milkbowl.vault.economy.Economy getEconomy() {
return Economy;
return economy;
}
public static void setEconomy(net.milkbowl.vault.economy.Economy economy) {
Economy = economy;
public static void setEconomy(Economy economy) {
this.economy = economy;
}
public static File getPlayerDataFolder() {

View File

@ -0,0 +1,116 @@
package me.skymc.taboolib.commands;
import com.ilummc.tlib.resources.TLocale;
import com.ilummc.tlib.util.Strings;
import me.skymc.taboolib.commands.internal.BaseMainCommand;
import me.skymc.taboolib.commands.internal.BaseSubCommand;
import me.skymc.taboolib.commands.internal.type.CommandArgument;
import me.skymc.taboolib.commands.internal.type.CommandRegister;
import me.skymc.taboolib.string.ArrayUtils;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
import org.bukkit.event.server.ServerCommandEvent;
/**
* @Author sky
* @Since 2018-07-04 21:32
*/
public class TabooLibExecuteCommand extends BaseMainCommand {
@Override
public String getCommandTitle() {
return TLocale.asString("COMMANDS.TEXECUTE.COMMAND-TITLE");
}
@CommandRegister(priority = 1)
BaseSubCommand chat = new BaseSubCommand() {
@Override
public String getLabel() {
return "chat";
}
@Override
public String getDescription() {
return TLocale.asString("COMMANDS.TEXECUTE.CHAT.DESCRIPTION");
}
@Override
public CommandArgument[] getArguments() {
return new CommandArgument[] {
new CommandArgument(TLocale.asString("COMMANDS.TEXECUTE.CHAT.ARGUMENTS.0")),
new CommandArgument(TLocale.asString("COMMANDS.TEXECUTE.CHAT.ARGUMENTS.1"))
};
}
@Override
public void onCommand(CommandSender sender, Command command, String label, String[] args) {
Player player = Bukkit.getPlayerExact(args[0]);
if (player == null) {
TLocale.sendTo(sender, "INVALID-PLAYER-OFFLINE", args[0]);
return;
}
player.chat(ArrayUtils.arrayJoin(args, 1));
}
};
@CommandRegister(priority = 1)
BaseSubCommand command = new BaseSubCommand() {
@Override
public String getLabel() {
return "command";
}
@Override
public String getDescription() {
return TLocale.asString("COMMANDS.TEXECUTE.COMMAND.DESCRIPTION");
}
@Override
public CommandArgument[] getArguments() {
return new CommandArgument[] {
new CommandArgument(TLocale.asString("COMMANDS.TEXECUTE.COMMAND.ARGUMENTS.0")),
new CommandArgument(TLocale.asString("COMMANDS.TEXECUTE.COMMAND.ARGUMENTS.1"))
};
}
@Override
public void onCommand(CommandSender sender, Command command, String label, String[] args) {
if (args[0].equalsIgnoreCase("console")) {
dispatchCommand(Bukkit.getConsoleSender(), ArrayUtils.arrayJoin(args, 1));
return;
}
Player player = Bukkit.getPlayerExact(args[0]);
if (player == null) {
TLocale.sendTo(sender, "INVALID-TARGET-NOT-FOUND", args[0]);
return;
}
dispatchCommand(player, ArrayUtils.arrayJoin(args, 1));
}
};
public static boolean dispatchCommand(CommandSender sender, String command) {
try {
if ((sender instanceof Player)) {
PlayerCommandPreprocessEvent e = new PlayerCommandPreprocessEvent((Player) sender, "/" + command);
Bukkit.getPluginManager().callEvent(e);
if (e.isCancelled() || Strings.isBlank(e.getMessage()) || !e.getMessage().startsWith("/")) {
return false;
}
return Bukkit.dispatchCommand(e.getPlayer(), e.getMessage().substring(1));
} else {
ServerCommandEvent e = new ServerCommandEvent(sender, command);
Bukkit.getPluginManager().callEvent(e);
if (e.isCancelled() || Strings.isBlank(e.getCommand())) {
return false;
}
return Bukkit.dispatchCommand(e.getSender(), e.getCommand());
}
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
}

View File

@ -25,7 +25,7 @@ import java.util.stream.Collectors;
* @Author sky
* @Since 2018-05-07 20:14
*/
public class TabooLibPluginMainCommand extends BaseMainCommand {
public class TabooLibPluginCommand extends BaseMainCommand {
@Override
public String getCommandTitle() {

View File

@ -78,13 +78,12 @@ public class SQLHost {
Objects.equals(getUser(), sqlHost.getUser()) &&
Objects.equals(getPort(), sqlHost.getPort()) &&
Objects.equals(getPassword(), sqlHost.getPassword()) &&
Objects.equals(getDatabase(), sqlHost.getDatabase()) &&
Objects.equals(getPlugin(), sqlHost.getPlugin());
Objects.equals(getDatabase(), sqlHost.getDatabase());
}
@Override
public int hashCode() {
return Objects.hash(getHost(), getUser(), getPort(), getPassword(), getDatabase(), getPlugin());
return Objects.hash(getHost(), getUser(), getPort(), getPassword(), getDatabase());
}
@Override

View File

@ -1,11 +1,12 @@
package me.skymc.taboolib.mysql.builder;
import com.google.common.base.Preconditions;
import com.ilummc.tlib.util.Strings;
import me.skymc.taboolib.mysql.builder.query.RunnableQuery;
import me.skymc.taboolib.mysql.builder.query.RunnableUpdate;
import me.skymc.taboolib.string.ArrayUtils;
import java.util.Arrays;
/**
* @Author sky
* @Since 2018-05-14 19:07
@ -28,17 +29,14 @@ public class SQLTable {
if (columns == null) {
columns = new SQLColumn[] {sqlColumn};
} else {
ArrayUtils.arrayAppend(columns, sqlColumn);
columns = ArrayUtils.arrayAppend(columns, sqlColumn);
}
return this;
}
public String createQuery() {
Preconditions.checkNotNull(columns);
StringBuilder builder = new StringBuilder();
for (SQLColumn sqlColumn : columns) {
builder.append(sqlColumn.convertToCommand()).append(", ");
}
Arrays.stream(columns).forEach(sqlColumn -> builder.append(sqlColumn.convertToCommand()).append(", "));
return Strings.replaceWithOrder("create table if not exists `{0}` ({1})", tableName, builder.substring(0, builder.length() - 2));
}

View File

@ -5,8 +5,13 @@ 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.fileutils.ConfigUtils;
import me.skymc.taboolib.fileutils.FileUtils;
import me.skymc.taboolib.mysql.builder.SQLHost;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import javax.sql.DataSource;
import java.util.concurrent.ConcurrentHashMap;
/**
@ -16,14 +21,16 @@ import java.util.concurrent.ConcurrentHashMap;
public class HikariHandler {
private static ConcurrentHashMap<SQLHost, MapDataSource> dataSource = new ConcurrentHashMap<>();
private static FileConfiguration settings;
public static void init() {
settings = ConfigUtils.saveDefaultConfig(Main.getInst(), "hikarisettings.yml");
}
public static DataSource createDataSource(SQLHost host) {
return createDataSource(host, null);
}
/**
* 根据数据库地址创建连接池如果已经存在则返回引用
*
* @param host 数据库地址
* @return {@link HikariDataSource}
* @throws java.sql.SQLException 数据库连接失败异常
*/
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();
@ -35,21 +42,11 @@ public class HikariHandler {
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 (host != null && dataSource.containsKey(host)) {
MapDataSource mapDataSource = dataSource.get(host);
@ -63,37 +60,26 @@ public class HikariHandler {
}
}
/**
* 根据数据库地址创建 HikariConfig 对象
*
* @param sqlHost 数据库地址
* @return {@link HikariConfig}
*/
public static HikariConfig createConfig(SQLHost sqlHost) {
HikariConfig config = new HikariConfig();
config.setDriverClassName("com.mysql.jdbc.Driver");
config.setDriverClassName(settings.getString("DefaultSettings.DriverClassName", "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.setAutoCommit(settings.getBoolean("DefaultSettings.AutoCommit", true));
config.setMinimumIdle(settings.getInt("DefaultSettings.MinimumIdle", 1));
config.setMaximumPoolSize(settings.getInt("DefaultSettings.MaximumPoolSize", 10));
config.setValidationTimeout(settings.getInt("DefaultSettings.ValidationTimeout", 3000));
config.setConnectionTimeout(settings.getInt("DefaultSettings.ConnectionTimeout", 10000));
config.setIdleTimeout(settings.getInt("DefaultSettings.IdleTimeout", 60000));
config.setMaxLifetime(settings.getInt("DefaultSettings.MaxLifetime", 60000));
if (settings.contains("DefaultSettings.DataSourceProperty")) {
settings.getConfigurationSection("DefaultSettings.DataSourceProperty").getKeys(false).forEach(key -> config.addDataSourceProperty(key, settings.getString("DefaultSettings.DataSourceProperty." + key)));
} else {
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");
@ -102,6 +88,7 @@ public class HikariHandler {
config.addDataSourceProperty("cacheServerConfiguration", "true");
config.addDataSourceProperty("elideSetAutoCommits", "true");
config.addDataSourceProperty("maintainTimeStats", "false");
}
return config;
}
}

View File

@ -6,7 +6,6 @@ import com.google.gson.JsonParser;
import com.ilummc.tlib.resources.TLocale;
import me.skymc.taboolib.Main;
import me.skymc.taboolib.TabooLib;
import me.skymc.taboolib.commands.plugin.TabooLibPluginMainCommand;
import me.skymc.taboolib.fileutils.FileUtils;
import org.bukkit.Bukkit;
import org.bukkit.scheduler.BukkitRunnable;

View File

@ -0,0 +1,32 @@
# 默认连接池配置
DefaultSettings:
DriverClassName: 'com.mysql.jdbc.Driver'
AutoCommit: true
MinimumIdle: 1
# 连接池大小
MaximumPoolSize: 10
# 用来指定验证连接有效性的超时时间(毫秒/默认: 5秒
ValidationTimeout: 3000
# 等待连接池分配连接的最大时长(毫秒/默认: 30秒
# 超过这个时长还没可用的连接则发生 SQLException
ConnectionTimeout: 10000
# 一个连接idle状态的最大时长毫秒/默认: 10分钟超时则被释放
IdleTimeout: 60000
# 一个连接的生命时长(毫秒/默认: 30分钟超时而且没被使用则被释放
MaxLifetime: 60000
# 是否自定义配置为true时下面两个参数才生效
DataSourceProperty:
cachePrepStmts: true
# 连接池大小默认25官方推荐250-500
prepStmtCacheSize: 250
# 单条语句最大长度默认256官方推荐2048
prepStmtCacheSqlLimit: 2048
# 新版本MySQL支持服务器端准备开启能够得到显著性能提升
useServerPrepStmts: true
useLocalSessionState: true
useLocalTransactionState: true
rewriteBatchedStatements: true
cacheResultSetMetadata: true
cacheServerConfiguration: true
elideSetAutoCommits: true
maintainTimeStats: false

View File

@ -533,6 +533,20 @@ COMMANDS:
RELOAD:
DESCRIPTION: '重载配置及数据库'
SUCCESS: '&8[&3&lTabooLib&8] &7请求已发送, 详细信息请查看控制台'
TEXECUTE:
COMMAND-TITLE: '&e&l----- &6&lTabooLibExecute Commands &e&l-----'
CHAT:
DESCRIPTION: '使玩家输入聊天内容'
ARGUMENTS:
0: '玩家'
1: '内容'
INVALID-PLAYER-OFFLINE: '&8[&3&lTabooLib&8] &4玩家 &c{0} &4不在线.'
COMMAND:
DESCRIPTION: '使目标输入执行指令'
ARGUMENTS:
0: '目标'
1: '内容'
INVALID-TARGET-NOT-FOUND: '&8[&3&lTabooLib&8] &4目标 &c{0} &4不存在.'
DATABASE:
CONNECTION-ESTABLISHED: '成功连接到 {0} 数据库,连接池大小 {1}'

View File

@ -21,6 +21,9 @@ commands:
taboolibplugin:
aliases: [tabooplugin, tplugin]
permission: taboolib.admin
taboolibexecute:
aliases: [texecute]
permission: taboolib.admin
taboolibrarymodule:
aliases: [tlm]
translateuuid: