import logging from typing import Any, List, Optional import psycopg2 from psycopg2.extras import RealDictCursor from config.settings import settings logger = logging.getLogger(__name__) class Database: _instance: Optional['Database'] = None _conn = None def __new__(cls): if cls._instance is None: cls._instance = super().__new__(cls) cls._instance._connect() return cls._instance def _connect(self): config = settings.db_config self._conn = psycopg2.connect( host=config["host"], port=config["port"], database=config["database"], user=config["user"], password=config["password"], cursor_factory=RealDictCursor, ) self._conn.autocommit = True logger.info(f"数据库连接成功: {config['host']}:{config['port']}/{config['database']}") def query(self, sql: str, params: tuple = ()) -> List[dict]: with self._conn.cursor() as cur: cur.execute(sql, params) return cur.fetchall() def query_one(self, sql: str, params: tuple = ()) -> Optional[dict]: rows = self.query(sql, params) return rows[0] if rows else None def scalar(self, sql: str, params: tuple = ()) -> Any: with self._conn.cursor() as cur: cur.execute(sql, params) row = cur.fetchone() if row: return list(row.values())[0] return None def execute(self, sql: str, params: tuple = ()) -> int: with self._conn.cursor() as cur: cur.execute(sql, params) return cur.rowcount def execute_many(self, sql: str, params_list: List[tuple]) -> int: with self._conn.cursor() as cur: cur.executemany(sql, params_list) return cur.rowcount def close(self): if self._conn: self._conn.close() logger.info("数据库连接已关闭") def get_db() -> Database: return Database()