TravelContentCreator/api/services/database_service.py
2025-07-25 17:13:37 +08:00

1093 lines
35 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
数据库服务层
负责景区、产品、风格、受众等数据的查询和管理
"""
import logging
import time
import traceback
from typing import Dict, Any, Optional, List, Tuple
import mysql.connector
from mysql.connector import pooling
from core.config import ConfigManager
logger = logging.getLogger(__name__)
class DatabaseService:
"""数据库服务类"""
def __init__(self, config_manager: ConfigManager):
"""
初始化数据库服务
Args:
config_manager: 配置管理器
"""
self.config_manager = config_manager
self.db_pool = self._init_db_pool()
def _init_db_pool(self):
"""初始化数据库连接池"""
# 获取数据库配置
raw_db_config = self.config_manager.get_raw_config('database')
# 处理环境变量
db_config = self._process_env_vars(raw_db_config)
# 连接尝试配置
connection_attempts = [
{"desc": "使用配置文件中的设置", "config": db_config},
{"desc": "使用明确的密码", "config": {**db_config, "password": "password"}},
{"desc": "使用空密码", "config": {**db_config, "password": ""}},
{"desc": "使用auth_plugin", "config": {**db_config, "auth_plugin": "mysql_native_password"}}
]
# 尝试不同的连接方式
for attempt in connection_attempts:
try:
# 打印连接信息(不包含密码)
connection_info = {k: v for k, v in attempt["config"].items() if k != 'password'}
logger.info(f"尝试连接数据库 ({attempt['desc']}): {connection_info}")
# 创建连接池
pool = pooling.MySQLConnectionPool(
pool_name=f"database_service_pool_{int(time.time())}",
pool_size=10,
**attempt["config"]
)
# 测试连接
with pool.get_connection() as conn:
cursor = conn.cursor()
cursor.execute("SELECT 1")
cursor.fetchall()
logger.info(f"数据库连接池初始化成功 ({attempt['desc']})")
return pool
except Exception as e:
error_details = traceback.format_exc()
logger.error(f"数据库连接尝试 ({attempt['desc']}) 失败: {e}\n{error_details}")
logger.error("所有数据库连接尝试都失败了")
return None
def _process_env_vars(self, config: Dict[str, Any]) -> Dict[str, Any]:
"""处理环境变量"""
import os
processed_config = {}
for key, value in config.items():
if isinstance(value, str) and value.startswith("${") and value.endswith("}"):
env_var = value[2:-1]
processed_config[key] = os.environ.get(env_var, "")
else:
processed_config[key] = value
return processed_config
def get_scenic_spot_by_id(self, spot_id: int) -> Optional[Dict[str, Any]]:
"""
根据ID获取景区信息
Args:
spot_id: 景区ID
Returns:
景区信息字典如果未找到则返回None
"""
if not self.db_pool:
logger.error("数据库连接池未初始化")
return None
try:
conn = self.db_pool.get_connection()
cursor = conn.cursor(dictionary=True)
cursor.execute(
"SELECT * FROM scenicSpot WHERE id = %s AND isDelete = 0",
(spot_id,)
)
result = cursor.fetchone()
cursor.close()
conn.close()
if result:
logger.info(f"找到景区信息: ID={spot_id}, 名称={result['name']}")
return result
else:
logger.warning(f"未找到景区信息: ID={spot_id}")
return None
except Exception as e:
logger.error(f"查询景区信息失败: {e}")
return None
def get_product_by_id(self, product_id: int) -> Optional[Dict[str, Any]]:
"""
根据ID获取产品信息
Args:
product_id: 产品ID
Returns:
产品信息字典如果未找到则返回None
"""
if not self.db_pool:
logger.error("数据库连接池未初始化")
return None
try:
conn = self.db_pool.get_connection()
cursor = conn.cursor(dictionary=True)
cursor.execute(
"SELECT * FROM product WHERE id = %s AND isDelete = 0",
(product_id,)
)
result = cursor.fetchone()
cursor.close()
conn.close()
if result:
logger.info(f"找到产品信息: ID={product_id}, 名称={result['productName']}")
return result
else:
logger.warning(f"未找到产品信息: ID={product_id}")
return None
except Exception as e:
logger.error(f"查询产品信息失败: {e}")
return None
def get_style_by_id(self, style_id: int) -> Optional[Dict[str, Any]]:
"""
根据ID获取风格信息
Args:
style_id: 风格ID
Returns:
风格信息字典如果未找到则返回None
"""
if not self.db_pool:
logger.error("数据库连接池未初始化")
return None
try:
conn = self.db_pool.get_connection()
cursor = conn.cursor(dictionary=True)
cursor.execute(
"SELECT * FROM contentStyles WHERE id = %s AND isDeleted = 0",
(style_id,)
)
result = cursor.fetchone()
cursor.close()
conn.close()
if result:
logger.info(f"找到风格信息: ID={style_id}, 名称={result['styleName']}")
return result
else:
logger.warning(f"未找到风格信息: ID={style_id}")
return None
except Exception as e:
logger.error(f"查询风格信息失败: {e}")
return None
def get_audience_by_id(self, audience_id: int) -> Optional[Dict[str, Any]]:
"""
根据ID获取受众信息
Args:
audience_id: 受众ID
Returns:
受众信息字典如果未找到则返回None
"""
if not self.db_pool:
logger.error("数据库连接池未初始化")
return None
try:
conn = self.db_pool.get_connection()
cursor = conn.cursor(dictionary=True)
cursor.execute(
"SELECT * FROM targetAudiences WHERE id = %s AND isDeleted = 0",
(audience_id,)
)
result = cursor.fetchone()
cursor.close()
conn.close()
if result:
logger.info(f"找到受众信息: ID={audience_id}, 名称={result['audienceName']}")
return result
else:
logger.warning(f"未找到受众信息: ID={audience_id}")
return None
except Exception as e:
logger.error(f"查询受众信息失败: {e}")
return None
def get_scenic_spots_by_ids(self, spot_ids: List[int]) -> List[Dict[str, Any]]:
"""
根据ID列表批量获取景区信息
Args:
spot_ids: 景区ID列表
Returns:
景区信息列表
"""
if not self.db_pool or not spot_ids:
return []
try:
conn = self.db_pool.get_connection()
cursor = conn.cursor(dictionary=True)
# 构建IN查询
placeholders = ','.join(['%s'] * len(spot_ids))
query = f"SELECT * FROM scenicSpot WHERE id IN ({placeholders}) AND isDelete = 0"
cursor.execute(query, spot_ids)
results = cursor.fetchall()
cursor.close()
conn.close()
logger.info(f"批量查询景区信息: 请求{len(spot_ids)}个,找到{len(results)}")
return results
except Exception as e:
logger.error(f"批量查询景区信息失败: {e}")
return []
def get_products_by_ids(self, productIds: List[int]) -> List[Dict[str, Any]]:
"""
根据ID列表批量获取产品信息
Args:
productIds: 产品ID列表
Returns:
产品信息列表
"""
if not self.db_pool or not productIds:
return []
try:
conn = self.db_pool.get_connection()
cursor = conn.cursor(dictionary=True)
# 构建IN查询
placeholders = ','.join(['%s'] * len(productIds))
query = f"SELECT * FROM product WHERE id IN ({placeholders}) AND isDelete = 0"
cursor.execute(query, productIds)
results = cursor.fetchall()
cursor.close()
conn.close()
logger.info(f"批量查询产品信息: 请求{len(productIds)}个,找到{len(results)}")
return results
except Exception as e:
logger.error(f"批量查询产品信息失败: {e}")
return []
def get_styles_by_ids(self, styleIds: List[int]) -> List[Dict[str, Any]]:
"""
根据ID列表批量获取风格信息
Args:
styleIds: 风格ID列表
Returns:
风格信息列表
"""
if not self.db_pool or not styleIds:
return []
try:
conn = self.db_pool.get_connection()
cursor = conn.cursor(dictionary=True)
# 构建IN查询
placeholders = ','.join(['%s'] * len(styleIds))
query = f"SELECT * FROM contentStyle WHERE id IN ({placeholders}) AND isDelete = 0"
cursor.execute(query, styleIds)
results = cursor.fetchall()
cursor.close()
conn.close()
logger.info(f"批量查询风格信息: 请求{len(styleIds)}个,找到{len(results)}")
return results
except Exception as e:
logger.error(f"批量查询风格信息失败: {e}")
return []
def get_audiences_by_ids(self, audienceIds: List[int]) -> List[Dict[str, Any]]:
"""
根据ID列表批量获取受众信息
Args:
audienceIds: 受众ID列表
Returns:
受众信息列表
"""
if not self.db_pool or not audienceIds:
return []
try:
conn = self.db_pool.get_connection()
cursor = conn.cursor(dictionary=True)
# 构建IN查询
placeholders = ','.join(['%s'] * len(audienceIds))
query = f"SELECT * FROM targetAudience WHERE id IN ({placeholders}) AND isDelete = 0"
cursor.execute(query, audienceIds)
results = cursor.fetchall()
cursor.close()
conn.close()
logger.info(f"批量查询受众信息: 请求{len(audienceIds)}个,找到{len(results)}")
return results
except Exception as e:
logger.error(f"批量查询受众信息失败: {e}")
return []
def list_all_scenic_spots(self, user_id: Optional[int] = None, is_public: Optional[bool] = None) -> List[Dict[str, Any]]:
"""
获取所有景区列表
Args:
user_id: 用户ID如果提供则只返回该用户的景区
is_public: 是否公开,如果提供则过滤公开/私有景区
Returns:
景区列表
"""
if not self.db_pool:
return []
try:
conn = self.db_pool.get_connection()
cursor = conn.cursor(dictionary=True)
# 构建查询条件
conditions = ["isDelete = 0"]
params = []
if user_id is not None:
conditions.append("userId = %s")
params.append(user_id)
if is_public is not None:
conditions.append("isPublic = %s")
params.append(1 if is_public else 0)
query = f"""
SELECT id, name, address, trafficInfo, description,
advantage, highlight, isPublic, userId
FROM scenicSpot
WHERE {' AND '.join(conditions)}
ORDER BY name
"""
cursor.execute(query, params)
results = cursor.fetchall()
cursor.close()
conn.close()
logger.info(f"获取景区列表: 找到{len(results)}个景区")
return results
except Exception as e:
logger.error(f"获取景区列表失败: {e}")
return []
def list_all_products(self, user_id: Optional[int] = None, is_public: Optional[bool] = None) -> List[Dict[str, Any]]:
"""
获取所有产品列表
Args:
user_id: 用户ID如果提供则只返回该用户的产品
is_public: 是否公开,如果提供则过滤公开/私有产品
Returns:
产品列表
"""
if not self.db_pool:
return []
try:
conn = self.db_pool.get_connection()
cursor = conn.cursor(dictionary=True)
# 构建查询条件
conditions = ["isDelete = 0"]
params = []
if user_id is not None:
conditions.append("userId = %s")
params.append(user_id)
if is_public is not None:
conditions.append("isPublic = %s")
params.append(1 if is_public else 0)
query = f"""
SELECT id, productName, originPrice, realPrice, packageInfo,
detailedDescription, keyAdvantages, highlights,
usageRules, surcharge, reservation, refund, discounts,
isPublic, userId
FROM product
WHERE {' AND '.join(conditions)}
ORDER BY productName
"""
cursor.execute(query, params)
results = cursor.fetchall()
cursor.close()
conn.close()
logger.info(f"获取产品列表: 找到{len(results)}个产品")
return results
except Exception as e:
logger.error(f"获取产品列表失败: {e}")
return []
def list_all_styles(self) -> List[Dict[str, Any]]:
"""
获取所有风格列表
Returns:
风格列表
"""
if not self.db_pool:
return []
try:
conn = self.db_pool.get_connection()
cursor = conn.cursor(dictionary=True)
cursor.execute("SELECT id, styleName, description FROM contentStyle WHERE isDelete = 0 ORDER BY styleName")
results = cursor.fetchall()
cursor.close()
conn.close()
logger.info(f"获取风格列表: 找到{len(results)}个风格")
return results
except Exception as e:
logger.error(f"获取风格列表失败: {e}")
return []
def list_all_audiences(self) -> List[Dict[str, Any]]:
"""
获取所有受众列表
Returns:
受众列表
"""
if not self.db_pool:
return []
try:
conn = self.db_pool.get_connection()
cursor = conn.cursor(dictionary=True)
cursor.execute("SELECT id, audienceName, description FROM targetAudience WHERE isDelete = 0 ORDER BY audienceName")
results = cursor.fetchall()
cursor.close()
conn.close()
logger.info(f"获取受众列表: 找到{len(results)}个受众")
return results
except Exception as e:
logger.error(f"获取受众列表失败: {e}")
return []
def is_available(self) -> bool:
"""
检查数据库服务是否可用
Returns:
数据库是否可用
"""
return self.db_pool is not None
# 名称到ID的反向查询方法
def get_style_id_by_name(self, style_name: str) -> Optional[int]:
"""
根据风格名称获取风格ID
Args:
style_name: 风格名称
Returns:
风格ID如果未找到则返回None
"""
if not self.db_pool:
logger.error("数据库连接池未初始化")
return None
try:
conn = self.db_pool.get_connection()
cursor = conn.cursor(dictionary=True)
cursor.execute(
"SELECT id FROM style WHERE styleName = %s AND isDelete = 0",
(style_name,)
)
result = cursor.fetchone()
cursor.close()
conn.close()
if result:
return result['id']
else:
logger.warning(f"未找到风格: {style_name}")
return None
except Exception as e:
logger.error(f"查询风格ID失败: {e}")
return None
def get_audience_id_by_name(self, audience_name: str) -> Optional[int]:
"""
根据受众名称获取受众ID
Args:
audience_name: 受众名称
Returns:
受众ID如果未找到则返回None
"""
if not self.db_pool:
logger.error("数据库连接池未初始化")
return None
try:
conn = self.db_pool.get_connection()
cursor = conn.cursor(dictionary=True)
cursor.execute(
"SELECT id FROM targetAudience WHERE audienceName = %s AND isDelete = 0",
(audience_name,)
)
result = cursor.fetchone()
cursor.close()
conn.close()
if result:
return result['id']
else:
logger.warning(f"未找到受众: {audience_name}")
return None
except Exception as e:
logger.error(f"查询受众ID失败: {e}")
return None
def get_scenic_spot_id_by_name(self, spot_name: str) -> Optional[int]:
"""
根据景区名称获取景区ID
Args:
spot_name: 景区名称
Returns:
景区ID如果未找到则返回None
"""
if not self.db_pool:
logger.error("数据库连接池未初始化")
return None
try:
conn = self.db_pool.get_connection()
cursor = conn.cursor(dictionary=True)
cursor.execute(
"SELECT id FROM scenicSpot WHERE name = %s AND isDelete = 0",
(spot_name,)
)
result = cursor.fetchone()
cursor.close()
conn.close()
if result:
return result['id']
else:
logger.warning(f"未找到景区: {spot_name}")
return None
except Exception as e:
logger.error(f"查询景区ID失败: {e}")
return None
def get_product_id_by_name(self, product_name: str) -> Optional[int]:
"""
根据产品名称获取产品ID
Args:
product_name: 产品名称
Returns:
产品ID如果未找到则返回None
"""
if not self.db_pool:
logger.error("数据库连接池未初始化")
return None
try:
conn = self.db_pool.get_connection()
cursor = conn.cursor(dictionary=True)
cursor.execute(
"SELECT id FROM product WHERE productName = %s AND isDelete = 0",
(product_name,)
)
result = cursor.fetchone()
cursor.close()
conn.close()
if result:
return result['id']
else:
logger.warning(f"未找到产品: {product_name}")
return None
except Exception as e:
logger.error(f"查询产品ID失败: {e}")
return None
def get_image_by_id(self, image_id: int) -> Optional[Dict[str, Any]]:
"""
根据ID获取图像信息
Args:
image_id: 图像ID
Returns:
图像信息字典如果未找到则返回None
"""
if not self.db_pool:
logger.error("数据库连接池未初始化")
return None
try:
conn = self.db_pool.get_connection()
cursor = conn.cursor(dictionary=True)
cursor.execute(
"SELECT * FROM material WHERE id = %s AND materialType = 'image' AND isDelete = 0",
(image_id,)
)
result = cursor.fetchone()
cursor.close()
conn.close()
if result:
logger.info(f"找到图像信息: ID={image_id}, 名称={result['materialName']}")
return result
else:
logger.warning(f"未找到图像信息: ID={image_id}")
return None
except Exception as e:
logger.error(f"查询图像信息失败: {e}")
return None
def get_images_by_ids(self, image_ids: List[int]) -> List[Dict[str, Any]]:
"""
根据ID列表批量获取图像信息
Args:
image_ids: 图像ID列表
Returns:
图像信息列表
"""
if not self.db_pool or not image_ids:
return []
try:
conn = self.db_pool.get_connection()
cursor = conn.cursor(dictionary=True)
# 构建IN查询
placeholders = ','.join(['%s'] * len(image_ids))
query = f"SELECT * FROM material WHERE id IN ({placeholders}) AND materialType = 'image' AND isDelete = 0"
cursor.execute(query, image_ids)
results = cursor.fetchall()
cursor.close()
conn.close()
logger.info(f"批量查询图像信息: 请求{len(image_ids)}个,找到{len(results)}")
return results
except Exception as e:
logger.error(f"批量查询图像信息失败: {e}")
return []
def get_content_by_id(self, content_id: int) -> Optional[Dict[str, Any]]:
"""
根据ID获取内容信息
Args:
content_id: 内容ID
Returns:
内容信息字典如果未找到则返回None
"""
if not self.db_pool:
logger.error("数据库连接池未初始化")
return None
try:
conn = self.db_pool.get_connection()
cursor = conn.cursor(dictionary=True)
cursor.execute(
"SELECT * FROM content WHERE id = %s AND isDelete = 0",
(content_id,)
)
result = cursor.fetchone()
cursor.close()
conn.close()
if result:
logger.info(f"找到内容信息: ID={content_id}, 标题={result['title']}")
return result
else:
logger.warning(f"未找到内容信息: ID={content_id}")
return None
except Exception as e:
logger.error(f"查询内容信息失败: {e}")
return None
def get_content_by_topic_index(self, topic_index: str) -> Optional[Dict[str, Any]]:
"""
根据主题索引获取内容信息
Args:
topic_index: 主题索引
Returns:
内容信息字典如果未找到则返回None
"""
if not self.db_pool:
logger.error("数据库连接池未初始化")
return None
try:
conn = self.db_pool.get_connection()
cursor = conn.cursor(dictionary=True)
cursor.execute(
"SELECT * FROM content WHERE topicIndex = %s AND isDelete = 0 ORDER BY createTime DESC LIMIT 1",
(topic_index,)
)
result = cursor.fetchone()
cursor.close()
conn.close()
if result:
logger.info(f"找到内容信息: topicIndex={topic_index}, 标题={result['title']}")
return result
else:
logger.warning(f"未找到内容信息: topicIndex={topic_index}")
return None
except Exception as e:
logger.error(f"查询内容信息失败: {e}")
return None
def get_images_by_folder_id(self, folder_id: int) -> List[Dict[str, Any]]:
"""
根据文件夹ID获取图像列表
Args:
folder_id: 文件夹ID
Returns:
图像信息列表
"""
if not self.db_pool:
return []
try:
conn = self.db_pool.get_connection()
cursor = conn.cursor(dictionary=True)
cursor.execute(
"SELECT * FROM material WHERE folderId = %s AND materialType = 'image' AND isDelete = 0 ORDER BY createTime DESC",
(folder_id,)
)
results = cursor.fetchall()
cursor.close()
conn.close()
logger.info(f"根据文件夹ID获取图像: folderId={folder_id}, 找到{len(results)}个图像")
return results
except Exception as e:
logger.error(f"根据文件夹ID获取图像失败: {e}")
return []
def get_folder_by_id(self, folder_id: int) -> Optional[Dict[str, Any]]:
"""
根据ID获取文件夹信息
Args:
folder_id: 文件夹ID
Returns:
文件夹信息字典如果未找到则返回None
"""
if not self.db_pool:
logger.error("数据库连接池未初始化")
return None
try:
conn = self.db_pool.get_connection()
cursor = conn.cursor(dictionary=True)
cursor.execute(
"SELECT * FROM material_folder WHERE id = %s AND isDelete = 0",
(folder_id,)
)
result = cursor.fetchone()
cursor.close()
conn.close()
if result:
logger.info(f"找到文件夹信息: ID={folder_id}, 名称={result['folderName']}")
return result
else:
logger.warning(f"未找到文件夹信息: ID={folder_id}")
return None
except Exception as e:
logger.error(f"查询文件夹信息失败: {e}")
return None
def get_related_images_for_content(self, content_id: int, limit: int = 10) -> List[Dict[str, Any]]:
"""
获取与内容相关的图像列表
Args:
content_id: 内容ID
limit: 限制数量
Returns:
相关图像列表
"""
if not self.db_pool:
return []
try:
conn = self.db_pool.get_connection()
cursor = conn.cursor(dictionary=True)
# 获取内容信息
cursor.execute(
"SELECT * FROM content WHERE id = %s AND isDelete = 0",
(content_id,)
)
content = cursor.fetchone()
if not content:
cursor.close()
conn.close()
return []
# 获取相关的图像(这里可以根据业务逻辑调整查询条件)
cursor.execute(
"SELECT * FROM material WHERE materialType = 'image' AND isDelete = 0 ORDER BY RAND() LIMIT %s",
(limit,)
)
results = cursor.fetchall()
cursor.close()
conn.close()
logger.info(f"获取相关内容图像: contentId={content_id}, 找到{len(results)}个图像")
return results
except Exception as e:
logger.error(f"获取相关内容图像失败: {e}")
return []
# 模板相关查询方法
def get_all_poster_templates(self) -> List[Dict[str, Any]]:
"""
获取所有海报模板
Returns:
模板列表
"""
if not self.db_pool:
return []
try:
conn = self.db_pool.get_connection()
cursor = conn.cursor(dictionary=True)
cursor.execute(
"SELECT * FROM posterTemplates ORDER BY createdAt"
)
results = cursor.fetchall()
cursor.close()
conn.close()
logger.info(f"获取海报模板列表: 找到{len(results)}个模板")
return results
except Exception as e:
logger.error(f"获取海报模板列表失败: {e}")
return []
def get_poster_template_by_id(self, template_id: str) -> Optional[Dict[str, Any]]:
"""
根据ID获取海报模板信息
Args:
template_id: 模板ID
Returns:
模板信息字典如果未找到则返回None
"""
if not self.db_pool:
logger.error("数据库连接池未初始化")
return None
try:
conn = self.db_pool.get_connection()
cursor = conn.cursor(dictionary=True)
cursor.execute(
"SELECT * FROM posterTemplates WHERE id = %s",
(template_id,)
)
result = cursor.fetchone()
cursor.close()
conn.close()
if result:
logger.info(f"找到模板信息: ID={template_id}, 名称={result['name']}")
return result
else:
logger.warning(f"未找到模板信息: ID={template_id}")
return None
except Exception as e:
logger.error(f"查询模板信息失败: {e}")
return None
def get_active_poster_templates(self) -> List[Dict[str, Any]]:
"""
获取所有激活的海报模板
Returns:
激活的模板列表
"""
if not self.db_pool:
return []
try:
conn = self.db_pool.get_connection()
cursor = conn.cursor(dictionary=True)
cursor.execute(
"SELECT * FROM posterTemplates WHERE isActive = 1 ORDER BY createdAt"
)
results = cursor.fetchall()
cursor.close()
conn.close()
logger.info(f"获取激活模板列表: 找到{len(results)}个模板")
return results
except Exception as e:
logger.error(f"获取激活模板列表失败: {e}")
return []
def update_template_usage_stats(self, template_id: str, success: bool = True, processing_time: float = 0.0):
"""
更新模板使用统计
Args:
template_id: 模板ID
success: 是否成功
processing_time: 处理时间(秒)
"""
if not self.db_pool:
logger.error("数据库连接池未初始化")
return
try:
conn = self.db_pool.get_connection()
cursor = conn.cursor()
# 更新或插入统计记录
cursor.execute("""
INSERT INTO templateUsageStats (templateId, usageCount, successCount, errorCount, avgProcessingTime, lastUsedAt)
VALUES (%s, 1, %s, %s, %s, NOW())
ON DUPLICATE KEY UPDATE
usageCount = usageCount + 1,
successCount = successCount + %s,
errorCount = errorCount + %s,
avgProcessingTime = (avgProcessingTime * (usageCount - 1) + %s) / usageCount,
lastUsedAt = NOW(),
updatedAt = NOW()
""", (
template_id,
1 if success else 0,
0 if success else 1,
processing_time,
1 if success else 0,
0 if success else 1,
processing_time
))
conn.commit()
cursor.close()
conn.close()
logger.info(f"更新模板使用统计: template_id={template_id}, success={success}, time={processing_time:.3f}s")
except Exception as e:
logger.error(f"更新模板使用统计失败: {e}")
def get_template_usage_stats(self, template_id: str) -> Optional[Dict[str, Any]]:
"""
获取模板使用统计
Args:
template_id: 模板ID
Returns:
使用统计信息
"""
if not self.db_pool:
return None
try:
conn = self.db_pool.get_connection()
cursor = conn.cursor(dictionary=True)
cursor.execute(
"SELECT * FROM templateUsageStats WHERE templateId = %s",
(template_id,)
)
result = cursor.fetchone()
cursor.close()
conn.close()
if result:
logger.info(f"找到模板使用统计: template_id={template_id}")
return result
else:
logger.warning(f"未找到模板使用统计: template_id={template_id}")
return None
except Exception as e:
logger.error(f"查询模板使用统计失败: {e}")
return None