Все ДАО получили перезагруженный метод для того что бы вызываться с передачей соединения и без передачи соединия
This commit is contained in:
AidarKC 2025-12-18 15:58:43 +03:00
parent 1b1da19d3d
commit d6d2bfeb73
6 changed files with 250 additions and 127 deletions

View File

@ -9,6 +9,10 @@ import java.util.List;
/**
* DAO для таблицы active_sessions.
*
* Правило:
* - методы с Connection НЕ закрывают соединение
* - методы без Connection сами открывают и закрывают соединение
*/
public final class ActiveSessionsDAO {
@ -26,7 +30,10 @@ public final class ActiveSessionsDAO {
return instance;
}
public void insert(ActiveSessionEntry session) throws SQLException {
// -------------------- INSERT --------------------
/** Вставка с внешним соединением. Соединение НЕ закрывает. */
public void insert(Connection c, ActiveSessionEntry session) throws SQLException {
String sql = """
INSERT INTO active_sessions (
sessionId,
@ -45,9 +52,7 @@ public final class ActiveSessionsDAO {
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
""";
try (Connection c = db.getConnection();
PreparedStatement ps = c.prepareStatement(sql)) {
try (PreparedStatement ps = c.prepareStatement(sql)) {
ps.setString(1, session.getSessionId());
ps.setLong(2, session.getLoginId());
ps.setString(3, session.getSessionPwd());
@ -61,12 +66,21 @@ public final class ActiveSessionsDAO {
ps.setString(11, session.getClientInfoFromClient());
ps.setString(12, session.getClientInfoFromRequest());
ps.setString(13, session.getUserLanguage());
ps.executeUpdate();
}
}
public ActiveSessionEntry getBySessionId(String sessionId) throws SQLException {
/** Вставка без внешнего соединения. Сам открывает/закрывает. */
public void insert(ActiveSessionEntry session) throws SQLException {
try (Connection c = db.getConnection()) {
insert(c, session);
}
}
// -------------------- SELECT --------------------
/** Получить по sessionId с внешним соединением. Соединение НЕ закрывает. */
public ActiveSessionEntry getBySessionId(Connection c, String sessionId) throws SQLException {
String sql = """
SELECT
sessionId,
@ -86,11 +100,8 @@ public final class ActiveSessionsDAO {
WHERE sessionId = ?
""";
try (Connection c = db.getConnection();
PreparedStatement ps = c.prepareStatement(sql)) {
try (PreparedStatement ps = c.prepareStatement(sql)) {
ps.setString(1, sessionId);
try (ResultSet rs = ps.executeQuery()) {
if (!rs.next()) return null;
return mapRow(rs);
@ -98,7 +109,15 @@ public final class ActiveSessionsDAO {
}
}
public List<ActiveSessionEntry> getByLoginId(long loginId) throws SQLException {
/** Получить по sessionId без внешнего соединения. Сам открывает/закрывает. */
public ActiveSessionEntry getBySessionId(String sessionId) throws SQLException {
try (Connection c = db.getConnection()) {
return getBySessionId(c, sessionId);
}
}
/** Получить список по loginId с внешним соединением. Соединение НЕ закрывает. */
public List<ActiveSessionEntry> getByLoginId(Connection c, long loginId) throws SQLException {
String sql = """
SELECT
sessionId,
@ -120,11 +139,8 @@ public final class ActiveSessionsDAO {
List<ActiveSessionEntry> result = new ArrayList<>();
try (Connection c = db.getConnection();
PreparedStatement ps = c.prepareStatement(sql)) {
try (PreparedStatement ps = c.prepareStatement(sql)) {
ps.setLong(1, loginId);
try (ResultSet rs = ps.executeQuery()) {
while (rs.next()) result.add(mapRow(rs));
}
@ -133,23 +149,40 @@ public final class ActiveSessionsDAO {
return result;
}
public void updateLastAuthirificatedAtMs(String sessionId, long lastAuthMs) throws SQLException {
/** Получить список по loginId без внешнего соединения. Сам открывает/закрывает. */
public List<ActiveSessionEntry> getByLoginId(long loginId) throws SQLException {
try (Connection c = db.getConnection()) {
return getByLoginId(c, loginId);
}
}
// -------------------- UPDATE --------------------
/** Обновить lastAuthirificatedAtMs с внешним соединением. Соединение НЕ закрывает. */
public void updateLastAuthirificatedAtMs(Connection c, String sessionId, long lastAuthMs) throws SQLException {
String sql = """
UPDATE active_sessions
SET lastAuthirificatedAtMs = ?
WHERE sessionId = ?
""";
try (Connection c = db.getConnection();
PreparedStatement ps = c.prepareStatement(sql)) {
try (PreparedStatement ps = c.prepareStatement(sql)) {
ps.setLong(1, lastAuthMs);
ps.setString(2, sessionId);
ps.executeUpdate();
}
}
/** Обновить lastAuthirificatedAtMs без внешнего соединения. Сам открывает/закрывает. */
public void updateLastAuthirificatedAtMs(String sessionId, long lastAuthMs) throws SQLException {
try (Connection c = db.getConnection()) {
updateLastAuthirificatedAtMs(c, sessionId, lastAuthMs);
}
}
/** Обновить данные refresh с внешним соединением. Соединение НЕ закрывает. */
public void updateOnRefresh(
Connection c,
String sessionId,
long lastAuthMs,
String clientIp,
@ -169,9 +202,7 @@ public final class ActiveSessionsDAO {
WHERE sessionId = ?
""";
try (Connection c = db.getConnection();
PreparedStatement ps = c.prepareStatement(sql)) {
try (PreparedStatement ps = c.prepareStatement(sql)) {
ps.setLong(1, lastAuthMs);
ps.setString(2, clientIp);
ps.setString(3, clientInfoFromClient);
@ -182,17 +213,41 @@ public final class ActiveSessionsDAO {
}
}
public void deleteBySessionId(String sessionId) throws SQLException {
/** Обновить данные refresh без внешнего соединения. Сам открывает/закрывает. */
public void updateOnRefresh(
String sessionId,
long lastAuthMs,
String clientIp,
String clientInfoFromClient,
String clientInfoFromRequest,
String userLanguage
) throws SQLException {
try (Connection c = db.getConnection()) {
updateOnRefresh(c, sessionId, lastAuthMs, clientIp, clientInfoFromClient, clientInfoFromRequest, userLanguage);
}
}
// -------------------- DELETE --------------------
/** Удалить по sessionId с внешним соединением. Соединение НЕ закрывает. */
public void deleteBySessionId(Connection c, String sessionId) throws SQLException {
String sql = "DELETE FROM active_sessions WHERE sessionId = ?";
try (Connection c = db.getConnection();
PreparedStatement ps = c.prepareStatement(sql)) {
try (PreparedStatement ps = c.prepareStatement(sql)) {
ps.setString(1, sessionId);
ps.executeUpdate();
}
}
/** Удалить по sessionId без внешнего соединения. Сам открывает/закрывает. */
public void deleteBySessionId(String sessionId) throws SQLException {
try (Connection c = db.getConnection()) {
deleteBySessionId(c, sessionId);
}
}
// -------------------- MAPPER --------------------
private ActiveSessionEntry mapRow(ResultSet rs) throws SQLException {
String sessionId = rs.getString("sessionId");
long loginId = rs.getLong("loginId");

View File

@ -21,12 +21,14 @@ public final class BlockchainStateDAO {
return instance;
}
/** Получить по blockchainId без внешнего соединения. Сам открывает/закрывает. */
public BlockchainStateEntry getByBlockchainId(long blockchainId) throws SQLException {
try (Connection c = db.getConnection()) {
return getByBlockchainId(c, blockchainId);
}
}
/** Получить по blockchainId с внешним соединением. Соединение НЕ закрывает. */
public BlockchainStateEntry getByBlockchainId(Connection c, long blockchainId) throws SQLException {
String sql = """
SELECT
@ -60,12 +62,14 @@ public final class BlockchainStateDAO {
}
}
/** UPSERT без внешнего соединения. Сам открывает/закрывает. */
public void upsert(BlockchainStateEntry e) throws SQLException {
try (Connection c = db.getConnection()) {
upsert(c, e);
}
}
/** UPSERT с внешним соединением. Соединение НЕ закрывает. */
public void upsert(Connection c, BlockchainStateEntry e) throws SQLException {
String sql = """
INSERT INTO blockchain_state (
@ -87,7 +91,7 @@ public final class BlockchainStateDAO {
line7_last_number, line7_last_hash,
updated_at_ms
) VALUES (
?,?,?,?,?,?,?,?, -- было 7, стало 8
?,?,?,?,?,?,?,?,
?,?,
?,?,
?,?,

View File

@ -8,36 +8,35 @@ import java.sql.*;
/**
* DAO для таблицы ip_geo_cache.
*
* Таблица:
* - ip TEXT PRIMARY KEY
* - geo TEXT
* - updated_at_ms INTEGER NOT NULL
* * Таблица:
* * - 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 SqliteDbController db = SqliteDbController.getInstance();
private IpGeoCacheDAO() {
}
private IpGeoCacheDAO() { }
public static IpGeoCacheDAO getInstance() {
if (instance == null) {
synchronized (IpGeoCacheDAO.class) {
if (instance == null) {
instance = new IpGeoCacheDAO();
}
if (instance == null) instance = new IpGeoCacheDAO();
}
}
return instance;
}
/**
* UPSERT по ip.
* Если записи нет вставляем.
* Если есть обновляем geo и updated_at_ms.
*/
public void upsert(IpGeoCacheEntry entry) throws SQLException {
// -------------------- UPSERT --------------------
/** UPSERT с внешним соединением. Соединение НЕ закрывает. */
public void upsert(Connection c, IpGeoCacheEntry entry) throws SQLException {
String sql = """
INSERT INTO ip_geo_cache (ip, geo, updated_at_ms)
VALUES (?, ?, ?)
@ -47,9 +46,7 @@ public final class IpGeoCacheDAO {
updated_at_ms = excluded.updated_at_ms
""";
try (Connection c = db.getConnection();
PreparedStatement ps = c.prepareStatement(sql)) {
try (PreparedStatement ps = c.prepareStatement(sql)) {
ps.setString(1, entry.getIp());
ps.setString(2, entry.getGeo());
ps.setLong(3, entry.getUpdatedAtMs());
@ -57,45 +54,60 @@ public final class IpGeoCacheDAO {
}
}
/**
* Получить запись по IP.
* Если нет возвращает null.
*/
public IpGeoCacheEntry getByIp(String ip) throws SQLException {
/** 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 (Connection c = db.getConnection();
PreparedStatement ps = c.prepareStatement(sql)) {
try (PreparedStatement ps = c.prepareStatement(sql)) {
ps.setString(1, ip);
try (ResultSet rs = ps.executeQuery()) {
if (!rs.next()) {
return null;
}
if (!rs.next()) return null;
return mapRow(rs);
}
}
}
/**
* Опционально очистка старых записей.
* Можно вызывать по расписанию, если нужно.
*/
public int deleteOlderThan(long thresholdMs) throws SQLException {
/** Получить по 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 (Connection c = db.getConnection();
PreparedStatement ps = c.prepareStatement(sql)) {
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");

View File

@ -17,6 +17,10 @@ import java.util.List;
* - loginKey TEXT
* - deviceKey TEXT
* - bchLimit INTEGER (может быть NULL)
*
* * Правило:
* * - методы с Connection НЕ закрывают соединение
* * - методы без Connection сами открывают и закрывают соединение
*/
public final class SolanaUsersDAO {
@ -28,23 +32,22 @@ public final class SolanaUsersDAO {
public static SolanaUsersDAO getInstance() {
if (instance == null) {
synchronized (SolanaUsersDAO.class) {
if (instance == null) {
instance = new SolanaUsersDAO();
}
if (instance == null) instance = new SolanaUsersDAO();
}
}
return instance;
}
public void insert(SolanaUserEntry user) throws SQLException {
// -------------------- INSERT --------------------
/** Вставка с внешним соединением. Соединение НЕ закрывает. */
public void insert(Connection c, SolanaUserEntry user) throws SQLException {
String sql = """
INSERT INTO solana_users (login, loginId, bchId, loginKey, deviceKey, bchLimit)
VALUES (?, ?, ?, ?, ?, ?)
""";
try (Connection c = db.getConnection();
PreparedStatement ps = c.prepareStatement(sql)) {
try (PreparedStatement ps = c.prepareStatement(sql)) {
ps.setString(1, user.getLogin());
ps.setLong(2, user.getLoginId());
ps.setLong(3, user.getBchId());
@ -61,16 +64,24 @@ public final class SolanaUsersDAO {
}
}
public SolanaUserEntry getByLoginId(long loginId) throws SQLException {
/** Вставка без внешнего соединения. Сам открывает/закрывает. */
public void insert(SolanaUserEntry user) throws SQLException {
try (Connection c = db.getConnection()) {
insert(c, user);
}
}
// -------------------- SELECT --------------------
/** Получить по loginId с внешним соединением. Соединение НЕ закрывает. */
public SolanaUserEntry getByLoginId(Connection c, long loginId) throws SQLException {
String sql = """
SELECT login, loginId, bchId, loginKey, deviceKey, bchLimit
FROM solana_users
WHERE loginId = ?
""";
try (Connection c = db.getConnection();
PreparedStatement ps = c.prepareStatement(sql)) {
try (PreparedStatement ps = c.prepareStatement(sql)) {
ps.setLong(1, loginId);
try (ResultSet rs = ps.executeQuery()) {
if (!rs.next()) return null;
@ -79,7 +90,14 @@ public final class SolanaUsersDAO {
}
}
// добавь рядом со старым методом
/** Получить по loginId без внешнего соединения. Сам открывает/закрывает. */
public SolanaUserEntry getByLoginId(long loginId) throws SQLException {
try (Connection c = db.getConnection()) {
return getByLoginId(c, loginId);
}
}
/** Получить по login (case-insensitive) с внешним соединением. Соединение НЕ закрывает. */
public SolanaUserEntry getByLogin(Connection c, String login) throws SQLException {
String sql = """
SELECT login, loginId, bchId, loginKey, deviceKey, bchLimit
@ -96,25 +114,15 @@ public final class SolanaUsersDAO {
}
}
/** Получить по login (case-insensitive) без внешнего соединения. Сам открывает/закрывает. */
public SolanaUserEntry getByLogin(String login) throws SQLException {
String sql = """
SELECT login, loginId, bchId, loginKey, deviceKey, bchLimit
FROM solana_users
WHERE LOWER(login) = LOWER(?)
""";
try (Connection c = db.getConnection();
PreparedStatement ps = c.prepareStatement(sql)) {
ps.setString(1, login);
try (ResultSet rs = ps.executeQuery()) {
if (!rs.next()) return null;
return mapRow(rs);
}
try (Connection c = db.getConnection()) {
return getByLogin(c, login);
}
}
public List<SolanaUserEntry> searchByLoginPrefix(String prefix) throws SQLException {
/** Поиск по префиксу с внешним соединением. Соединение НЕ закрывает. */
public List<SolanaUserEntry> searchByLoginPrefix(Connection c, String prefix) throws SQLException {
String sql = """
SELECT login, loginId, bchId, loginKey, deviceKey, bchLimit
FROM solana_users
@ -125,9 +133,7 @@ public final class SolanaUsersDAO {
List<SolanaUserEntry> result = new ArrayList<>();
try (Connection c = db.getConnection();
PreparedStatement ps = c.prepareStatement(sql)) {
try (PreparedStatement ps = c.prepareStatement(sql)) {
ps.setString(1, prefix.toLowerCase() + "%");
try (ResultSet rs = ps.executeQuery()) {
while (rs.next()) result.add(mapRow(rs));
@ -137,6 +143,15 @@ public final class SolanaUsersDAO {
return result;
}
/** Поиск по префиксу без внешнего соединения. Сам открывает/закрывает. */
public List<SolanaUserEntry> searchByLoginPrefix(String prefix) throws SQLException {
try (Connection c = db.getConnection()) {
return searchByLoginPrefix(c, prefix);
}
}
// -------------------- MAPPER --------------------
private SolanaUserEntry mapRow(ResultSet rs) throws SQLException {
return new SolanaUserEntry(
rs.getLong("loginId"),

View File

@ -7,32 +7,27 @@ import java.sql.*;
import java.util.ArrayList;
import java.util.List;
/** Здесь зраним сохранённые параметры пользователей (в основном до каково сообщения просмотрены ленты) */
/** Здесь храним сохранённые параметры пользователей (в основном до какого сообщения просмотрены ленты) */
public final class UserParamsDAO {
private static volatile UserParamsDAO instance;
private final SqliteDbController db = SqliteDbController.getInstance();
private UserParamsDAO() {
}
private UserParamsDAO() { }
public static UserParamsDAO getInstance() {
if (instance == null) {
synchronized (UserParamsDAO.class) {
if (instance == null) {
instance = new UserParamsDAO();
}
if (instance == null) instance = new UserParamsDAO();
}
}
return instance;
}
/**
* UPSERT методом ON CONFLICT одним SQL-запросом.
* Если запись существует -> обновляем поля.
* Если нет -> вставляем новую запись.
*/
public void upsert(UserParamEntry param) throws SQLException {
// -------------------- UPSERT --------------------
/** UPSERT с внешним соединением. Соединение НЕ закрывает. */
public void upsert(Connection c, UserParamEntry param) throws SQLException {
String sql = """
INSERT INTO users_params (
loginId,
@ -52,9 +47,7 @@ public final class UserParamsDAO {
signature = excluded.signature
""";
try (Connection c = db.getConnection();
PreparedStatement ps = c.prepareStatement(sql)) {
try (PreparedStatement ps = c.prepareStatement(sql)) {
ps.setLong(1, param.getLoginId());
ps.setString(2, param.getParam());
ps.setLong(3, param.getBchChannelId());
@ -66,10 +59,17 @@ public final class UserParamsDAO {
}
}
/**
* Получить параметр по loginId + param.
*/
public UserParamEntry getByUserIdAndParam(long loginId, String paramName) throws SQLException {
/** UPSERT без внешнего соединения. Сам открывает/закрывает. */
public void upsert(UserParamEntry param) throws SQLException {
try (Connection c = db.getConnection()) {
upsert(c, param);
}
}
// -------------------- SELECT --------------------
/** Получить параметр с внешним соединением. Соединение НЕ закрывает. */
public UserParamEntry getByUserIdAndParam(Connection c, long loginId, String paramName) throws SQLException {
String sql = """
SELECT
loginId,
@ -83,9 +83,7 @@ public final class UserParamsDAO {
WHERE loginId = ? AND param = ?
""";
try (Connection c = db.getConnection();
PreparedStatement ps = c.prepareStatement(sql)) {
try (PreparedStatement ps = c.prepareStatement(sql)) {
ps.setLong(1, loginId);
ps.setString(2, paramName);
try (ResultSet rs = ps.executeQuery()) {
@ -95,10 +93,15 @@ public final class UserParamsDAO {
}
}
/**
* Получить все параметры пользователя.
*/
public List<UserParamEntry> getByUserId(long loginId) throws SQLException {
/** Получить параметр без внешнего соединения. Сам открывает/закрывает. */
public UserParamEntry getByUserIdAndParam(long loginId, String paramName) throws SQLException {
try (Connection c = db.getConnection()) {
return getByUserIdAndParam(c, loginId, paramName);
}
}
/** Получить все параметры пользователя с внешним соединением. Соединение НЕ закрывает. */
public List<UserParamEntry> getByUserId(Connection c, long loginId) throws SQLException {
String sql = """
SELECT
loginId,
@ -115,9 +118,7 @@ public final class UserParamsDAO {
List<UserParamEntry> result = new ArrayList<>();
try (Connection c = db.getConnection();
PreparedStatement ps = c.prepareStatement(sql)) {
try (PreparedStatement ps = c.prepareStatement(sql)) {
ps.setLong(1, loginId);
try (ResultSet rs = ps.executeQuery()) {
while (rs.next()) result.add(mapRow(rs));
@ -127,6 +128,15 @@ public final class UserParamsDAO {
return result;
}
/** Получить все параметры пользователя без внешнего соединения. Сам открывает/закрывает. */
public List<UserParamEntry> getByUserId(long loginId) throws SQLException {
try (Connection c = db.getConnection()) {
return getByUserId(c, loginId);
}
}
// -------------------- MAPPER --------------------
private UserParamEntry mapRow(ResultSet rs) throws SQLException {
return new UserParamEntry(
rs.getLong("loginId"),

View File

@ -0,0 +1,27 @@
DAO: правило перегруженных методов (короткая справка)
1) Всегда два метода:
insert(Connection c, …) // не закрывает соединение, не коммитит
insert(…) // открывает своё соединение и сам закрывает
2) Внутри одного бизнес-метода:
открываем одно соединение conn = db.getConnection();
делаем несколько DAO-вызовов через версии с Connection
в конце вручную conn.commit();
conn закрываем только один раз в finally
3) DAO-методы с Connection:
не создают соединение
не закрывают соединение
не делают commit/rollback
4) DAO-методы без Connection:
маленькие удобные обёртки
открывают соединение в try-with-resources
внутри вызывают версию с Connection
5) Итог:
одиночные операции → вызываем короткий метод без Connection
пакетные/атомарные операции → берём одно соединение и используем только методы с Connection