4. 数据库设计与ORM:风控规则表、交易流水表、账户表设计、SQLAlchemy异步ORM配置、Alembic迁移管理
实时交易风控系统的核心是数据。所有风控规则的判定、交易流水的记录、账户状态的维护,最终都依赖数据库的稳定与高效。本章将围绕三张核心表(风控规则表、交易流水表、账户表)展开,讲解如何基于 PostgreSQL 进行表结构设计,并配置 SQLAlchemy 异步 ORM 与 Alembic 迁移管理,为后续的 API 开发打下坚实的数据基础。
4.1 核心表结构设计
我们采用 三表分离 的设计模式:risk_rules 存储风控规则定义,transactions 存储每笔交易流水,accounts 存储账户摘要与风控状态。三表通过 account_id 关联,形成完整的数据闭环。
| 表名 | 核心字段 | 主键/索引 | 用途 |
|---|---|---|---|
risk_rules |
rule_id, rule_name, rule_type, config_json, is_active, priority, created_at | PRIMARY KEY (rule_id), INDEX (rule_type, is_active) | 定义风控规则(如单笔限额、频率限制、黑名单) |
transactions |
txn_id, account_id, amount, currency, txn_type, status, risk_level, created_at | PRIMARY KEY (txn_id), INDEX (account_id, created_at), INDEX (status) | 记录每笔交易流水,用于事后审计与实时风控判定 |
accounts |
account_id, balance, frozen_amount, risk_score, is_blocked, last_txn_at, version | PRIMARY KEY (account_id), UNIQUE (account_id) | 维护账户余额、冻结金额、风控评分与乐观锁版本号 |
4.1.1 风控规则表(risk_rules)
规则表采用 配置化 设计,将规则参数以 JSON 格式存储在 config_json 字段中,避免频繁修改表结构。例如,单笔限额规则可配置为:{"max_amount": 100000, "currency": "CNY"}。
-- 风控规则表 DDL
CREATE TABLE risk_rules (
rule_id BIGSERIAL PRIMARY KEY,
rule_name VARCHAR(128) NOT NULL,
rule_type VARCHAR(32) NOT NULL, -- 'amount_limit', 'frequency', 'blacklist', 'velocity'
config_json JSONB NOT NULL DEFAULT '{}',
is_active BOOLEAN NOT NULL DEFAULT TRUE,
priority INT NOT NULL DEFAULT 0,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_rules_type_active ON risk_rules(rule_type, is_active);
4.1.2 交易流水表(transactions)
交易流水表是系统中最繁忙的表,每秒可能写入数千条记录。我们使用 复合索引 加速按账户和时间范围的查询,并考虑按时间分区以提升维护效率。
-- 交易流水表 DDL(含分区示例)
CREATE TABLE transactions (
txn_id BIGSERIAL,
account_id BIGINT NOT NULL,
amount NUMERIC(20,4) NOT NULL,
currency CHAR(3) NOT NULL DEFAULT 'CNY',
txn_type VARCHAR(16) NOT NULL, -- 'deposit', 'withdraw', 'transfer'
status VARCHAR(16) NOT NULL DEFAULT 'pending', -- 'pending','approved','rejected'
risk_level VARCHAR(8) DEFAULT 'low', -- 'low','medium','high'
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
) PARTITION BY RANGE (created_at);
-- 创建分区(示例:按月分区)
CREATE TABLE transactions_202501 PARTITION OF transactions
FOR VALUES FROM ('2025-01-01') TO ('2025-02-01');
CREATE INDEX idx_tx_account_time ON transactions(account_id, created_at DESC);
CREATE INDEX idx_tx_status ON transactions(status);
4.1.3 账户表(accounts)
账户表使用 乐观锁(version 字段)防止并发更新导致的数据不一致。每次更新余额时,需校验 version 是否与读取时一致。
-- 账户表 DDL
CREATE TABLE accounts (
account_id BIGSERIAL PRIMARY KEY,
balance NUMERIC(20,4) NOT NULL DEFAULT 0.0000,
frozen_amount NUMERIC(20,4) NOT NULL DEFAULT 0.0000,
risk_score INT NOT NULL DEFAULT 0, -- 0-100
is_blocked BOOLEAN NOT NULL DEFAULT FALSE,
last_txn_at TIMESTAMPTZ,
version INT NOT NULL DEFAULT 1, -- 乐观锁版本号
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
4.2 三表关系与数据流
下图展示了三张核心表之间的关联关系以及实时风控判定的数据流向:
4.3 SQLAlchemy 异步 ORM 配置
在实时交易系统中,同步数据库操作会阻塞事件循环,导致吞吐量下降。我们使用 SQLAlchemy 的 异步扩展(asyncpg 驱动 + asyncio 模式)来避免阻塞。
4.3.1 安装依赖
pip install sqlalchemy[asyncio] asyncpg alembic
4.3.2 创建异步引擎与会话工厂
# config/database.py
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession, async_sessionmaker
from sqlalchemy.orm import DeclarativeBase
DATABASE_URL = "postgresql+asyncpg://user:password@localhost:5432/risk_control"
engine = create_async_engine(DATABASE_URL, echo=True, pool_size=10, max_overflow=20)
async_session_factory = async_sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)
class Base(DeclarativeBase):
pass
4.3.3 定义 ORM 模型
以 Account 模型为例,展示异步 ORM 的字段定义与乐观锁实现:
# models/account.py
from sqlalchemy import Column, BigInteger, Numeric, Integer, Boolean, DateTime, func
from config.database import Base
class Account(Base):
__tablename__ = "accounts"
account_id = Column(BigInteger, primary_key=True, autoincrement=True)
balance = Column(Numeric(20, 4), nullable=False, default=0)
frozen_amount = Column(Numeric(20, 4), nullable=False, default=0)
risk_score = Column(Integer, nullable=False, default=0)
is_blocked = Column(Boolean, nullable=False, default=False)
last_txn_at = Column(DateTime(timezone=True), nullable=True)
version = Column(Integer, nullable=False, default=1)
created_at = Column(DateTime(timezone=True), server_default=func.now())
updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now())
4.3.4 异步 CRUD 示例
# repositories/account_repo.py
from sqlalchemy import select, update
from sqlalchemy.ext.asyncio import AsyncSession
from models.account import Account
async def get_account_by_id(db: AsyncSession, account_id: int) -> Account | None:
result = await db.execute(select(Account).where(Account.account_id == account_id))
return result.scalar_one_or_none()
async def update_balance_with_optimistic_lock(
db: AsyncSession, account_id: int, new_balance: float, current_version: int
) -> bool:
stmt = (
update(Account)
.where(Account.account_id == account_id, Account.version == current_version)
.values(balance=new_balance, version=current_version + 1)
)
result = await db.execute(stmt)
await db.commit()
return result.rowcount > 0 # 返回 True 表示更新成功,False 表示版本冲突
await 调用。不要在异步上下文中混用同步 Session,否则会导致事件循环阻塞。
4.4 Alembic 迁移管理
Alembic 是 SQLAlchemy 的官方迁移工具,支持自动生成迁移脚本、版本回滚、多环境同步。在异步项目中,需配置 run_async=True 以支持异步引擎。
4.4.1 初始化 Alembic
alembic init alembic
4.4.2 配置 alembic.ini 与 env.py
修改 alembic.ini 中的数据库连接字符串:
sqlalchemy.url = postgresql+asyncpg://user:password@localhost:5432/risk_control
修改 alembic/env.py 以支持异步:
# alembic/env.py
from config.database import Base, engine
from models import Account, Transaction, RiskRule # 导入所有模型
target_metadata = Base.metadata
def run_migrations_online():
# 使用异步引擎运行迁移
with engine.connect() as connection:
context.configure(connection=connection, target_metadata=target_metadata)
with context.begin_transaction():
context.run_migrations()
4.4.3 生成并执行迁移
# 生成迁移脚本(自动检测模型变更)
alembic revision --autogenerate -m "add accounts table"
# 查看生成的迁移脚本
alembic history
# 执行迁移(升级到最新版本)
alembic upgrade head
# 回滚一个版本
alembic downgrade -1
| Alembic 命令 | 说明 | 常用场景 |
|---|---|---|
alembic init |
初始化迁移目录 | 项目首次搭建时 |
alembic revision --autogenerate |
自动生成迁移脚本 | 模型字段变更后 |
alembic upgrade head |
升级到最新版本 | 部署/同步数据库 |
alembic downgrade -1 |
回滚一个版本 | 迁移出错时快速回退 |
alembic history |
查看迁移历史 | 确认当前版本位置 |
4.5 本章小结
本章完成了实时交易风控系统的数据库层设计:
- 三表设计:
risk_rules(规则配置)、transactions(交易流水)、accounts(账户状态),满足读写分离与高并发需求。 - 异步 ORM:基于 SQLAlchemy + asyncpg 实现非阻塞数据库操作,避免事件循环阻塞。
- 迁移管理:使用 Alembic 管理数据库版本,支持自动生成迁移脚本与回滚。