| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115 |
- import mysql.connector
- from mysql.connector import errorcode
- from .config import settings
- from app.core.logger import get_logger
- logger = get_logger(__name__)
- # 全局的连接池
- db_connection_pool = None
- def init_database():
- """
- 初始化数据库:如果数据库或表不存在,则创建它们。
- 主键统一为 'id'。
- """
- logger.info("--- 开始初始化数据库 ---")
- try:
- cnx = mysql.connector.connect(**settings.DATABASE_CONFIG)
- cursor = cnx.cursor()
- cursor.execute(f"CREATE DATABASE IF NOT EXISTS {settings.DB_NAME} DEFAULT CHARACTER SET 'utf8mb4'")
- logger.info(f"数据库 '{settings.DB_NAME}' 已准备就绪。")
- cnx.database = settings.DB_NAME
- # 1. 创建 cards 表 (主键为 id)
- cards_table = (
- f"CREATE TABLE IF NOT EXISTS `{settings.DB_CARD_TABLE_NAME}` ("
- " `id` INT AUTO_INCREMENT PRIMARY KEY,"
- " `card_name` VARCHAR(255) NULL COMMENT '卡牌的通用名称',"
- " `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,"
- " `updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP"
- ") ENGINE=InnoDB COMMENT='存储实体卡牌的核心信息'"
- )
- cursor.execute(cards_table)
- logger.info(f"数据表 '{settings.DB_CARD_TABLE_NAME}' 已准备就绪。")
- # 2. 创建 card_images 表 (主键为 id)
- card_images_table = (
- f"CREATE TABLE IF NOT EXISTS `{settings.DB_IMAGE_TABLE_NAME}` ("
- " `id` INT AUTO_INCREMENT PRIMARY KEY,"
- " `card_id` INT NOT NULL COMMENT '关联的卡牌ID',"
- " `image_type` VARCHAR(50) NOT NULL COMMENT '图片类型 (front_face, back_face, etc)',"
- " `image_name` VARCHAR(255) NULL,"
- " `image_path` VARCHAR(512) NOT NULL,"
- " `detection_json` JSON NOT NULL COMMENT '原始检测JSON数据',"
- " `modified_json` JSON NULL COMMENT '修改后的JSON数据',"
- " `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,"
- " `updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,"
- # 外键现在引用 cards(id)
- f" FOREIGN KEY (`card_id`) REFERENCES `{settings.DB_CARD_TABLE_NAME}`(`id`) ON DELETE CASCADE,"
- " UNIQUE KEY `uk_card_image_type` (`card_id`, `image_type`)"
- ") ENGINE=InnoDB COMMENT='存储所有卡牌的图片及检测数据'"
- )
- cursor.execute(card_images_table)
- logger.info(f"数据表 '{settings.DB_IMAGE_TABLE_NAME}' 已准备就绪。")
- except mysql.connector.Error as err:
- logger.error(f"数据库初始化失败: {err}")
- exit(1)
- finally:
- if 'cursor' in locals() and cursor:
- cursor.close()
- if 'cnx' in locals() and cnx.is_connected():
- cnx.close()
- logger.info("--- 数据库初始化完成 ---")
- def load_database_pool():
- """
- 在应用启动时创建数据库连接池。
- """
- global db_connection_pool
- if db_connection_pool is None:
- logger.info("--- 创建数据库连接池 ---")
- try:
- db_connection_pool = mysql.connector.pooling.MySQLConnectionPool(
- pool_name="mypool",
- pool_size=5,
- **settings.DATABASE_CONFIG_WITH_DB
- )
- logger.info("--- 数据库连接池创建成功 ---")
- except mysql.connector.Error as err:
- logger.error(f"创建数据库连接池失败: {err}")
- exit(1)
- def close_database_pool():
- """
- 在应用关闭时,不需要手动关闭连接池,连接器会自动处理。
- 这个函数留作备用。
- """
- logger.info("--- 数据库连接池将自动关闭 ---")
- # --- FastAPI 依赖注入 ---
- def get_db_connection():
- """
- 一个FastAPI依赖项,用于从池中获取数据库连接。
- 它确保连接在使用后返回到池中。
- """
- if db_connection_pool is None:
- raise RuntimeError("数据库连接池未初始化")
- db_conn = None
- try:
- db_conn = db_connection_pool.get_connection()
- yield db_conn
- except mysql.connector.Error as err:
- logger.error(f"获取数据库连接失败: {err}")
- finally:
- if db_conn and db_conn.is_connected():
- db_conn.close()
|