refactor: optimize structure, stability and runtime performance
This commit is contained in:
119
db_pool.py
119
db_pool.py
@@ -7,8 +7,12 @@
|
||||
|
||||
import sqlite3
|
||||
import threading
|
||||
from queue import Queue, Empty
|
||||
import time
|
||||
from queue import Empty, Full, Queue
|
||||
|
||||
from app_logger import get_logger
|
||||
|
||||
|
||||
logger = get_logger("database")
|
||||
|
||||
|
||||
class ConnectionPool:
|
||||
@@ -44,12 +48,55 @@ class ConnectionPool:
|
||||
"""创建新的数据库连接"""
|
||||
conn = sqlite3.connect(self.database, check_same_thread=False)
|
||||
conn.row_factory = sqlite3.Row
|
||||
# 启用外键约束,确保 ON DELETE CASCADE 等约束生效
|
||||
conn.execute("PRAGMA foreign_keys=ON")
|
||||
# 设置WAL模式提高并发性能
|
||||
conn.execute("PRAGMA journal_mode=WAL")
|
||||
# 在WAL模式下使用NORMAL同步,兼顾性能与可靠性
|
||||
conn.execute("PRAGMA synchronous=NORMAL")
|
||||
# 设置合理的超时时间
|
||||
conn.execute("PRAGMA busy_timeout=5000")
|
||||
return conn
|
||||
|
||||
def _close_connection(self, conn) -> None:
|
||||
if conn is None:
|
||||
return
|
||||
try:
|
||||
conn.close()
|
||||
except Exception as e:
|
||||
logger.warning(f"关闭连接失败: {e}")
|
||||
|
||||
def _is_connection_healthy(self, conn) -> bool:
|
||||
if conn is None:
|
||||
return False
|
||||
try:
|
||||
conn.rollback()
|
||||
conn.execute("SELECT 1")
|
||||
return True
|
||||
except sqlite3.Error as e:
|
||||
logger.warning(f"连接健康检查失败(数据库错误): {e}")
|
||||
except Exception as e:
|
||||
logger.warning(f"连接健康检查失败(未知错误): {e}")
|
||||
return False
|
||||
|
||||
def _replenish_pool_if_needed(self) -> None:
|
||||
with self._lock:
|
||||
if self._pool.qsize() >= self.pool_size:
|
||||
return
|
||||
|
||||
new_conn = None
|
||||
try:
|
||||
new_conn = self._create_connection()
|
||||
self._pool.put(new_conn, block=False)
|
||||
self._created_connections += 1
|
||||
except Full:
|
||||
if new_conn:
|
||||
self._close_connection(new_conn)
|
||||
except Exception as e:
|
||||
if new_conn:
|
||||
self._close_connection(new_conn)
|
||||
logger.warning(f"重建连接失败: {e}")
|
||||
|
||||
def get_connection(self):
|
||||
"""
|
||||
从连接池获取连接
|
||||
@@ -70,66 +117,20 @@ class ConnectionPool:
|
||||
Args:
|
||||
conn: 要归还的连接
|
||||
"""
|
||||
import sqlite3
|
||||
from queue import Full
|
||||
|
||||
if conn is None:
|
||||
return
|
||||
|
||||
connection_healthy = False
|
||||
try:
|
||||
# 回滚任何未提交的事务
|
||||
conn.rollback()
|
||||
# 安全修复:验证连接是否健康,防止损坏的连接污染连接池
|
||||
conn.execute("SELECT 1")
|
||||
connection_healthy = True
|
||||
except sqlite3.Error as e:
|
||||
# 数据库相关错误,连接可能损坏
|
||||
print(f"连接健康检查失败(数据库错误): {e}")
|
||||
except Exception as e:
|
||||
print(f"连接健康检查失败(未知错误): {e}")
|
||||
|
||||
if connection_healthy:
|
||||
if self._is_connection_healthy(conn):
|
||||
try:
|
||||
self._pool.put(conn, block=False)
|
||||
return # 成功归还
|
||||
return
|
||||
except Full:
|
||||
# 队列已满(不应该发生,但处理它)
|
||||
print(f"警告: 连接池已满,关闭多余连接")
|
||||
connection_healthy = False # 标记为需要关闭
|
||||
logger.warning("连接池已满,关闭多余连接")
|
||||
self._close_connection(conn)
|
||||
return
|
||||
|
||||
# 连接不健康或队列已满,关闭它
|
||||
try:
|
||||
conn.close()
|
||||
except Exception as close_error:
|
||||
print(f"关闭连接失败: {close_error}")
|
||||
|
||||
# 如果连接不健康,尝试创建新连接补充池
|
||||
if not connection_healthy:
|
||||
with self._lock:
|
||||
# 双重检查:确保池确实需要补充
|
||||
if self._pool.qsize() < self.pool_size:
|
||||
new_conn = None
|
||||
try:
|
||||
new_conn = self._create_connection()
|
||||
self._pool.put(new_conn, block=False)
|
||||
# 只有成功放入池后才增加计数
|
||||
self._created_connections += 1
|
||||
except Full:
|
||||
# 在获取锁期间池被填满了,关闭新建的连接
|
||||
if new_conn:
|
||||
try:
|
||||
new_conn.close()
|
||||
except Exception:
|
||||
pass
|
||||
except Exception as create_error:
|
||||
# 创建连接失败,确保关闭已创建的连接
|
||||
if new_conn:
|
||||
try:
|
||||
new_conn.close()
|
||||
except Exception:
|
||||
pass
|
||||
print(f"重建连接失败: {create_error}")
|
||||
self._close_connection(conn)
|
||||
self._replenish_pool_if_needed()
|
||||
|
||||
def close_all(self):
|
||||
"""关闭所有连接"""
|
||||
@@ -138,7 +139,7 @@ class ConnectionPool:
|
||||
conn = self._pool.get(block=False)
|
||||
conn.close()
|
||||
except Exception as e:
|
||||
print(f"关闭连接失败: {e}")
|
||||
logger.warning(f"关闭连接失败: {e}")
|
||||
|
||||
def get_stats(self):
|
||||
"""获取连接池统计信息"""
|
||||
@@ -175,14 +176,14 @@ class PooledConnection:
|
||||
if exc_type is not None:
|
||||
# 发生异常,回滚事务
|
||||
self._conn.rollback()
|
||||
print(f"数据库事务已回滚: {exc_type.__name__}")
|
||||
logger.warning(f"数据库事务已回滚: {exc_type.__name__}")
|
||||
# 注意: 不自动commit,要求用户显式调用conn.commit()
|
||||
|
||||
if self._cursor:
|
||||
self._cursor.close()
|
||||
self._cursor = None
|
||||
except Exception as e:
|
||||
print(f"关闭游标失败: {e}")
|
||||
logger.warning(f"关闭游标失败: {e}")
|
||||
finally:
|
||||
# 归还连接
|
||||
self._pool.return_connection(self._conn)
|
||||
@@ -254,7 +255,7 @@ def init_pool(database, pool_size=5):
|
||||
with _pool_lock:
|
||||
if _pool is None:
|
||||
_pool = ConnectionPool(database, pool_size)
|
||||
print(f"[OK] 数据库连接池已初始化 (大小: {pool_size})")
|
||||
logger.info(f"[OK] 数据库连接池已初始化 (大小: {pool_size})")
|
||||
|
||||
|
||||
def get_db():
|
||||
|
||||
Reference in New Issue
Block a user