I'm creating a plugin for the game Minecraft, and with it I'm using HikariCP and MySQL to store data between server restarts. I've created working code but I'm wanting to improve it.
While the code works fine, I feel there's a simpler way to structure it. I appreciate any suggestions.
HikariFacade.java
public class HikariFacade {
private final HikariConfig hikariConfig;
private final HikariDataSource hikariDataSource;
public HikariFacade(HikariConfig hikariConfig) {
this.hikariConfig = hikariConfig;
hikariDataSource = new HikariDataSource(hikariConfig);
}
/**
* Get a connection from the DataSource
*
* @return A connection, or null if one couldn't be obtained
*/
public Connection getConnection() {
Connection connection = null;
try {
connection = hikariDataSource.getConnection();
} catch (SQLException e) {
e.printStackTrace();
}
return connection;
}
/**
* Create a PreparedStatement
*
* @param sql The SQL for the PreparedStatment
* @return A prepared statement
* @throws SQLException
*/
public PreparedStatement createPreparedStatement(String sql) throws SQLException {
return getConnection().prepareStatement(sql);
}
/**
* Run an update, then close the resources
*
* @param ps Run a PreparedStatement as an update
* @return The number of rows effected
* @throws SQLException
*/
public int update(PreparedStatement ps) throws SQLException {
int i = ps.executeUpdate();
close(ps.getConnection(), ps, null);
return i;
}
/**
* Run a query, then close the resources
*
* @param ps Run a PreparedStatement as a query
* @return The ResultSet from the query
* @throws SQLException
*/
public ResultSet query(PreparedStatement ps) throws SQLException {
ResultSet rs = ps.executeQuery();
close(ps.getConnection(), ps, rs);
return rs;
}
/**
* Close a set of database related objects
*
* @param connection A Connection to close
* @param statement A Statement to close
* @param resultSet A ResultSet to close
*/
public static void close(Connection connection, Statement statement, ResultSet resultSet) {
try {
if (connection != null) {
connection.close();
}
if (statement != null) {
statement.close();
}
if (resultSet != null) {
resultSet.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
public HikariDataSource getHikariDataSource() {
return hikariDataSource;
}
}
DatabaseManager.java
public abstract class DatabaseManager {
protected HikariFacade hikariFacade;
public DatabaseManager(HikariFacade hikariFacade) {
this.hikariFacade = hikariFacade;
}
}
TownDatabaseManager.java
public class TownDatabaseManager extends DatabaseManager {
public TownDatabaseManager(HikariFacade hikariFacade) {
super(hikariFacade);
}
public int create(Town town) {
String sql = "INSERT INTO towns VALUES (?);";
try {
PreparedStatement ps = hikariFacade.createPreparedStatement(sql);
ps.setString(1, String.valueOf(town.getUuid()));
return hikariFacade.update(ps);
} catch (SQLException e) {
e.printStackTrace();
}
return 0;
}
public List<Town> loadTowns() {
String sql = "SELECT * FROM towns;";
try {
PreparedStatement ps = hikariFacade.createPreparedStatement(sql);
ResultSet rs = hikariFacade.query(ps);
List<Town> towns = new ArrayList<>();
while (rs.next()) {
UUID townUuid = UUID.fromString(rs.getString("town_uuid"));
towns.add(new Town(townUuid));
}
return towns;
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
}
Here's how this is all used in the end:
Main.java
private void testDb() {
Town newTown = new Town(UUID.randomUUID());
int i = new TownDatabaseManager(getHikariFacade()).create(newTown);
new TownDatabaseManager(getHikariFacade()).loadTowns();
}