Signed-off-by: TIANHE <TIANHE@GMAIL.COM>
This commit is contained in:
TIANHE
2025-12-30 21:02:38 +08:00
parent 58a1133c83
commit 50939212be
23 changed files with 910 additions and 99 deletions
+19 -14
View File
@@ -12,8 +12,12 @@ from app.utils.logger import get_logger
logger = get_logger(__name__)
# 数据库文件默认路径(兼容旧行为:backend_api_python/quantdinger.db
# SQLite 主库路径解析
#
# 目标默认行为:把主库放到 `backend_api_python/data/quantdinger.db`
# 兼容旧行为:老版本会在 `backend_api_python/quantdinger.db` 建库
_BASE_DIR = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
_DEFAULT_DB_FILE = os.path.join(_BASE_DIR, 'data', 'quantdinger.db')
_LEGACY_DB_FILE = os.path.join(_BASE_DIR, 'quantdinger.db')
@@ -23,13 +27,13 @@ def _get_db_file() -> str:
Priority:
- SQLITE_DATABASE_FILE env (Docker 推荐:/app/data/quantdinger.db)
- legacy default: backend_api_python/quantdinger.db
- default: backend_api_python/data/quantdinger.db (local recommended)
Also performs a best-effort one-time migration:
If the configured path doesn't exist but legacy db exists, copy legacy to configured path.
If the configured/default path doesn't exist but legacy db exists, copy legacy to configured/default path.
"""
env_path = os.getenv('SQLITE_DATABASE_FILE')
db_path = (env_path or '').strip() or _LEGACY_DB_FILE
db_path = (env_path or '').strip() or _DEFAULT_DB_FILE
# Ensure parent dir exists
parent = os.path.dirname(db_path)
@@ -421,8 +425,9 @@ def _init_db_schema(conn):
conn.commit()
logger.info("Database schema initialized (SQLite)")
# 初始化一次
# 初始化一次(按 db_file 维度)
_has_initialized = False
_initialized_db_file = None
class SQLiteCursor:
"""模拟 pymysql DictCursor"""
@@ -492,24 +497,24 @@ def get_db_connection():
"""
获取数据库连接 (Context Manager)
"""
global _has_initialized
global _has_initialized, _initialized_db_file
# 简单的连接创建,不使用连接池(SQLite 文件锁机制决定了连接池意义不大)
# 使用线程锁防止写冲突(虽然 SQLite 有 WAL 模式,但稳妥起见)
# 注意:这里加锁粒度较大,如果是高并发场景可能会慢,但对于个人量化系统足够。
# 初始化表结构
if not _has_initialized:
# 初始化表结构(确保每个 db_file 都被初始化过)
db_file = _get_db_file()
if (not _has_initialized) or (_initialized_db_file != db_file):
try:
db_file = _get_db_file()
conn_init = sqlite3.connect(db_file)
_init_db_schema(conn_init)
conn_init.close()
_has_initialized = True
_initialized_db_file = db_file
except Exception as e:
logger.error(f"Failed to initialize database: {e}")
db_file = _get_db_file()
conn = SQLiteConnection(db_file)
try:
# with _db_lock: # SQLite 内部有锁,这里如果不跨线程共享连接其实不用强加锁
@@ -523,18 +528,18 @@ def get_db_connection():
def get_db_connection_sync():
"""兼容旧接口"""
global _has_initialized
if not _has_initialized:
global _has_initialized, _initialized_db_file
db_file = _get_db_file()
if (not _has_initialized) or (_initialized_db_file != db_file):
try:
db_file = _get_db_file()
conn_init = sqlite3.connect(db_file)
_init_db_schema(conn_init)
conn_init.close()
_has_initialized = True
_initialized_db_file = db_file
except Exception as e:
logger.error(f"Failed to initialize database: {e}")
db_file = _get_db_file()
return SQLiteConnection(db_file)
def close_db_connection():