- 重构数据访问层:引入DAO模式,支持MySQL/SQLite双数据库 - 新增数据库架构:完整的股票数据、AI分析、自选股管理表结构 - 升级AI分析服务:集成豆包大模型,支持多维度分析 - 优化API路由:分离市场数据API,提供更清晰的接口设计 - 完善项目文档:添加数据库迁移指南、新功能指南等 - 清理冗余文件:删除旧的缓存文件和无用配置 - 新增调度器:支持定时任务和数据自动更新 - 改进前端模板:简化的股票展示页面 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
114 lines
4.2 KiB
Python
114 lines
4.2 KiB
Python
"""
|
||
基础数据访问对象
|
||
"""
|
||
from abc import ABC, abstractmethod
|
||
from typing import Dict, Any, Optional, List
|
||
import logging
|
||
from datetime import datetime, date
|
||
|
||
from app.database import DatabaseManager
|
||
|
||
|
||
class BaseDAO(ABC):
|
||
"""数据访问对象基类"""
|
||
|
||
def __init__(self):
|
||
self.db_manager = DatabaseManager()
|
||
self.logger = logging.getLogger(self.__class__.__name__)
|
||
|
||
def _execute_query(self, query: str, params: Optional[tuple] = None) -> List[Dict]:
|
||
"""执行查询语句"""
|
||
try:
|
||
with self.db_manager.get_cursor() as cursor:
|
||
cursor.execute(query, params)
|
||
return cursor.fetchall()
|
||
except Exception as e:
|
||
self.logger.error(f"查询执行失败: {query}, 参数: {params}, 错误: {e}")
|
||
raise
|
||
|
||
def _execute_single_query(self, query: str, params: Optional[tuple] = None) -> Optional[Dict]:
|
||
"""执行单条记录查询"""
|
||
try:
|
||
with self.db_manager.get_cursor() as cursor:
|
||
cursor.execute(query, params)
|
||
return cursor.fetchone()
|
||
except Exception as e:
|
||
self.logger.error(f"单条查询执行失败: {query}, 参数: {params}, 错误: {e}")
|
||
raise
|
||
|
||
def _execute_update(self, query: str, params: Optional[tuple] = None) -> int:
|
||
"""执行更新语句,返回影响的行数"""
|
||
try:
|
||
with self.db_manager.get_connection() as conn:
|
||
with conn.cursor() as cursor:
|
||
cursor.execute(query, params)
|
||
affected_rows = cursor.rowcount
|
||
conn.commit()
|
||
return affected_rows
|
||
except Exception as e:
|
||
self.logger.error(f"更新执行失败: {query}, 参数: {params}, 错误: {e}")
|
||
raise
|
||
|
||
def _execute_insert(self, query: str, params: Optional[tuple] = None) -> int:
|
||
"""执行插入语句,返回插入的ID"""
|
||
try:
|
||
with self.db_manager.get_connection() as conn:
|
||
with conn.cursor() as cursor:
|
||
cursor.execute(query, params)
|
||
inserted_id = cursor.lastrowid
|
||
conn.commit()
|
||
return inserted_id
|
||
except Exception as e:
|
||
self.logger.error(f"插入执行失败: {query}, 参数: {params}, 错误: {e}")
|
||
raise
|
||
|
||
def _execute_batch_insert(self, query: str, params_list: List[tuple]) -> int:
|
||
"""批量插入数据,返回插入的总行数"""
|
||
if not params_list:
|
||
return 0
|
||
|
||
try:
|
||
with self.db_manager.get_connection() as conn:
|
||
with conn.cursor() as cursor:
|
||
cursor.executemany(query, params_list)
|
||
affected_rows = cursor.rowcount
|
||
conn.commit()
|
||
return affected_rows
|
||
except Exception as e:
|
||
self.logger.error(f"批量插入失败: {query}, 参数数量: {len(params_list)}, 错误: {e}")
|
||
raise
|
||
|
||
def log_data_update(self, data_type: str, stock_code: str, status: str,
|
||
message: str = None, execution_time: float = None):
|
||
"""记录数据更新日志"""
|
||
try:
|
||
query = """
|
||
INSERT INTO data_update_log
|
||
(data_type, stock_code, update_status, update_message, execution_time)
|
||
VALUES (%s, %s, %s, %s, %s)
|
||
"""
|
||
self._execute_insert(query, (data_type, stock_code, status, message, execution_time))
|
||
except Exception as e:
|
||
self.logger.error(f"记录更新日志失败: {e}")
|
||
|
||
def get_today_date(self) -> str:
|
||
"""获取今天的日期字符串"""
|
||
return date.today().strftime('%Y-%m-%d')
|
||
|
||
def parse_float(self, value: Any) -> Optional[float]:
|
||
"""解析浮点数"""
|
||
if value is None or value == '':
|
||
return None
|
||
try:
|
||
return float(value)
|
||
except (ValueError, TypeError):
|
||
return None
|
||
|
||
def parse_int(self, value: Any) -> Optional[int]:
|
||
"""解析整数"""
|
||
if value is None or value == '':
|
||
return None
|
||
try:
|
||
return int(value)
|
||
except (ValueError, TypeError):
|
||
return None |