Files
SHiNE-server/SHiNE-server/shine-server-db/src/main/java/shine/db/dao/IpGeoCacheDAO.java
T

117 lines
4.0 KiB
Java

package shine.db.dao;
import shine.db.DbController;
import shine.db.entities.IpGeoCacheEntry;
import java.sql.*;
/**
* DAO для таблицы ip_geo_cache.
*
* Таблица:
* - ip TEXT PRIMARY KEY
* - geo TEXT
* - updated_at_ms INTEGER NOT NULL
*
* Правило:
* - методы с Connection НЕ закрывают соединение
* - методы без Connection сами открывают и закрывают соединение
*/
public final class IpGeoCacheDAO {
private static volatile IpGeoCacheDAO instance;
private final DbController db = DbController.getInstance();
private IpGeoCacheDAO() { }
public static IpGeoCacheDAO getInstance() {
if (instance == null) {
synchronized (IpGeoCacheDAO.class) {
if (instance == null) instance = new IpGeoCacheDAO();
}
}
return instance;
}
// -------------------- UPSERT --------------------
/** UPSERT с внешним соединением. Соединение НЕ закрывает. */
public void upsert(Connection c, IpGeoCacheEntry entry) throws SQLException {
String sql = """
INSERT INTO ip_geo_cache (ip, geo, updated_at_ms)
VALUES (?, ?, ?)
ON CONFLICT(ip)
DO UPDATE SET
geo = excluded.geo,
updated_at_ms = excluded.updated_at_ms
""";
try (PreparedStatement ps = c.prepareStatement(sql)) {
ps.setString(1, entry.getIp());
ps.setString(2, entry.getGeo());
ps.setLong(3, entry.getUpdatedAtMs());
ps.executeUpdate();
}
}
/** UPSERT без внешнего соединения. Сам открывает/закрывает. */
public void upsert(IpGeoCacheEntry entry) throws SQLException {
try (Connection c = db.getConnection()) {
upsert(c, entry);
}
}
// -------------------- SELECT --------------------
/** Получить по IP с внешним соединением. Соединение НЕ закрывает. */
public IpGeoCacheEntry getByIp(Connection c, String ip) throws SQLException {
String sql = """
SELECT ip, geo, updated_at_ms
FROM ip_geo_cache
WHERE ip = ?
""";
try (PreparedStatement ps = c.prepareStatement(sql)) {
ps.setString(1, ip);
try (ResultSet rs = ps.executeQuery()) {
if (!rs.next()) return null;
return mapRow(rs);
}
}
}
/** Получить по IP без внешнего соединения. Сам открывает/закрывает. */
public IpGeoCacheEntry getByIp(String ip) throws SQLException {
try (Connection c = db.getConnection()) {
return getByIp(c, ip);
}
}
// -------------------- DELETE --------------------
/** Удалить старые записи с внешним соединением. Соединение НЕ закрывает. */
public int deleteOlderThan(Connection c, long thresholdMs) throws SQLException {
String sql = "DELETE FROM ip_geo_cache WHERE updated_at_ms < ?";
try (PreparedStatement ps = c.prepareStatement(sql)) {
ps.setLong(1, thresholdMs);
return ps.executeUpdate();
}
}
/** Удалить старые записи без внешнего соединения. Сам открывает/закрывает. */
public int deleteOlderThan(long thresholdMs) throws SQLException {
try (Connection c = db.getConnection()) {
return deleteOlderThan(c, thresholdMs);
}
}
// -------------------- MAPPER --------------------
private IpGeoCacheEntry mapRow(ResultSet rs) throws SQLException {
String ip = rs.getString("ip");
String geo = rs.getString("geo");
long updatedAtMs = rs.getLong("updated_at_ms");
return new IpGeoCacheEntry(ip, geo, updatedAtMs);
}
}