This commit is contained in:
aaron 2025-03-12 15:48:33 +08:00
parent 861d5258fb
commit e81a69e2e6
3 changed files with 61 additions and 9 deletions

View File

@ -56,6 +56,7 @@ class CouponInfo(BaseModel):
id: int
name: str
amount: float
expire_time: datetime
coupon_type: CouponType
create_time: datetime

View File

@ -1,4 +1,4 @@
from sqlalchemy import create_engine, event
from sqlalchemy import create_engine, event, text
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, scoped_session
from app.core.config import settings
@ -22,7 +22,15 @@ engine = create_engine(
pool_size=10, # 连接池大小
max_overflow=20, # 允许的最大连接数超出pool_size的数量
pool_timeout=30, # 获取连接的超时时间(秒)
echo_pool=settings.DEBUG # 在调试模式下记录连接池事件
echo_pool=settings.DEBUG, # 在调试模式下记录连接池事件
# 添加以下参数以增强连接稳定性
pool_reset_on_return='commit', # 在连接返回池时重置连接状态
isolation_level='READ COMMITTED', # 设置事务隔离级别
connect_args={
'connect_timeout': 10, # 连接超时时间(秒)
'read_timeout': 30, # 读取超时时间(秒)
'write_timeout': 30 # 写入超时时间(秒)
}
)
# 创建线程安全的会话工厂
@ -59,10 +67,14 @@ def checkout(dbapi_connection, connection_record, connection_proxy):
# 执行简单查询测试连接
cursor = dbapi_connection.cursor()
cursor.execute("SELECT 1")
cursor.fetchone() # 确保实际获取结果
cursor.close()
except Exception as e:
# 如果连接无效,断开它
# 如果连接无效,断开它并尝试重新连接
logger.warning(f"检测到无效的数据库连接: {str(e)}")
# 标记连接为无效
connection_record.invalidate()
# 强制处理连接池
connection_proxy._pool.dispose()
raise
@ -113,7 +125,25 @@ def after_cursor_execute(conn, cursor, statement, parameters, context, executema
def get_db():
"""获取数据库会话"""
session_id = threading.get_ident()
session = SessionLocal()
db = None
retry_count = 0
max_retries = 3
while retry_count < max_retries:
try:
db = SessionLocal()
# 测试连接是否有效
db.execute(text("SELECT 1"))
break
except Exception as e:
retry_count += 1
if db:
db.close()
if retry_count >= max_retries:
logger.error(f"无法建立数据库连接,已重试 {retry_count} 次: {str(e)}")
raise
logger.warning(f"数据库连接失败,正在重试 ({retry_count}/{max_retries}): {str(e)}")
time.sleep(0.5) # 短暂延迟后重试
# 记录活跃会话
with session_lock:
@ -123,10 +153,11 @@ def get_db():
}
try:
yield session
yield db
finally:
# 关闭会话并从活跃会话中移除
session.close()
if db:
db.close()
with session_lock:
if session_id in active_sessions:
del active_sessions[session_id]
@ -134,9 +165,27 @@ def get_db():
@contextmanager
def get_db_context():
"""上下文管理器版本的get_db用于非依赖项场景"""
session = SessionLocal()
session = None
retry_count = 0
max_retries = 3
session_id = threading.get_ident()
while retry_count < max_retries:
try:
session = SessionLocal()
# 测试连接是否有效
session.execute(text("SELECT 1"))
break
except Exception as e:
retry_count += 1
if session:
session.close()
if retry_count >= max_retries:
logger.error(f"无法建立数据库连接,已重试 {retry_count} 次: {str(e)}")
raise
logger.warning(f"数据库连接失败,正在重试 ({retry_count}/{max_retries}): {str(e)}")
time.sleep(0.5) # 短暂延迟后重试
# 记录活跃会话
with session_lock:
active_sessions[session_id] = {
@ -148,10 +197,12 @@ def get_db_context():
yield session
session.commit()
except Exception as e:
session.rollback()
if session:
session.rollback()
raise e
finally:
session.close()
if session:
session.close()
with session_lock:
if session_id in active_sessions:
del active_sessions[session_id]

Binary file not shown.