1414 *
1515 * <p>Supports MySQL, MariaDB, and PostgreSQL. The required JDBC driver JAR is
1616 * downloaded automatically from Maven Central on first use and cached in
17- * {@code <pluginDataFolder >/drivers/}. See {@link SQLDriverLoader}.
17+ * {@code <dataFolder >/drivers/}. See {@link SQLDriverLoader}.
1818 *
19- * <p>Connection details are supplied via {@link SQLPlayerJoinTracker. SQLConfig}.
19+ * <p>Connection details are supplied via {@link SQLConfig}.
2020 * The store keeps a single persistent {@link Connection} and transparently
2121 * reconnects on failure.
2222 *
2323 * <p>All public methods are {@code synchronized} for thread safety.
2424 */
25- public class SQLPlayerDataStore implements PlayerDataStore {
25+ public class SQLPlayerDataStore extends SQLHandler implements PlayerDataStore {
2626
2727 // MySQL / MariaDB uses INSERT … ON DUPLICATE KEY UPDATE.
2828 // PostgreSQL uses INSERT … ON CONFLICT DO UPDATE.
@@ -33,17 +33,9 @@ public class SQLPlayerDataStore implements PlayerDataStore {
3333 private final String UPSERT_MYSQL ;
3434 private final String UPSERT_POSTGRES ;
3535
36- private final CoreLogger logger ;
37- private final SQLPlayerJoinTracker .SQLConfig sqlConfig ;
38- private final boolean isPostgres ;
39- private Connection connection ;
40-
41- public SQLPlayerDataStore (CoreLogger logger , SQLPlayerJoinTracker .SQLConfig sqlConfig , Path pluginDataFolder )
36+ public SQLPlayerDataStore (CoreLogger logger , SQLConfig sqlConfig , Path dataFolder )
4237 throws SQLException , SQLDriverLoader .DriverLoadException {
43- this .logger = logger ;
44- this .sqlConfig = sqlConfig ;
45- this .isPostgres = "postgresql" .equals (sqlConfig .driver ());
46- new SQLDriverLoader (logger , pluginDataFolder ).ensureLoaded (sqlConfig .driver ());
38+ super (logger , sqlConfig , dataFolder );
4739
4840 String tableName = sqlConfig .tablePrefix () + "players" ;
4941
@@ -92,14 +84,18 @@ public SQLPlayerDataStore(CoreLogger logger, SQLPlayerJoinTracker.SQLConfig sqlC
9284 " ignore_swap = EXCLUDED.ignore_swap," +
9385 " ignore_leave = EXCLUDED.ignore_leave" ;
9486
95- setUpConnection ();
87+ }
88+
89+ @ Override
90+ protected String createTableSql () {
91+ return isPostgres ? CREATE_TABLE_POSTGRES : CREATE_TABLE_MYSQL ;
9692 }
9793
9894 @ Override
9995 @ Nullable
10096 public synchronized PlayerDataSnapshot getData (UUID playerUuid ) {
10197 if (isConnectionInvalid ()) return null ;
102- try (PreparedStatement ps = connection .prepareStatement (SELECT_SQL )) {
98+ try (PreparedStatement ps = connection () .prepareStatement (SELECT_SQL )) {
10399 ps .setString (1 , playerUuid .toString ());
104100 try (ResultSet rs = ps .executeQuery ()) {
105101 if (rs .next ()) {
@@ -122,7 +118,7 @@ public synchronized PlayerDataSnapshot getData(UUID playerUuid) {
122118 public synchronized void saveData (UUID playerUuid , PlayerDataSnapshot data ) {
123119 if (isConnectionInvalid ()) return ;
124120 String upsert = isPostgres ? UPSERT_POSTGRES : UPSERT_MYSQL ;
125- try (PreparedStatement ps = connection .prepareStatement (upsert )) {
121+ try (PreparedStatement ps = connection () .prepareStatement (upsert )) {
126122 ps .setString (1 , playerUuid .toString ());
127123 ps .setString (2 , data .playerName ());
128124 ps .setObject (3 , data .silentState (), Types .BOOLEAN );
@@ -139,7 +135,7 @@ public synchronized void saveData(UUID playerUuid, PlayerDataSnapshot data) {
139135 @ Nullable
140136 public synchronized UUID resolveUuid (String playerName ) {
141137 if (isConnectionInvalid ()) return null ;
142- try (PreparedStatement ps = connection .prepareStatement (RESOLVE_SQL )) {
138+ try (PreparedStatement ps = connection () .prepareStatement (RESOLVE_SQL )) {
143139 ps .setString (1 , playerName );
144140 try (ResultSet rs = ps .executeQuery ()) {
145141 if (rs .next ()) {
@@ -151,67 +147,4 @@ public synchronized UUID resolveUuid(String playerName) {
151147 }
152148 return null ;
153149 }
154-
155- @ Override
156- public synchronized void close () throws SQLException {
157- if (connection != null && !connection .isClosed ()) {
158- connection .close ();
159- }
160- }
161-
162- // --- Internal helpers ---
163-
164- /**
165- * Opens a new connection and ensures the table exists.
166- */
167- private void setUpConnection () throws SQLException {
168- String url = buildJdbcUrl ();
169- this .connection = DriverManager .getConnection (url , sqlConfig .username (), sqlConfig .password ());
170- try (Statement stmt = connection .createStatement ()) {
171- stmt .execute (isPostgres ? CREATE_TABLE_POSTGRES : CREATE_TABLE_MYSQL );
172- }
173- logger .debug ("[SQLPlayerDataStore] Connected to " + sqlConfig .driver () + " at " + sqlConfig .host () + ":" + sqlConfig .port ());
174- }
175-
176- /**
177- * Returns {@code true} if the connection is unusable, attempting a reconnect first.
178- */
179- private boolean isConnectionInvalid () {
180- try {
181- if (connection == null || connection .isClosed () || !connection .isValid (sqlConfig .connectionTimeout ())) {
182- logger .info ("[SQLPlayerDataStore] Connection lost — attempting reconnect..." );
183- setUpConnection ();
184- }
185- return false ;
186- } catch (SQLException e ) {
187- logger .severe ("[SQLPlayerDataStore] Cannot reach SQL server at '" + sqlConfig .host () + "': " + e .getMessage ());
188- return true ;
189- }
190- }
191-
192- /**
193- * Builds a JDBC URL from the {@link SQLPlayerJoinTracker.SQLConfig}.
194- *
195- * <ul>
196- * <li>MySQL: {@code jdbc:mysql://host:port/db?...}</li>
197- * <li>MariaDB: {@code jdbc:mariadb://host:port/db?...}</li>
198- * <li>PostgreSQL: {@code jdbc:postgresql://host:port/db?...}</li>
199- * </ul>
200- */
201- private String buildJdbcUrl () {
202- StringBuilder url = new StringBuilder ()
203- .append ("jdbc:" ).append (sqlConfig .driver ()).append ("://" )
204- .append (sqlConfig .host ()).append (':' ).append (sqlConfig .port ())
205- .append ('/' ).append (sqlConfig .database ())
206- .append ("?autoReconnect=true" )
207- .append ("&connectTimeout=" ).append (sqlConfig .connectionTimeout () * 1000 )
208- .append ("&allowPublicKeyRetrieval=true" );
209-
210- if (!isPostgres ) {
211- url .append ("&useSSL=" ).append (sqlConfig .useSSL ());
212- url .append ("&characterEncoding=utf8" );
213- }
214-
215- return url .toString ();
216- }
217150}
0 commit comments