SQLite now uses single connection again (Fixes #309, #321 & possibly #319)

This commit is contained in:
Rsl1122 2017-10-07 19:46:51 +03:00
parent cafd73b787
commit 82869f0ec1
8 changed files with 200 additions and 151 deletions

View File

@ -3,7 +3,6 @@ package main.java.com.djrapitops.plan.database;
import main.java.com.djrapitops.plan.api.IPlan;
import main.java.com.djrapitops.plan.api.exceptions.DatabaseInitException;
import main.java.com.djrapitops.plan.database.tables.*;
import org.apache.commons.dbcp2.BasicDataSource;
import org.apache.commons.lang3.StringUtils;
import java.sql.Connection;
@ -22,90 +21,23 @@ import java.util.UUID;
*/
public abstract class Database {
/**
* Instance of Plan used with this database.
*/
protected final IPlan plugin;
/**
* Table representing plan_users in the database.
*/
protected UsersTable usersTable;
/**
* Table representing plan_user_info in the database.
*/
protected UserInfoTable userInfoTable;
/**
* Table representing plan_actions in the database.
*/
protected ActionsTable actionsTable;
/**
* Table representing plan_kills in the database.
*/
protected KillsTable killsTable;
/**
* Table representing plan_nicknames in the database.
*/
protected NicknamesTable nicknamesTable;
/**
* Table representing plan_sessions in the database.
*/
protected SessionsTable sessionsTable;
/**
* Table representing plan_ips in the database.
*/
protected IPsTable ipsTable;
/**
* Table representing plan_commandusages in the database.
*/
protected CommandUseTable commandUseTable;
/**
* Table representing plan_tps in the database.
*
* @since 3.5.0
*/
protected TPSTable tpsTable;
/**
* Table representing plan_version in the database.
*/
protected VersionTable versionTable;
/**
* Table representing plan_security in the database.
*
* @since 3.5.2
*/
protected SecurityTable securityTable;
/**
* Table representing plan_worlds in the database.
*
* @since 3.6.0
*/
protected WorldTable worldTable;
/**
* Table representing plan_world_times in the database.
*
* @since 3.6.0
*/
protected WorldTimesTable worldTimesTable;
/**
* Table representing plan_servers in the database.
*/
protected ServerTable serverTable;
protected BasicDataSource dataSource;
/**
* Super constructor.
@ -179,6 +111,16 @@ public abstract class Database {
*/
public abstract void close() throws SQLException;
/**
* Returns a connection to the MySQL connection pool.
* <p>
* On SQLite does nothing.
*
* @param connection Connection to return.
* @throws SQLException DB Error
*/
public abstract void returnToPool(Connection connection) throws SQLException;
/**
* Removes all data related to an account from the database.
*
@ -318,10 +260,6 @@ public abstract class Database {
return userInfoTable;
}
public BasicDataSource getDataSource() {
return dataSource;
}
public abstract void commit(Connection connection) throws SQLException;
public boolean isUsingMySQL() {

View File

@ -5,11 +5,16 @@ import main.java.com.djrapitops.plan.api.IPlan;
import main.java.com.djrapitops.plan.api.exceptions.DatabaseInitException;
import org.apache.commons.dbcp2.BasicDataSource;
import java.sql.Connection;
import java.sql.SQLException;
/**
* @author Rsl1122
*/
public class MySQLDB extends SQLDB {
private BasicDataSource dataSource;
/**
* Class Constructor.
*
@ -50,4 +55,15 @@ public class MySQLDB extends SQLDB {
public String getName() {
return "MySQL";
}
@Override
public Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
@Override
public void close() throws SQLException {
dataSource.close();
super.close();
}
}

View File

@ -10,7 +10,6 @@ import main.java.com.djrapitops.plan.database.Database;
import main.java.com.djrapitops.plan.database.tables.*;
import main.java.com.djrapitops.plan.database.tables.move.Version8TransferTable;
import main.java.com.djrapitops.plan.utilities.Benchmark;
import main.java.com.djrapitops.plan.utilities.MiscUtils;
import org.apache.commons.dbcp2.BasicDataSource;
import java.sql.Connection;
@ -191,7 +190,6 @@ public abstract class SQLDB extends Database {
*/
@Override
public void close() throws SQLException {
dataSource.close();
setStatus("Closed");
open = false;
Log.logDebug("Database"); // Log remaining Debug info if present
@ -282,9 +280,7 @@ public abstract class SQLDB extends Database {
Log.logDebug("Database");
}
public Connection getConnection() throws SQLException {
return getDataSource().getConnection();
}
public abstract Connection getConnection() throws SQLException;
/**
* Commits changes to the .db file when using SQLite Database.
@ -298,7 +294,14 @@ public abstract class SQLDB extends Database {
connection.commit();
}
} finally {
MiscUtils.close(connection);
returnToPool(connection);
}
}
@Override
public void returnToPool(Connection connection) throws SQLException {
if (usingMySQL && connection != null) {
connection.close();
}
}
@ -313,7 +316,7 @@ public abstract class SQLDB extends Database {
connection.rollback();
}
} finally {
MiscUtils.close(connection);
returnToPool(connection);
}
}

View File

@ -1,10 +1,18 @@
package main.java.com.djrapitops.plan.database.databases;
import com.djrapitops.plugin.task.AbsRunnable;
import com.djrapitops.plugin.task.ITask;
import main.java.com.djrapitops.plan.Log;
import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.api.exceptions.DatabaseInitException;
import main.java.com.djrapitops.plan.utilities.MiscUtils;
import org.apache.commons.dbcp2.BasicDataSource;
import java.io.File;
import java.util.Collections;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
/**
* @author Rsl1122
@ -12,6 +20,8 @@ import java.util.Collections;
public class SQLiteDB extends SQLDB {
private final String dbName;
private Connection connection;
private ITask connectionPingTask;
/**
* Class Constructor.
@ -31,17 +41,74 @@ public class SQLiteDB extends SQLDB {
* Setups the {@link BasicDataSource}
*/
@Override
public void setupDataSource() {
dataSource = new BasicDataSource();
public void setupDataSource() throws DatabaseInitException {
try {
connection = getNewConnection(dbName);
} catch (SQLException e) {
throw new DatabaseInitException(e);
}
startConnectionPingTask();
}
String filePath = new File(plugin.getDataFolder(), dbName + ".db").getAbsolutePath();
dataSource.setUrl("jdbc:sqlite:" + filePath);
public Connection getNewConnection(String dbName) throws SQLException {
try {
Class.forName("org.sqlite.JDBC");
} catch (ClassNotFoundException e) {
Log.toLog(this.getClass().getName(), e);
return null; // Should never happen.
}
dataSource.setEnableAutoCommitOnReturn(false);
dataSource.setDefaultAutoCommit(false);
String dbFilePath = new File(plugin.getDataFolder(), dbName + ".db").getAbsolutePath();
Connection connection = DriverManager.getConnection("jdbc:sqlite:" + dbFilePath + "?journal_mode=WAL");
connection.setAutoCommit(false);
// connection.
dataSource.setConnectionInitSqls(Collections.singletonList("PRAGMA JOURNAL_MODE=WAL"));
dataSource.setMaxTotal(-1);
// setJournalMode(connection);
return connection;
}
private void setJournalMode(Connection connection) throws SQLException {
try (Statement statement = connection.createStatement()) {
statement.execute("");
}
}
private void startConnectionPingTask() {
stopConnectionPingTask();
// Maintains Connection.
connectionPingTask = plugin.getRunnableFactory().createNew(new AbsRunnable("DBConnectionPingTask " + getName()) {
@Override
public void run() {
Statement statement = null;
try {
if (connection != null && !connection.isClosed()) {
statement = connection.createStatement();
statement.execute("/* ping */ SELECT 1");
}
} catch (SQLException e) {
try {
connection = getNewConnection(dbName);
} catch (SQLException e1) {
Log.toLog(this.getClass().getName(), e1);
Log.error("SQLite connection maintaining task had to be closed due to exception.");
this.cancel();
}
} finally {
MiscUtils.close(statement);
}
}
}).runTaskTimerAsynchronously(60L * 20L, 60L * 20L);
}
private void stopConnectionPingTask() {
if (connectionPingTask != null) {
try {
connectionPingTask.cancel();
} catch (Exception ignored) {
}
}
}
/**
@ -52,4 +119,18 @@ public class SQLiteDB extends SQLDB {
return "SQLite";
}
@Override
public Connection getConnection() throws SQLException {
if (connection == null) {
connection = getNewConnection(dbName);
}
return connection;
}
@Override
public void close() throws SQLException {
stopConnectionPingTask();
MiscUtils.close(connection);
super.close();
}
}

View File

@ -84,13 +84,16 @@ public abstract class Table {
*/
protected boolean execute(String statementString) throws SQLException {
Statement statement = null;
try (Connection connection = getConnection()) {
Connection connection = null;
try {
connection = getConnection();
statement = connection.createStatement();
boolean b = statement.execute(statementString);
commit(connection);
return b;
} finally {
close(statement);
db.returnToPool(connection);
}
}
@ -181,23 +184,35 @@ public abstract class Table {
protected boolean execute(ExecStatement statement) throws SQLException {
boolean updatedSomething = false;
try (Connection connection = getConnection()) {
Connection connection = null;
try {
connection = getConnection();
updatedSomething = statement.execute(connection.prepareStatement(statement.getSql()));
commit(connection);
} finally {
db.returnToPool(connection);
}
return updatedSomething;
}
protected void executeBatch(ExecStatement statement) throws SQLException {
try (Connection connection = getConnection()) {
Connection connection = null;
try {
connection = getConnection();
statement.executeBatch(connection.prepareStatement(statement.getSql()));
commit(connection);
} finally {
db.returnToPool(connection);
}
}
protected <T> T query(QueryStatement<T> statement) throws SQLException {
try (Connection connection = getConnection()) {
Connection connection = null;
try {
connection = getConnection();
return statement.executeQuery(connection.prepareStatement(statement.getSql()));
} finally {
db.returnToPool(connection);
}
}
}

View File

@ -31,8 +31,7 @@ public class LiteBansDatabaseQueries extends Table {
try {
statement = database.prepareStatement("SELECT uuid, reason, banned_by_name, until FROM litebans_bans");
set = statement.executeQuery();
List<BanObject> bans = getBanObjects(set);
return bans;
return getBanObjects(set);
} finally {
close(set);
close(statement);
@ -59,8 +58,7 @@ public class LiteBansDatabaseQueries extends Table {
statement = database.prepareStatement("SELECT uuid, reason, banned_by_name, until FROM litebans_bans WHERE uuid=?");
statement.setString(1, playerUUID.toString());
set = statement.executeQuery();
List<BanObject> bans = getBanObjects(set);
return bans;
return getBanObjects(set);
} finally {
close(set);
close(statement);

View File

@ -7,9 +7,12 @@ package com.djrapitops.pluginbridge.plan.viaversion;
import main.java.com.djrapitops.plan.api.exceptions.DBCreateTableException;
import main.java.com.djrapitops.plan.database.databases.SQLDB;
import main.java.com.djrapitops.plan.database.processing.ExecStatement;
import main.java.com.djrapitops.plan.database.processing.QueryAllStatement;
import main.java.com.djrapitops.plan.database.processing.QueryStatement;
import main.java.com.djrapitops.plan.database.sql.Select;
import main.java.com.djrapitops.plan.database.tables.Table;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
@ -52,38 +55,38 @@ public class ProtocolTable extends Table {
}
public int getProtocolVersion(UUID uuid) throws SQLException {
PreparedStatement statement = null;
ResultSet set = null;
try (Connection connection = getConnection()) {
statement = connection.prepareStatement("SELECT " + columnProtocolVersion + " FROM " + tableName + " WHERE " + columnUUID + "=?");
statement.setString(1, uuid.toString());
set = statement.executeQuery();
if (set.next()) {
return set.getInt(columnProtocolVersion);
} else {
return -1;
String sql = "SELECT " + columnProtocolVersion + " FROM " + tableName + " WHERE " + columnUUID + "=?";
return query(new QueryStatement<Integer>(sql) {
@Override
public void prepare(PreparedStatement statement) throws SQLException {
statement.setString(1, uuid.toString());
}
} finally {
close(set, statement);
}
@Override
public Integer processResults(ResultSet set) throws SQLException {
if (set.next()) {
return set.getInt(columnProtocolVersion);
} else {
return -1;
}
}
});
}
public Map<UUID, Integer> getProtocolVersions() throws SQLException {
PreparedStatement statement = null;
ResultSet set = null;
try (Connection connection = getConnection()) {
statement = connection.prepareStatement("SELECT * FROM " + tableName);
set = statement.executeQuery();
Map<UUID, Integer> versions = new HashMap<>();
while (set.next()) {
String uuidS = set.getString(columnUUID);
UUID uuid = UUID.fromString(uuidS);
versions.put(uuid, set.getInt(columnProtocolVersion));
return query(new QueryAllStatement<Map<UUID, Integer>>(Select.all(tableName).toString(), 5000) {
@Override
public Map<UUID, Integer> processResults(ResultSet set) throws SQLException {
Map<UUID, Integer> versions = new HashMap<>();
while (set.next()) {
String uuidS = set.getString(columnUUID);
UUID uuid = UUID.fromString(uuidS);
versions.put(uuid, set.getInt(columnProtocolVersion));
}
return versions;
}
return versions;
} finally {
close(set, statement);
}
});
}
private boolean exists(UUID uuid) throws SQLException {
@ -91,36 +94,31 @@ public class ProtocolTable extends Table {
}
private void updateProtocolVersion(UUID uuid, int version) throws SQLException {
PreparedStatement statement = null;
try (Connection connection = getConnection()) {
statement = connection.prepareStatement("UPDATE " + tableName + " SET "
+ columnProtocolVersion + "=? "
+ " WHERE (" + columnUUID + "=?)");
statement.setInt(1, version);
statement.setString(2, uuid.toString());
statement.execute();
String sql = "UPDATE " + tableName + " SET "
+ columnProtocolVersion + "=? "
+ " WHERE (" + columnUUID + "=?)";
commit(connection);
} finally {
close(statement);
}
execute(new ExecStatement(sql) {
@Override
public void prepare(PreparedStatement statement) throws SQLException {
statement.setInt(1, version);
statement.setString(2, uuid.toString());
}
});
}
private void insertProtocolVersion(UUID uuid, int version) throws SQLException {
PreparedStatement statement = null;
try (Connection connection = getConnection()) {
statement = connection.prepareStatement(
"INSERT INTO " + tableName + " ("
+ columnUUID + ", "
+ columnProtocolVersion
+ ") VALUES (?, ?)");
statement.setString(1, uuid.toString());
statement.setInt(2, version);
statement.execute();
String sql = "INSERT INTO " + tableName + " ("
+ columnUUID + ", "
+ columnProtocolVersion
+ ") VALUES (?, ?)";
commit(connection);
} finally {
close(statement);
}
execute(new ExecStatement(sql) {
@Override
public void prepare(PreparedStatement statement) throws SQLException {
statement.setString(1, uuid.toString());
statement.setInt(2, version);
}
});
}
}