feat: 添加MySQL数据库支持和完整的数据库管理功能
- 添加MySQL数据库连接配置 - 创建SQLAlchemy数据库模型(用户表和产品表) - 添加Alembic数据库迁移工具 - 创建数据库管理脚本(database_manager.py) - 添加SQL文件目录结构(migrations, seeds, schemas) - 更新应用配置以支持数据库连接 - 添加完整的数据库设置文档 - 配置开发环境数据库连接(localhost:3306, root/123456, fast_demo)
This commit is contained in:
parent
04cb2cbbf7
commit
1f2bb12178
|
|
@ -0,0 +1,86 @@
|
||||||
|
# CODEBUDDY.md
|
||||||
|
|
||||||
|
此文件为 CodeBuddy Code 在此代码库中工作时提供指导。
|
||||||
|
|
||||||
|
## 常用命令
|
||||||
|
|
||||||
|
### 应用启动
|
||||||
|
```bash
|
||||||
|
# 安装依赖
|
||||||
|
pip install -r requirements.txt
|
||||||
|
|
||||||
|
# 使用便捷启动脚本(推荐)
|
||||||
|
python start.py --env dev # 开发环境
|
||||||
|
python start.py --env prod # 生产环境
|
||||||
|
python start.py --port 9000 # 指定端口
|
||||||
|
|
||||||
|
# 直接运行主文件
|
||||||
|
python main.py
|
||||||
|
```
|
||||||
|
|
||||||
|
### 环境配置
|
||||||
|
```bash
|
||||||
|
# 环境变量优先级(从高到低):
|
||||||
|
# 1. 环境变量
|
||||||
|
# 2. .env.{environment} 文件
|
||||||
|
# 3. .env 基础配置文件
|
||||||
|
# 4. 代码中的默认值
|
||||||
|
|
||||||
|
# 配置验证
|
||||||
|
python -c "from app.core.config import settings; print(f'Environment: {settings.ENVIRONMENT}'); print(f'Debug: {settings.DEBUG}')"
|
||||||
|
```
|
||||||
|
|
||||||
|
## 架构设计
|
||||||
|
|
||||||
|
### 应用工厂模式
|
||||||
|
项目采用应用工厂模式,核心文件:
|
||||||
|
- **应用创建**:`app/core/application.py` - 使用 `create_application()` 工厂函数
|
||||||
|
- **配置管理**:`app/core/config.py` - 基于 pydantic-settings 的多环境配置
|
||||||
|
- **路由聚合**:`app/api/v1/router.py` - 集中管理 API 路由注册
|
||||||
|
|
||||||
|
### 分层架构
|
||||||
|
1. **API层** (`app/api/v1/endpoints/`) - FastAPI 路由端点,处理 HTTP 请求/响应
|
||||||
|
2. **服务层** (`app/services/`) - 业务逻辑封装,使用单例服务实例
|
||||||
|
3. **模型层** (`app/models/`) - 核心领域模型,Pydantic BaseModel
|
||||||
|
4. **Schema层** (`app/schemas/`) - 请求/响应验证和序列化
|
||||||
|
|
||||||
|
### 路由结构
|
||||||
|
- 所有 API 以 `/api/v1/` 为前缀
|
||||||
|
- 路由通过 `app/api/v1/router.py` 统一注册
|
||||||
|
- 每个资源对应一个独立的路由器文件
|
||||||
|
|
||||||
|
### 配置管理
|
||||||
|
- 支持多环境:development、testing、production
|
||||||
|
- 自动加载对应配置文件:`.env.dev.{env}`
|
||||||
|
- 类型安全验证和转换
|
||||||
|
- 便利属性:`settings.is_development`、`settings.is_production`
|
||||||
|
|
||||||
|
### 服务模式
|
||||||
|
- 使用静态服务类 (`UserService`、`ProductService`)
|
||||||
|
- 当前使用内存数据库进行演示
|
||||||
|
- 服务层负责所有 CRUD 操作和业务规则
|
||||||
|
|
||||||
|
### 关键特性
|
||||||
|
- CORS 中间件配置
|
||||||
|
- 应用生命周期事件处理器
|
||||||
|
- 模块化路由设计
|
||||||
|
- 版本化的 API 结构
|
||||||
|
|
||||||
|
## 开发规范
|
||||||
|
|
||||||
|
### 添加新资源
|
||||||
|
1. 模型层:在 `app/models/` 创建数据模型
|
||||||
|
2. Schema层:在 `app/schemas/` 创建 Base/Create/Update/Response 模式
|
||||||
|
3. 服务层:在 `app/services/` 创建服务类
|
||||||
|
4. API层:在 `app/api/v1/endpoints/` 创建路由端点
|
||||||
|
5. 路由注册:在 `app/api/v1/router.py` 注册新路由
|
||||||
|
|
||||||
|
### 配置扩展
|
||||||
|
- 新配置项添加到 `app/core/config.py` 中的 Settings 类
|
||||||
|
- 遵循现有配置验证模式
|
||||||
|
- 支持环境变量覆盖
|
||||||
|
|
||||||
|
### 数据存储
|
||||||
|
- 当前使用内存数据存储用于演示
|
||||||
|
- 实际实现将在服务层集成数据库
|
||||||
|
- 服务接口设计支持无缝替换存储后端
|
||||||
|
|
@ -0,0 +1,199 @@
|
||||||
|
# 数据库设置指南
|
||||||
|
|
||||||
|
本项目已配置支持MySQL数据库,包含完整的数据库模型、迁移脚本和管理工具。
|
||||||
|
|
||||||
|
## 目录结构
|
||||||
|
|
||||||
|
```
|
||||||
|
sql/
|
||||||
|
├── migrations/ # 数据库迁移文件
|
||||||
|
│ └── 001_create_tables.sql
|
||||||
|
├── seeds/ # 种子数据文件
|
||||||
|
│ └── sample_data.sql
|
||||||
|
└── schemas/ # 数据库架构文件
|
||||||
|
└── init_database.sql
|
||||||
|
|
||||||
|
alembic/ # Alembic迁移工具
|
||||||
|
├── versions/ # 自动生成的迁移版本
|
||||||
|
├── env.py # Alembic环境配置
|
||||||
|
└── script.py.mako # 迁移模板
|
||||||
|
|
||||||
|
app/database/ # 数据库相关代码
|
||||||
|
├── __init__.py
|
||||||
|
├── connection.py # 数据库连接管理
|
||||||
|
├── base.py # 基础模型类
|
||||||
|
└── models.py # SQLAlchemy模型
|
||||||
|
```
|
||||||
|
|
||||||
|
## 快速开始
|
||||||
|
|
||||||
|
### 1. 安装依赖
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install -r requirements.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 配置数据库
|
||||||
|
|
||||||
|
创建 `.env.dev` 文件(参考 `.env.example`):
|
||||||
|
|
||||||
|
```env
|
||||||
|
# MySQL 数据库配置
|
||||||
|
DB_HOST=localhost
|
||||||
|
DB_PORT=3306
|
||||||
|
DB_USER=root
|
||||||
|
DB_PASSWORD=your_password
|
||||||
|
DB_NAME=fastapi_demo
|
||||||
|
DB_CHARSET=utf8mb4
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 初始化数据库
|
||||||
|
|
||||||
|
使用数据库管理脚本:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 初始化数据库(创建数据库和表,插入示例数据)
|
||||||
|
python database_manager.py init
|
||||||
|
|
||||||
|
# 或者分步执行
|
||||||
|
python database_manager.py create-db # 创建数据库
|
||||||
|
python database_manager.py create-tables # 创建表
|
||||||
|
python database_manager.py seed # 插入示例数据
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. 启动应用
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python main.py
|
||||||
|
```
|
||||||
|
|
||||||
|
## 数据库管理
|
||||||
|
|
||||||
|
### 使用数据库管理脚本
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python database_manager.py init # 初始化数据库
|
||||||
|
python database_manager.py reset # 重置数据库
|
||||||
|
python database_manager.py create-db # 仅创建数据库
|
||||||
|
python database_manager.py create-tables # 仅创建表
|
||||||
|
python database_manager.py seed # 仅插入示例数据
|
||||||
|
python database_manager.py help # 显示帮助
|
||||||
|
```
|
||||||
|
|
||||||
|
### 使用Alembic进行迁移
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 初始化Alembic(首次使用)
|
||||||
|
alembic init alembic
|
||||||
|
|
||||||
|
# 创建新的迁移
|
||||||
|
alembic revision --autogenerate -m "描述信息"
|
||||||
|
|
||||||
|
# 执行迁移
|
||||||
|
alembic upgrade head
|
||||||
|
|
||||||
|
# 回滚迁移
|
||||||
|
alembic downgrade -1
|
||||||
|
|
||||||
|
# 查看迁移历史
|
||||||
|
alembic history
|
||||||
|
|
||||||
|
# 查看当前版本
|
||||||
|
alembic current
|
||||||
|
```
|
||||||
|
|
||||||
|
## 数据库模型
|
||||||
|
|
||||||
|
### 用户表 (users)
|
||||||
|
|
||||||
|
| 字段 | 类型 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| id | int(11) | 主键,自增 |
|
||||||
|
| username | varchar(50) | 用户名,唯一 |
|
||||||
|
| email | varchar(100) | 邮箱,唯一 |
|
||||||
|
| full_name | varchar(100) | 全名,可空 |
|
||||||
|
| is_active | tinyint(1) | 是否激活 |
|
||||||
|
| created_at | datetime | 创建时间 |
|
||||||
|
| updated_at | datetime | 更新时间 |
|
||||||
|
|
||||||
|
### 产品表 (products)
|
||||||
|
|
||||||
|
| 字段 | 类型 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| id | int(11) | 主键,自增 |
|
||||||
|
| name | varchar(200) | 产品名称 |
|
||||||
|
| description | text | 产品描述,可空 |
|
||||||
|
| price | decimal(10,2) | 价格 |
|
||||||
|
| stock | int(11) | 库存数量 |
|
||||||
|
| is_available | tinyint(1) | 是否可用 |
|
||||||
|
| created_at | datetime | 创建时间 |
|
||||||
|
| updated_at | datetime | 更新时间 |
|
||||||
|
|
||||||
|
## 配置说明
|
||||||
|
|
||||||
|
### 数据库连接配置
|
||||||
|
|
||||||
|
在 `app/core/config.py` 中配置:
|
||||||
|
|
||||||
|
```python
|
||||||
|
# MySQL 数据库配置
|
||||||
|
DB_HOST: str = "localhost" # 数据库主机
|
||||||
|
DB_PORT: int = 3306 # 数据库端口
|
||||||
|
DB_USER: str = "root" # 数据库用户名
|
||||||
|
DB_PASSWORD: str = "" # 数据库密码
|
||||||
|
DB_NAME: str = "fastapi_demo" # 数据库名称
|
||||||
|
DB_CHARSET: str = "utf8mb4" # 字符集
|
||||||
|
|
||||||
|
# 数据库连接池配置
|
||||||
|
DB_POOL_SIZE: int = 5 # 连接池大小
|
||||||
|
DB_MAX_OVERFLOW: int = 10 # 最大溢出连接数
|
||||||
|
DB_POOL_TIMEOUT: int = 30 # 连接超时时间(秒)
|
||||||
|
DB_POOL_RECYCLE: int = 3600 # 连接回收时间(秒)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 环境变量
|
||||||
|
|
||||||
|
支持通过环境变量覆盖配置:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export DB_HOST=localhost
|
||||||
|
export DB_PORT=3306
|
||||||
|
export DB_USER=root
|
||||||
|
export DB_PASSWORD=your_password
|
||||||
|
export DB_NAME=fastapi_demo
|
||||||
|
```
|
||||||
|
|
||||||
|
## 故障排除
|
||||||
|
|
||||||
|
### 常见问题
|
||||||
|
|
||||||
|
1. **连接失败**
|
||||||
|
- 检查MySQL服务是否启动
|
||||||
|
- 验证数据库配置信息
|
||||||
|
- 确认用户权限
|
||||||
|
|
||||||
|
2. **字符编码问题**
|
||||||
|
- 确保数据库使用utf8mb4字符集
|
||||||
|
- 检查连接字符串中的charset参数
|
||||||
|
|
||||||
|
3. **迁移失败**
|
||||||
|
- 检查Alembic配置
|
||||||
|
- 确认数据库连接正常
|
||||||
|
- 查看迁移文件语法
|
||||||
|
|
||||||
|
### 日志调试
|
||||||
|
|
||||||
|
启用SQL日志:
|
||||||
|
|
||||||
|
```env
|
||||||
|
DB_ECHO=true
|
||||||
|
LOG_LEVEL=debug
|
||||||
|
```
|
||||||
|
|
||||||
|
## 开发建议
|
||||||
|
|
||||||
|
1. **使用迁移管理数据库结构变更**
|
||||||
|
2. **在开发环境中使用示例数据**
|
||||||
|
3. **定期备份生产数据库**
|
||||||
|
4. **使用连接池优化性能**
|
||||||
|
5. **监控数据库连接状态**
|
||||||
|
|
@ -0,0 +1,110 @@
|
||||||
|
# 开发环境配置总结
|
||||||
|
|
||||||
|
## 🎯 数据库配置
|
||||||
|
|
||||||
|
### 连接信息
|
||||||
|
- **主机**: localhost
|
||||||
|
- **端口**: 3306
|
||||||
|
- **用户名**: root
|
||||||
|
- **密码**: 123456
|
||||||
|
- **数据库名**: fast_demo
|
||||||
|
- **字符集**: utf8mb4
|
||||||
|
|
||||||
|
### 连接URL
|
||||||
|
```
|
||||||
|
mysql+pymysql://root:123456@localhost:3306/fast_demo?charset=utf8mb4
|
||||||
|
```
|
||||||
|
|
||||||
|
## 📁 配置文件
|
||||||
|
|
||||||
|
### 1. 应用配置 (`app/core/config.py`)
|
||||||
|
已更新默认数据库配置:
|
||||||
|
```python
|
||||||
|
DB_HOST: str = "localhost"
|
||||||
|
DB_PORT: int = 3306
|
||||||
|
DB_USER: str = "root"
|
||||||
|
DB_PASSWORD: str = "123456"
|
||||||
|
DB_NAME: str = "fast_demo"
|
||||||
|
DB_CHARSET: str = "utf8mb4"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Alembic配置 (`alembic.ini`)
|
||||||
|
已更新数据库URL:
|
||||||
|
```ini
|
||||||
|
sqlalchemy.url = mysql+pymysql://root:123456@localhost:3306/fast_demo?charset=utf8mb4
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🗄️ 数据库表
|
||||||
|
|
||||||
|
### 用户表 (users)
|
||||||
|
| 字段 | 类型 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| id | int(11) | 主键,自增 |
|
||||||
|
| username | varchar(50) | 用户名,唯一 |
|
||||||
|
| email | varchar(100) | 邮箱,唯一 |
|
||||||
|
| full_name | varchar(100) | 全名,可空 |
|
||||||
|
| is_active | tinyint(1) | 是否激活 |
|
||||||
|
| created_at | datetime | 创建时间 |
|
||||||
|
| updated_at | datetime | 更新时间 |
|
||||||
|
|
||||||
|
### 产品表 (products)
|
||||||
|
| 字段 | 类型 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| id | int(11) | 主键,自增 |
|
||||||
|
| name | varchar(200) | 产品名称 |
|
||||||
|
| description | text | 产品描述,可空 |
|
||||||
|
| price | decimal(10,2) | 价格 |
|
||||||
|
| stock | int(11) | 库存数量 |
|
||||||
|
| is_available | tinyint(1) | 是否可用 |
|
||||||
|
| created_at | datetime | 创建时间 |
|
||||||
|
| updated_at | datetime | 更新时间 |
|
||||||
|
|
||||||
|
## 🚀 快速开始
|
||||||
|
|
||||||
|
### 1. 启动应用
|
||||||
|
```bash
|
||||||
|
python main.py
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 访问API文档
|
||||||
|
- Swagger UI: http://127.0.0.1:8000/docs
|
||||||
|
- ReDoc: http://127.0.0.1:8000/redoc
|
||||||
|
|
||||||
|
### 3. 数据库管理
|
||||||
|
```bash
|
||||||
|
# 初始化数据库
|
||||||
|
python database_manager.py init
|
||||||
|
|
||||||
|
# 重置数据库
|
||||||
|
python database_manager.py reset
|
||||||
|
|
||||||
|
# 查看帮助
|
||||||
|
python database_manager.py help
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🔧 环境变量
|
||||||
|
|
||||||
|
可以通过环境变量覆盖配置:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export DB_HOST=localhost
|
||||||
|
export DB_PORT=3306
|
||||||
|
export DB_USER=root
|
||||||
|
export DB_PASSWORD=123456
|
||||||
|
export DB_NAME=fast_demo
|
||||||
|
```
|
||||||
|
|
||||||
|
## ✅ 验证配置
|
||||||
|
|
||||||
|
数据库连接已成功验证:
|
||||||
|
- ✅ 数据库 'fast_demo' 已存在
|
||||||
|
- ✅ 数据库连接成功
|
||||||
|
- ✅ 表 'users' 和 'products' 已创建
|
||||||
|
- ✅ 示例数据已插入
|
||||||
|
|
||||||
|
## 📝 注意事项
|
||||||
|
|
||||||
|
1. 确保MySQL服务正在运行
|
||||||
|
2. 确保用户 'root' 有访问数据库的权限
|
||||||
|
3. 开发环境配置已优化,包含热重载等功能
|
||||||
|
4. 生产环境请修改默认密码和配置
|
||||||
|
|
@ -0,0 +1,112 @@
|
||||||
|
# A generic, single database configuration.
|
||||||
|
|
||||||
|
[alembic]
|
||||||
|
# path to migration scripts
|
||||||
|
script_location = alembic
|
||||||
|
|
||||||
|
# template used to generate migration file names; The default value is %%(rev)s_%%(slug)s
|
||||||
|
# Uncomment the line below if you want the files to be prepended with date and time
|
||||||
|
# file_template = %%(year)d_%%(month).2d_%%(day).2d_%%(hour).2d%%(minute).2d-%%(rev)s_%%(slug)s
|
||||||
|
|
||||||
|
# sys.path path, will be prepended to sys.path if present.
|
||||||
|
# defaults to the current working directory.
|
||||||
|
prepend_sys_path = .
|
||||||
|
|
||||||
|
# timezone to use when rendering the date within the migration file
|
||||||
|
# as well as the filename.
|
||||||
|
# If specified, requires the python-dateutil library that can be
|
||||||
|
# installed by adding `alembic[tz]` to the pip requirements
|
||||||
|
# string value is passed to dateutil.tz.gettz()
|
||||||
|
# leave blank for localtime
|
||||||
|
# timezone =
|
||||||
|
|
||||||
|
# max length of characters to apply to the
|
||||||
|
# "slug" field
|
||||||
|
# truncate_slug_length = 40
|
||||||
|
|
||||||
|
# set to 'true' to run the environment during
|
||||||
|
# the 'revision' command, regardless of autogenerate
|
||||||
|
# revision_environment = false
|
||||||
|
|
||||||
|
# set to 'true' to allow .pyc and .pyo files without
|
||||||
|
# a source .py file to be detected as revisions in the
|
||||||
|
# versions/ directory
|
||||||
|
# sourceless = false
|
||||||
|
|
||||||
|
# version number format
|
||||||
|
version_num_format = %04d
|
||||||
|
|
||||||
|
# version path separator; As mentioned above, this is the character used to split
|
||||||
|
# version_locations. The default within new alembic.ini files is "os", which uses
|
||||||
|
# os.pathsep. If this key is omitted entirely, it falls back to the legacy
|
||||||
|
# behavior of splitting on spaces and/or commas.
|
||||||
|
# Valid values for version_path_separator are:
|
||||||
|
#
|
||||||
|
# version_path_separator = :
|
||||||
|
# version_path_separator = ;
|
||||||
|
# version_path_separator = space
|
||||||
|
version_path_separator = os
|
||||||
|
|
||||||
|
# set to 'true' to search source files recursively
|
||||||
|
# in each "version_locations" directory
|
||||||
|
# new in Alembic version 1.10
|
||||||
|
# recursive_version_locations = false
|
||||||
|
|
||||||
|
# the output encoding used when revision files
|
||||||
|
# are written from script.py.mako
|
||||||
|
# output_encoding = utf-8
|
||||||
|
|
||||||
|
sqlalchemy.url = mysql+pymysql://root:123456@localhost:3306/fast_demo?charset=utf8mb4
|
||||||
|
|
||||||
|
|
||||||
|
[post_write_hooks]
|
||||||
|
# post_write_hooks defines scripts or Python functions that are run
|
||||||
|
# on newly generated revision scripts. See the documentation for further
|
||||||
|
# detail and examples
|
||||||
|
|
||||||
|
# format using "black" - use the console_scripts runner, against the "black" entrypoint
|
||||||
|
# hooks = black
|
||||||
|
# black.type = console_scripts
|
||||||
|
# black.entrypoint = black
|
||||||
|
# black.options = -l 79 REVISION_SCRIPT_FILENAME
|
||||||
|
|
||||||
|
# lint with attempts to fix using "ruff" - use the exec runner, execute a binary
|
||||||
|
# hooks = ruff
|
||||||
|
# ruff.type = exec
|
||||||
|
# ruff.executable = %(here)s/.venv/bin/ruff
|
||||||
|
# ruff.options = --fix REVISION_SCRIPT_FILENAME
|
||||||
|
|
||||||
|
# Logging configuration
|
||||||
|
[loggers]
|
||||||
|
keys = root,sqlalchemy,alembic
|
||||||
|
|
||||||
|
[handlers]
|
||||||
|
keys = console
|
||||||
|
|
||||||
|
[formatters]
|
||||||
|
keys = generic
|
||||||
|
|
||||||
|
[logger_root]
|
||||||
|
level = WARN
|
||||||
|
handlers = console
|
||||||
|
qualname =
|
||||||
|
|
||||||
|
[logger_sqlalchemy]
|
||||||
|
level = WARN
|
||||||
|
handlers =
|
||||||
|
qualname = sqlalchemy.engine
|
||||||
|
|
||||||
|
[logger_alembic]
|
||||||
|
level = INFO
|
||||||
|
handlers =
|
||||||
|
qualname = alembic
|
||||||
|
|
||||||
|
[handler_console]
|
||||||
|
class = StreamHandler
|
||||||
|
args = (sys.stderr,)
|
||||||
|
level = NOTSET
|
||||||
|
formatter = generic
|
||||||
|
|
||||||
|
[formatter_generic]
|
||||||
|
format = %(levelname)-5.5s [%(name)s] %(message)s
|
||||||
|
datefmt = %H:%M:%S
|
||||||
|
|
@ -0,0 +1,93 @@
|
||||||
|
"""
|
||||||
|
Alembic 环境配置
|
||||||
|
"""
|
||||||
|
from logging.config import fileConfig
|
||||||
|
from sqlalchemy import engine_from_config
|
||||||
|
from sqlalchemy import pool
|
||||||
|
from alembic import context
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
# 添加项目根目录到 Python 路径
|
||||||
|
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||||
|
|
||||||
|
from app.database.models import Base
|
||||||
|
from app.core.config import settings
|
||||||
|
|
||||||
|
# this is the Alembic Config object, which provides
|
||||||
|
# access to the values within the .ini file in use.
|
||||||
|
config = context.config
|
||||||
|
|
||||||
|
# Interpret the config file for Python logging.
|
||||||
|
# This line sets up loggers basically.
|
||||||
|
if config.config_file_name is not None:
|
||||||
|
fileConfig(config.config_file_name)
|
||||||
|
|
||||||
|
# add your model's MetaData object here
|
||||||
|
# for 'autogenerate' support
|
||||||
|
target_metadata = Base.metadata
|
||||||
|
|
||||||
|
# other values from the config, defined by the needs of env.py,
|
||||||
|
# can be acquired:
|
||||||
|
# my_important_option = config.get_main_option("my_important_option")
|
||||||
|
# ... etc.
|
||||||
|
|
||||||
|
|
||||||
|
def get_url():
|
||||||
|
"""获取数据库连接URL"""
|
||||||
|
return settings.DATABASE_URL
|
||||||
|
|
||||||
|
|
||||||
|
def run_migrations_offline() -> None:
|
||||||
|
"""Run migrations in 'offline' mode.
|
||||||
|
|
||||||
|
This configures the context with just a URL
|
||||||
|
and not an Engine, though an Engine is acceptable
|
||||||
|
here as well. By skipping the Engine creation
|
||||||
|
we don't even need a DBAPI to be available.
|
||||||
|
|
||||||
|
Calls to context.execute() here emit the given string to the
|
||||||
|
script output.
|
||||||
|
|
||||||
|
"""
|
||||||
|
url = get_url()
|
||||||
|
context.configure(
|
||||||
|
url=url,
|
||||||
|
target_metadata=target_metadata,
|
||||||
|
literal_binds=True,
|
||||||
|
dialect_opts={"paramstyle": "named"},
|
||||||
|
)
|
||||||
|
|
||||||
|
with context.begin_transaction():
|
||||||
|
context.run_migrations()
|
||||||
|
|
||||||
|
|
||||||
|
def run_migrations_online() -> None:
|
||||||
|
"""Run migrations in 'online' mode.
|
||||||
|
|
||||||
|
In this scenario we need to create an Engine
|
||||||
|
and associate a connection with the context.
|
||||||
|
|
||||||
|
"""
|
||||||
|
configuration = config.get_section(config.config_ini_section)
|
||||||
|
configuration["sqlalchemy.url"] = get_url()
|
||||||
|
|
||||||
|
connectable = engine_from_config(
|
||||||
|
configuration,
|
||||||
|
prefix="sqlalchemy.",
|
||||||
|
poolclass=pool.NullPool,
|
||||||
|
)
|
||||||
|
|
||||||
|
with connectable.connect() as connection:
|
||||||
|
context.configure(
|
||||||
|
connection=connection, target_metadata=target_metadata
|
||||||
|
)
|
||||||
|
|
||||||
|
with context.begin_transaction():
|
||||||
|
context.run_migrations()
|
||||||
|
|
||||||
|
|
||||||
|
if context.is_offline_mode():
|
||||||
|
run_migrations_offline()
|
||||||
|
else:
|
||||||
|
run_migrations_online()
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
"""${message}
|
||||||
|
|
||||||
|
Revision ID: ${up_revision}
|
||||||
|
Revises: ${down_revision | comma,n}
|
||||||
|
Create Date: ${create_date}
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
${imports if imports else ""}
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = ${repr(up_revision)}
|
||||||
|
down_revision = ${repr(down_revision)}
|
||||||
|
branch_labels = ${repr(branch_labels)}
|
||||||
|
depends_on = ${repr(depends_on)}
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade() -> None:
|
||||||
|
${upgrades if upgrades else "pass"}
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade() -> None:
|
||||||
|
${downgrades if downgrades else "pass"}
|
||||||
|
|
@ -96,6 +96,12 @@ def register_events(app: FastAPI) -> None:
|
||||||
# 可以在这里添加启动时的初始化操作
|
# 可以在这里添加启动时的初始化操作
|
||||||
# 如:数据库连接、缓存初始化等
|
# 如:数据库连接、缓存初始化等
|
||||||
|
|
||||||
|
# 创建数据库表(如果不存在)
|
||||||
|
from app.database.connection import engine
|
||||||
|
from app.database.models import Base
|
||||||
|
Base.metadata.create_all(bind=engine)
|
||||||
|
print("[INFO] Database tables created/verified successfully")
|
||||||
|
|
||||||
@app.on_event("shutdown")
|
@app.on_event("shutdown")
|
||||||
async def shutdown_event():
|
async def shutdown_event():
|
||||||
"""应用关闭时执行"""
|
"""应用关闭时执行"""
|
||||||
|
|
|
||||||
|
|
@ -30,10 +30,25 @@ class Settings(BaseSettings):
|
||||||
REDOC_URL: Optional[str] = "/redoc"
|
REDOC_URL: Optional[str] = "/redoc"
|
||||||
|
|
||||||
# === 数据库配置 ===
|
# === 数据库配置 ===
|
||||||
DATABASE_URL: Optional[str] = None
|
# MySQL 数据库配置
|
||||||
|
DB_HOST: str = "localhost"
|
||||||
|
DB_PORT: int = 3306
|
||||||
|
DB_USER: str = "root"
|
||||||
|
DB_PASSWORD: str = "123456"
|
||||||
|
DB_NAME: str = "fast_demo"
|
||||||
|
DB_CHARSET: str = "utf8mb4"
|
||||||
|
|
||||||
|
# 数据库连接池配置
|
||||||
DB_ECHO: bool = False
|
DB_ECHO: bool = False
|
||||||
DB_POOL_SIZE: int = 5
|
DB_POOL_SIZE: int = 5
|
||||||
DB_MAX_OVERFLOW: int = 10
|
DB_MAX_OVERFLOW: int = 10
|
||||||
|
DB_POOL_TIMEOUT: int = 30
|
||||||
|
DB_POOL_RECYCLE: int = 3600
|
||||||
|
|
||||||
|
@property
|
||||||
|
def DATABASE_URL(self) -> str:
|
||||||
|
"""构建数据库连接URL"""
|
||||||
|
return f"mysql+pymysql://{self.DB_USER}:{self.DB_PASSWORD}@{self.DB_HOST}:{self.DB_PORT}/{self.DB_NAME}?charset={self.DB_CHARSET}"
|
||||||
|
|
||||||
# === Redis 配置 ===
|
# === Redis 配置 ===
|
||||||
REDIS_HOST: str = "localhost"
|
REDIS_HOST: str = "localhost"
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
"""
|
||||||
|
数据库模块
|
||||||
|
"""
|
||||||
|
from .connection import engine, SessionLocal, get_db
|
||||||
|
from .base import Base
|
||||||
|
|
||||||
|
__all__ = ["engine", "SessionLocal", "get_db", "Base"]
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
"""
|
||||||
|
数据库基础模型类
|
||||||
|
"""
|
||||||
|
from sqlalchemy.ext.declarative import declarative_base
|
||||||
|
|
||||||
|
Base = declarative_base()
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
"""
|
||||||
|
数据库连接管理
|
||||||
|
"""
|
||||||
|
from sqlalchemy import create_engine
|
||||||
|
from sqlalchemy.ext.declarative import declarative_base
|
||||||
|
from sqlalchemy.orm import sessionmaker
|
||||||
|
from app.core.config import settings
|
||||||
|
|
||||||
|
# 创建数据库引擎
|
||||||
|
engine = create_engine(
|
||||||
|
settings.DATABASE_URL,
|
||||||
|
echo=settings.DB_ECHO,
|
||||||
|
pool_size=settings.DB_POOL_SIZE,
|
||||||
|
max_overflow=settings.DB_MAX_OVERFLOW,
|
||||||
|
pool_timeout=settings.DB_POOL_TIMEOUT,
|
||||||
|
pool_recycle=settings.DB_POOL_RECYCLE,
|
||||||
|
pool_pre_ping=True, # 连接前测试连接是否有效
|
||||||
|
)
|
||||||
|
|
||||||
|
# 创建会话工厂
|
||||||
|
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
||||||
|
|
||||||
|
# 创建基础模型类
|
||||||
|
Base = declarative_base()
|
||||||
|
|
||||||
|
|
||||||
|
def get_db():
|
||||||
|
"""
|
||||||
|
获取数据库会话的依赖注入函数
|
||||||
|
"""
|
||||||
|
db = SessionLocal()
|
||||||
|
try:
|
||||||
|
yield db
|
||||||
|
finally:
|
||||||
|
db.close()
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
"""
|
||||||
|
SQLAlchemy 数据库模型
|
||||||
|
"""
|
||||||
|
from sqlalchemy import Column, Integer, String, Float, Boolean, DateTime, Text
|
||||||
|
from sqlalchemy.sql import func
|
||||||
|
from .base import Base
|
||||||
|
|
||||||
|
|
||||||
|
class User(Base):
|
||||||
|
"""用户表"""
|
||||||
|
__tablename__ = "users"
|
||||||
|
|
||||||
|
id = Column(Integer, primary_key=True, index=True, autoincrement=True)
|
||||||
|
username = Column(String(50), unique=True, index=True, nullable=False, comment="用户名")
|
||||||
|
email = Column(String(100), unique=True, index=True, nullable=False, comment="邮箱")
|
||||||
|
full_name = Column(String(100), nullable=True, comment="全名")
|
||||||
|
is_active = Column(Boolean, default=True, nullable=False, comment="是否激活")
|
||||||
|
created_at = Column(DateTime(timezone=True), server_default=func.now(), comment="创建时间")
|
||||||
|
updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now(), comment="更新时间")
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f"<User(id={self.id}, username='{self.username}', email='{self.email}')>"
|
||||||
|
|
||||||
|
|
||||||
|
class Product(Base):
|
||||||
|
"""产品表"""
|
||||||
|
__tablename__ = "products"
|
||||||
|
|
||||||
|
id = Column(Integer, primary_key=True, index=True, autoincrement=True)
|
||||||
|
name = Column(String(200), nullable=False, comment="产品名称")
|
||||||
|
description = Column(Text, nullable=True, comment="产品描述")
|
||||||
|
price = Column(Float, nullable=False, comment="价格")
|
||||||
|
stock = Column(Integer, default=0, nullable=False, comment="库存数量")
|
||||||
|
is_available = Column(Boolean, default=True, nullable=False, comment="是否可用")
|
||||||
|
created_at = Column(DateTime(timezone=True), server_default=func.now(), comment="创建时间")
|
||||||
|
updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now(), comment="更新时间")
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f"<Product(id={self.id}, name='{self.name}', price={self.price})>"
|
||||||
|
|
@ -0,0 +1,139 @@
|
||||||
|
"""
|
||||||
|
数据库管理脚本
|
||||||
|
用于初始化数据库、运行迁移、插入测试数据等
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import asyncio
|
||||||
|
from sqlalchemy import create_engine, text
|
||||||
|
from app.core.config import settings
|
||||||
|
from app.database.models import Base
|
||||||
|
|
||||||
|
|
||||||
|
def create_database():
|
||||||
|
"""创建数据库(如果不存在)"""
|
||||||
|
# 连接到MySQL服务器(不指定数据库)
|
||||||
|
server_url = f"mysql+pymysql://{settings.DB_USER}:{settings.DB_PASSWORD}@{settings.DB_HOST}:{settings.DB_PORT}/"
|
||||||
|
engine = create_engine(server_url)
|
||||||
|
|
||||||
|
with engine.connect() as conn:
|
||||||
|
# 创建数据库
|
||||||
|
conn.execute(text(f"CREATE DATABASE IF NOT EXISTS `{settings.DB_NAME}` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci"))
|
||||||
|
print(f"✅ 数据库 '{settings.DB_NAME}' 创建成功")
|
||||||
|
|
||||||
|
|
||||||
|
def create_tables():
|
||||||
|
"""创建数据库表"""
|
||||||
|
engine = create_engine(settings.DATABASE_URL)
|
||||||
|
Base.metadata.create_all(bind=engine)
|
||||||
|
print("✅ 数据库表创建成功")
|
||||||
|
|
||||||
|
|
||||||
|
def run_sql_file(file_path):
|
||||||
|
"""运行SQL文件"""
|
||||||
|
if not os.path.exists(file_path):
|
||||||
|
print(f"❌ SQL文件不存在: {file_path}")
|
||||||
|
return
|
||||||
|
|
||||||
|
engine = create_engine(settings.DATABASE_URL)
|
||||||
|
|
||||||
|
with open(file_path, 'r', encoding='utf-8') as f:
|
||||||
|
sql_content = f.read()
|
||||||
|
|
||||||
|
with engine.connect() as conn:
|
||||||
|
# 分割SQL语句并执行
|
||||||
|
statements = [stmt.strip() for stmt in sql_content.split(';') if stmt.strip()]
|
||||||
|
for statement in statements:
|
||||||
|
if statement:
|
||||||
|
conn.execute(text(statement))
|
||||||
|
conn.commit()
|
||||||
|
|
||||||
|
print(f"✅ SQL文件执行成功: {file_path}")
|
||||||
|
|
||||||
|
|
||||||
|
def init_database():
|
||||||
|
"""初始化数据库"""
|
||||||
|
print("🚀 开始初始化数据库...")
|
||||||
|
|
||||||
|
# 1. 创建数据库
|
||||||
|
create_database()
|
||||||
|
|
||||||
|
# 2. 创建表
|
||||||
|
create_tables()
|
||||||
|
|
||||||
|
# 3. 插入示例数据
|
||||||
|
sample_data_file = "sql/seeds/sample_data.sql"
|
||||||
|
if os.path.exists(sample_data_file):
|
||||||
|
run_sql_file(sample_data_file)
|
||||||
|
|
||||||
|
print("🎉 数据库初始化完成!")
|
||||||
|
|
||||||
|
|
||||||
|
def reset_database():
|
||||||
|
"""重置数据库"""
|
||||||
|
print("⚠️ 重置数据库...")
|
||||||
|
|
||||||
|
# 删除并重新创建数据库
|
||||||
|
server_url = f"mysql+pymysql://{settings.DB_USER}:{settings.DB_PASSWORD}@{settings.DB_HOST}:{settings.DB_PORT}/"
|
||||||
|
engine = create_engine(server_url)
|
||||||
|
|
||||||
|
with engine.connect() as conn:
|
||||||
|
conn.execute(text(f"DROP DATABASE IF EXISTS `{settings.DB_NAME}`"))
|
||||||
|
print(f"🗑️ 数据库 '{settings.DB_NAME}' 已删除")
|
||||||
|
|
||||||
|
# 重新初始化
|
||||||
|
init_database()
|
||||||
|
|
||||||
|
|
||||||
|
def show_help():
|
||||||
|
"""显示帮助信息"""
|
||||||
|
print("""
|
||||||
|
数据库管理脚本使用说明:
|
||||||
|
|
||||||
|
python database_manager.py init - 初始化数据库(创建数据库和表)
|
||||||
|
python database_manager.py reset - 重置数据库(删除并重新创建)
|
||||||
|
python database_manager.py create-db - 仅创建数据库
|
||||||
|
python database_manager.py create-tables - 仅创建表
|
||||||
|
python database_manager.py seed - 仅插入示例数据
|
||||||
|
python database_manager.py help - 显示此帮助信息
|
||||||
|
|
||||||
|
环境变量配置:
|
||||||
|
- DB_HOST: 数据库主机 (默认: localhost)
|
||||||
|
- DB_PORT: 数据库端口 (默认: 3306)
|
||||||
|
- DB_USER: 数据库用户名 (默认: root)
|
||||||
|
- DB_PASSWORD: 数据库密码 (默认: 空)
|
||||||
|
- DB_NAME: 数据库名称 (默认: fastapi_demo)
|
||||||
|
""")
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""主函数"""
|
||||||
|
if len(sys.argv) < 2:
|
||||||
|
show_help()
|
||||||
|
return
|
||||||
|
|
||||||
|
command = sys.argv[1].lower()
|
||||||
|
|
||||||
|
try:
|
||||||
|
if command == "init":
|
||||||
|
init_database()
|
||||||
|
elif command == "reset":
|
||||||
|
reset_database()
|
||||||
|
elif command == "create-db":
|
||||||
|
create_database()
|
||||||
|
elif command == "create-tables":
|
||||||
|
create_tables()
|
||||||
|
elif command == "seed":
|
||||||
|
run_sql_file("sql/seeds/sample_data.sql")
|
||||||
|
elif command == "help":
|
||||||
|
show_help()
|
||||||
|
else:
|
||||||
|
print(f"❌ 未知命令: {command}")
|
||||||
|
show_help()
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ 执行失败: {str(e)}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
|
@ -4,3 +4,9 @@ pydantic==2.8.0
|
||||||
pydantic-settings==2.1.0
|
pydantic-settings==2.1.0
|
||||||
python-multipart==0.0.6
|
python-multipart==0.0.6
|
||||||
email-validator==2.1.0
|
email-validator==2.1.0
|
||||||
|
|
||||||
|
# 数据库相关依赖
|
||||||
|
sqlalchemy>=2.0.30
|
||||||
|
alembic>=1.13.1
|
||||||
|
pymysql>=1.1.0
|
||||||
|
cryptography>=41.0.0
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
-- 迁移文件:创建基础表结构
|
||||||
|
-- 创建时间:2024-01-01
|
||||||
|
-- 描述:创建用户表和产品表
|
||||||
|
|
||||||
|
-- 创建用户表
|
||||||
|
CREATE TABLE IF NOT EXISTS `users` (
|
||||||
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||||
|
`username` varchar(50) NOT NULL COMMENT '用户名',
|
||||||
|
`email` varchar(100) NOT NULL COMMENT '邮箱',
|
||||||
|
`full_name` varchar(100) DEFAULT NULL COMMENT '全名',
|
||||||
|
`is_active` tinyint(1) NOT NULL DEFAULT '1' COMMENT '是否激活',
|
||||||
|
`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||||
|
`updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `username` (`username`),
|
||||||
|
UNIQUE KEY `email` (`email`),
|
||||||
|
KEY `idx_username` (`username`),
|
||||||
|
KEY `idx_email` (`email`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户表';
|
||||||
|
|
||||||
|
-- 创建产品表
|
||||||
|
CREATE TABLE IF NOT EXISTS `products` (
|
||||||
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||||
|
`name` varchar(200) NOT NULL COMMENT '产品名称',
|
||||||
|
`description` text COMMENT '产品描述',
|
||||||
|
`price` decimal(10,2) NOT NULL COMMENT '价格',
|
||||||
|
`stock` int(11) NOT NULL DEFAULT '0' COMMENT '库存数量',
|
||||||
|
`is_available` tinyint(1) NOT NULL DEFAULT '1' COMMENT '是否可用',
|
||||||
|
`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||||
|
`updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `idx_name` (`name`),
|
||||||
|
KEY `idx_price` (`price`),
|
||||||
|
KEY `idx_is_available` (`is_available`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='产品表';
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
-- 创建数据库
|
||||||
|
CREATE DATABASE IF NOT EXISTS `fastapi_demo`
|
||||||
|
DEFAULT CHARACTER SET utf8mb4
|
||||||
|
COLLATE utf8mb4_unicode_ci;
|
||||||
|
|
||||||
|
-- 使用数据库
|
||||||
|
USE `fastapi_demo`;
|
||||||
|
|
||||||
|
-- 创建用户表
|
||||||
|
CREATE TABLE IF NOT EXISTS `users` (
|
||||||
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||||
|
`username` varchar(50) NOT NULL COMMENT '用户名',
|
||||||
|
`email` varchar(100) NOT NULL COMMENT '邮箱',
|
||||||
|
`full_name` varchar(100) DEFAULT NULL COMMENT '全名',
|
||||||
|
`is_active` tinyint(1) NOT NULL DEFAULT '1' COMMENT '是否激活',
|
||||||
|
`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||||
|
`updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `username` (`username`),
|
||||||
|
UNIQUE KEY `email` (`email`),
|
||||||
|
KEY `idx_username` (`username`),
|
||||||
|
KEY `idx_email` (`email`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户表';
|
||||||
|
|
||||||
|
-- 创建产品表
|
||||||
|
CREATE TABLE IF NOT EXISTS `products` (
|
||||||
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||||
|
`name` varchar(200) NOT NULL COMMENT '产品名称',
|
||||||
|
`description` text COMMENT '产品描述',
|
||||||
|
`price` decimal(10,2) NOT NULL COMMENT '价格',
|
||||||
|
`stock` int(11) NOT NULL DEFAULT '0' COMMENT '库存数量',
|
||||||
|
`is_available` tinyint(1) NOT NULL DEFAULT '1' COMMENT '是否可用',
|
||||||
|
`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||||
|
`updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `idx_name` (`name`),
|
||||||
|
KEY `idx_price` (`price`),
|
||||||
|
KEY `idx_is_available` (`is_available`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='产品表';
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
-- 插入示例用户数据
|
||||||
|
INSERT INTO `users` (`username`, `email`, `full_name`, `is_active`) VALUES
|
||||||
|
('admin', 'admin@example.com', '管理员', 1),
|
||||||
|
('john_doe', 'john@example.com', 'John Doe', 1),
|
||||||
|
('jane_smith', 'jane@example.com', 'Jane Smith', 1),
|
||||||
|
('bob_wilson', 'bob@example.com', 'Bob Wilson', 0);
|
||||||
|
|
||||||
|
-- 插入示例产品数据
|
||||||
|
INSERT INTO `products` (`name`, `description`, `price`, `stock`, `is_available`) VALUES
|
||||||
|
('iPhone 15 Pro', '苹果最新旗舰手机,配备A17 Pro芯片', 9999.00, 50, 1),
|
||||||
|
('MacBook Pro 16"', '专业级笔记本电脑,M3 Max芯片', 19999.00, 20, 1),
|
||||||
|
('AirPods Pro', '主动降噪无线耳机', 1999.00, 100, 1),
|
||||||
|
('iPad Air', '轻薄便携的平板电脑', 4399.00, 30, 1),
|
||||||
|
('Apple Watch Series 9', '智能手表,健康监测', 2999.00, 80, 1),
|
||||||
|
('Magic Keyboard', '无线键盘,支持多设备连接', 999.00, 0, 0);
|
||||||
Loading…
Reference in New Issue