170 lines
4.8 KiB
Markdown
170 lines
4.8 KiB
Markdown
# 同步编程模型
|
|
|
|
:::tip 核心原则
|
|
Flask 基于 WSGI 同步框架,所有视图函数和业务代码均为同步 `def`。通过多线程/多进程实现并发,代码简洁直观,调试方便。
|
|
:::
|
|
|
|
## Flask 的执行模型
|
|
|
|
Flask 采用同步编程模型,所有请求处理在独立的线程中执行:
|
|
|
|
```
|
|
客户端请求
|
|
↓
|
|
WSGI 服务器(Gunicorn / Flask 内置)
|
|
↓
|
|
分配线程处理请求
|
|
↓
|
|
Flask 路由分发 → 视图函数 → Service → Repository → 数据库
|
|
↓
|
|
返回响应(同步等待完成)
|
|
```
|
|
|
|
所有业务代码均为同步 `def`,数据库操作通过 SQLAlchemy 同步 ORM 完成,Redis 操作通过同步客户端完成。
|
|
|
|
## 为什么选择同步模型
|
|
|
|
| 考量 | 说明 |
|
|
|:---|:---|
|
|
| **成熟稳定** | Flask 同步模型经过长期验证,生态完善 |
|
|
| **代码简洁** | 直接调用,无异步包装开销 |
|
|
| **调试方便** | 标准 Python 调试工具(pdb)直接可用 |
|
|
| **学习曲线** | 同步编程更直观,团队上手快 |
|
|
| **后台管理** | CRUD 为主的场景,同步模型完全够用 |
|
|
|
|
## 代码示例:全同步模式
|
|
|
|
### Router 层
|
|
|
|
```python
|
|
# src/modules/system/position/router.py
|
|
from flask import Blueprint, request
|
|
|
|
from src.core.permission import check_permission
|
|
from src.modules.system.position import service as position
|
|
from src.common.utils.request import parse_request_body
|
|
from src.core import response as R
|
|
|
|
position_blue = Blueprint('position', __name__, url_prefix='/position')
|
|
|
|
|
|
@position_blue.route('/page', methods=["GET"])
|
|
@check_permission("sys:position:page")
|
|
def page():
|
|
"""
|
|
查询岗位分页数据
|
|
|
|
同步函数:直接调用 service,无需 await。
|
|
"""
|
|
return R.ok(data=position.get_position_page(request.args))
|
|
|
|
|
|
@position_blue.route('/add', methods=["POST"])
|
|
@check_permission("sys:position:add")
|
|
def add():
|
|
"""
|
|
添加岗位
|
|
|
|
同步函数:解析请求体 → 调用 service → 返回结果。
|
|
"""
|
|
json_data, err = parse_request_body()
|
|
if err:
|
|
return R.failed(msg=err)
|
|
position.add_position(json_data)
|
|
return R.ok(msg="添加成功")
|
|
```
|
|
|
|
### Service 层
|
|
|
|
```python
|
|
# src/modules/system/position/service.py
|
|
from src.common.base_service import BaseService
|
|
from src.core.exceptions import BizError
|
|
from src.modules.system.position.schema import PositionForm, PositionStatusForm
|
|
from src.modules.system.position.repository import PositionRepository
|
|
from src.modules.system.user.repository import UserRepository
|
|
|
|
|
|
class PositionService(BaseService):
|
|
"""
|
|
岗位服务类
|
|
|
|
所有方法均为同步 classmethod,直接调用 Repository 访问数据库。
|
|
"""
|
|
repository = PositionRepository
|
|
form = PositionForm
|
|
status_form = PositionStatusForm
|
|
model_name = "岗位"
|
|
|
|
@classmethod
|
|
def before_delete(cls, ids):
|
|
"""删除前校验:检查用户引用"""
|
|
for pid in ids:
|
|
if UserRepository.count_by({'position_id': pid}) > 0:
|
|
raise BizError(f"岗位ID {pid} 已被用户引用,无法删除")
|
|
|
|
|
|
# 模块级代理函数
|
|
get_position_page = PositionService.get_page
|
|
add_position = PositionService.add
|
|
```
|
|
|
|
### Repository 层
|
|
|
|
```python
|
|
# src/modules/system/position/repository.py
|
|
from src.common.base_repository import BaseRepository
|
|
from src.common.constants.common import PAGE_SIZE
|
|
from src.modules.system.position.models import Position
|
|
|
|
|
|
class PositionRepository(BaseRepository):
|
|
"""岗位数据仓储,所有查询方法均为同步 classmethod"""
|
|
model = Position
|
|
|
|
@classmethod
|
|
def page(cls, params: dict):
|
|
"""分页查询:直接调用基类 find_page,同步执行"""
|
|
return cls.find_page(
|
|
page=int(params.get('pageNo', 1)),
|
|
page_size=int(params.get('pageSize', PAGE_SIZE)),
|
|
filters={'status': params.get('status')},
|
|
like_filters={'name': params.get('name')},
|
|
order_by='sort',
|
|
)
|
|
```
|
|
|
|
:::tip 全链路同步
|
|
从 Router → Service → Repository → 数据库,全链路均为同步调用,代码简洁直观。
|
|
:::
|
|
|
|
## Redis 操作也是同步的
|
|
|
|
项目使用 `redis-py` 同步客户端,所有 Redis 操作也是同步的:
|
|
|
|
```python
|
|
# src/core/redis_client.py
|
|
from redis import Redis
|
|
|
|
redis = Redis.from_url(REDIS_URL, decode_responses=True)
|
|
```
|
|
|
|
```python
|
|
# 使用示例(同步)
|
|
from src.core.redis_client import redis
|
|
|
|
# 存储验证码
|
|
redis.set(f"captcha:{key}", code, ex=300)
|
|
|
|
# 查询验证码
|
|
cached_code = redis.get(f"captcha:{key}")
|
|
|
|
# 登录失败计数
|
|
count = redis.incr(f"login:fail:{ip}:{username}")
|
|
redis.expire(f"login:fail:{ip}:{username}", 300)
|
|
```
|
|
|
|
## 总结
|
|
|
|
项目采用 Flask 同步架构,全链路(Router → Service → Repository → Redis → 数据库)均为同步 `def`,代码简洁直观。通过 WSGI 服务器的多线程/多进程模型实现并发处理,对于后台管理系统场景完全够用。
|