118 lines
5.0 KiB
Python
118 lines
5.0 KiB
Python
import os
|
||
from typing import Optional
|
||
|
||
import aiosqlite
|
||
from logs.custom_logger import logger
|
||
|
||
|
||
class DatabaseConnection:
|
||
"""Базовый класс для работы с базой данных."""
|
||
|
||
def __init__(self, db_path: str):
|
||
self.db_path = os.path.abspath(db_path)
|
||
self.logger = logger
|
||
self.logger.info(f"Инициация базы данных: {self.db_path}")
|
||
|
||
async def _get_connection(self):
|
||
"""Получение асинхронного соединения с базой данных."""
|
||
try:
|
||
conn = await aiosqlite.connect(self.db_path)
|
||
# Включаем поддержку внешних ключей
|
||
await conn.execute("PRAGMA foreign_keys = ON")
|
||
# Включаем WAL режим для лучшей производительности
|
||
await conn.execute("PRAGMA journal_mode = WAL")
|
||
await conn.execute("PRAGMA synchronous = NORMAL")
|
||
await conn.execute("PRAGMA cache_size = 10000")
|
||
await conn.execute("PRAGMA temp_store = MEMORY")
|
||
return conn
|
||
except Exception as e:
|
||
self.logger.error(f"Ошибка при получении соединения: {e}")
|
||
raise
|
||
|
||
async def _execute_query(self, query: str, params: tuple = ()):
|
||
"""Выполнение запроса с автоматическим закрытием соединения."""
|
||
conn = None
|
||
try:
|
||
conn = await self._get_connection()
|
||
result = await conn.execute(query, params)
|
||
await conn.commit()
|
||
return result
|
||
except Exception as e:
|
||
self.logger.error(f"Ошибка при выполнении запроса: {e}")
|
||
raise
|
||
finally:
|
||
if conn:
|
||
await conn.close()
|
||
|
||
async def _execute_query_with_result(self, query: str, params: tuple = ()):
|
||
"""Выполнение запроса с результатом и автоматическим закрытием соединения."""
|
||
conn = None
|
||
try:
|
||
conn = await self._get_connection()
|
||
result = await conn.execute(query, params)
|
||
# Получаем все результаты сразу, чтобы можно было закрыть соединение
|
||
rows = await result.fetchall()
|
||
return rows
|
||
except Exception as e:
|
||
self.logger.error(f"Ошибка при выполнении запроса: {e}")
|
||
raise
|
||
finally:
|
||
if conn:
|
||
await conn.close()
|
||
|
||
async def _execute_transaction(self, queries: list):
|
||
"""Выполнение транзакции с несколькими запросами."""
|
||
conn = None
|
||
try:
|
||
conn = await self._get_connection()
|
||
for query, params in queries:
|
||
await conn.execute(query, params)
|
||
await conn.commit()
|
||
except Exception as e:
|
||
if conn:
|
||
await conn.rollback()
|
||
self.logger.error(f"Ошибка при выполнении транзакции: {e}")
|
||
raise
|
||
finally:
|
||
if conn:
|
||
await conn.close()
|
||
|
||
async def check_database_integrity(self):
|
||
"""Проверяет целостность базы данных и очищает WAL файлы."""
|
||
conn = None
|
||
try:
|
||
conn = await self._get_connection()
|
||
result = await conn.execute("PRAGMA integrity_check")
|
||
integrity_result = await result.fetchone()
|
||
|
||
if integrity_result and integrity_result[0] == "ok":
|
||
self.logger.info("Проверка целостности базы данных прошла успешно")
|
||
await conn.execute("PRAGMA wal_checkpoint(TRUNCATE)")
|
||
self.logger.info("WAL файлы очищены")
|
||
else:
|
||
self.logger.warning(
|
||
f"Проблемы с целостностью базы данных: {integrity_result}"
|
||
)
|
||
|
||
except Exception as e:
|
||
self.logger.error(f"Ошибка при проверке целостности базы данных: {e}")
|
||
raise
|
||
finally:
|
||
if conn:
|
||
await conn.close()
|
||
|
||
async def cleanup_wal_files(self):
|
||
"""Очищает WAL файлы и переключает на DELETE режим для предотвращения проблем с I/O."""
|
||
conn = None
|
||
try:
|
||
conn = await self._get_connection()
|
||
await conn.execute("PRAGMA journal_mode=DELETE")
|
||
await conn.execute("PRAGMA journal_mode=WAL")
|
||
self.logger.info("WAL файлы очищены и режим восстановлен")
|
||
except Exception as e:
|
||
self.logger.error(f"Ошибка при очистке WAL файлов: {e}")
|
||
raise
|
||
finally:
|
||
if conn:
|
||
await conn.close()
|