Plan/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/MySQLDB.java

173 lines
6.0 KiB
Java

/*
* This file is part of Player Analytics (Plan).
*
* Plan is free software: you can redistribute it and/or modify
* it under the terms of the LGNU Lesser General Public License v3 as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Plan is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* LGNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
*/
package com.djrapitops.plan.system.database.databases.sql;
import com.djrapitops.plan.api.exceptions.database.DBInitException;
import com.djrapitops.plan.api.exceptions.database.DBOpException;
import com.djrapitops.plan.data.store.containers.NetworkContainer;
import com.djrapitops.plan.system.database.databases.DBType;
import com.djrapitops.plan.system.info.server.ServerInfo;
import com.djrapitops.plan.system.locale.Locale;
import com.djrapitops.plan.system.locale.lang.PluginLang;
import com.djrapitops.plan.system.settings.Settings;
import com.djrapitops.plan.system.settings.config.PlanConfig;
import com.djrapitops.plugin.benchmarking.Timings;
import com.djrapitops.plugin.logging.L;
import com.djrapitops.plugin.logging.console.PluginLogger;
import com.djrapitops.plugin.logging.error.ErrorHandler;
import com.djrapitops.plugin.task.RunnableFactory;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import dagger.Lazy;
import javax.inject.Inject;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
/**
* @author Rsl1122
*/
public class MySQLDB extends SQLDB {
private static int increment = 1;
protected volatile DataSource dataSource;
@Inject
public MySQLDB(
Locale locale,
PlanConfig config,
Lazy<ServerInfo> serverInfo,
NetworkContainer.Factory networkContainerFactory,
RunnableFactory runnableFactory,
PluginLogger pluginLogger,
Timings timings,
ErrorHandler errorHandler
) {
super(() -> serverInfo.get().getServerUUID(), locale, config, networkContainerFactory, runnableFactory, pluginLogger, timings, errorHandler);
}
private static synchronized void increment() {
increment++;
}
@Override
public DBType getType() {
return DBType.MySQL;
}
/**
* Setups the {@link HikariDataSource}
*/
@Override
public void setupDataSource() throws DBInitException {
try {
HikariConfig hikariConfig = new HikariConfig();
String host = config.getString(Settings.DB_HOST);
String port = config.getString(Settings.DB_PORT);
String database = config.getString(Settings.DB_DATABASE);
String launchOptions = config.getString(Settings.DB_LAUNCH_OPTIONS);
if (launchOptions.isEmpty() || !launchOptions.startsWith("?") || launchOptions.endsWith("&")) {
launchOptions = "?rewriteBatchedStatements=true&useSSL=false";
logger.error(locale.getString(PluginLang.DB_MYSQL_LAUNCH_OPTIONS_FAIL, launchOptions));
}
hikariConfig.setJdbcUrl("jdbc:mysql://" + host + ":" + port + "/" + database + launchOptions);
String username = config.getString(Settings.DB_USER);
String password = config.getString(Settings.DB_PASS);
hikariConfig.setUsername(username);
hikariConfig.setPassword(password);
hikariConfig.setPoolName("Plan Connection Pool-" + increment);
increment();
hikariConfig.setAutoCommit(true);
hikariConfig.setMaximumPoolSize(8);
hikariConfig.setMaxLifetime(TimeUnit.MINUTES.toMillis(25L));
hikariConfig.setLeakDetectionThreshold(TimeUnit.MINUTES.toMillis(10L));
this.dataSource = new HikariDataSource(hikariConfig);
getConnection();
} catch (SQLException e) {
throw new DBInitException("Failed to set-up HikariCP Datasource: " + e.getMessage(), e);
}
}
@Override
public Connection getConnection() throws SQLException {
Connection connection = dataSource.getConnection();
if (!connection.isValid(5)) {
connection.close();
if (dataSource instanceof HikariDataSource) {
((HikariDataSource) dataSource).close();
}
try {
setupDataSource();
// get new connection after restarting pool
return dataSource.getConnection();
} catch (DBInitException e) {
throw new DBOpException("Failed to restart DataSource after a connection was invalid: " + e.getMessage(), e);
}
}
return connection;
}
@Override
public void close() {
if (dataSource instanceof HikariDataSource) {
((HikariDataSource) dataSource).close();
}
super.close();
}
@Override
public void returnToPool(Connection connection) {
try {
if (connection != null) {
connection.close();
}
} catch (SQLException e) {
errorHandler.log(L.ERROR, this.getClass(), e);
}
}
@Override
public void commit(Connection connection) {
returnToPool(connection);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
MySQLDB mySQLDB = (MySQLDB) o;
return Objects.equals(dataSource, mySQLDB.dataSource);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), dataSource);
}
}