Python数据库设计模式:从ORM到数据层架构
·
Python数据库设计模式:从ORM到数据层架构
引言
数据库设计是后端开发的核心环节。作为从Python转向Rust的后端开发者,我发现Python的数据库生态非常成熟,尤其是SQLAlchemy提供了强大的ORM能力。本文将深入探讨Python数据库设计模式,帮助你构建高效、可维护的数据层架构。
一、数据库设计基础
1.1 设计原则
| 原则 | 描述 |
|---|---|
| 规范化 | 消除数据冗余,避免更新异常 |
| 反规范化 | 为性能牺牲部分规范化 |
| 索引优化 | 合理创建索引提升查询性能 |
| 数据完整性 | 约束保证数据一致性 |
1.2 ER图设计
用户(用户ID, 用户名, 邮箱, 密码)
订单(订单ID, 用户ID, 订单日期, 状态)
订单商品(订单ID, 商品ID, 数量, 单价)
商品(商品ID, 名称, 价格, 库存)
二、ORM模式
2.1 SQLAlchemy基础
from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
Base = declarative_base()
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
username = Column(String(50), unique=True, nullable=False)
email = Column(String(100), unique=True, nullable=False)
def __repr__(self):
return f"<User(id={self.id}, username='{self.username}')>"
# 创建引擎和会话
engine = create_engine('sqlite:///example.db')
Session = sessionmaker(bind=engine)
session = Session()
2.2 CRUD操作
# 创建
user = User(username='alice', email='alice@example.com')
session.add(user)
session.commit()
# 读取
user = session.query(User).filter_by(username='alice').first()
# 更新
user.email = 'new_email@example.com'
session.commit()
# 删除
session.delete(user)
session.commit()
2.3 关系映射
from sqlalchemy import ForeignKey
from sqlalchemy.orm import relationship
class Order(Base):
__tablename__ = 'orders'
id = Column(Integer, primary_key=True)
user_id = Column(Integer, ForeignKey('users.id'))
status = Column(String(20))
user = relationship('User', back_populates='orders')
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
username = Column(String(50))
orders = relationship('Order', back_populates='user')
三、数据访问模式
3.1 Repository模式
from abc import ABC, abstractmethod
from typing import List, Optional
class UserRepository(ABC):
@abstractmethod
def get_by_id(self, user_id: int) -> Optional[User]:
pass
@abstractmethod
def get_all(self) -> List[User]:
pass
@abstractmethod
def save(self, user: User) -> User:
pass
@abstractmethod
def delete(self, user_id: int) -> None:
pass
class SQLAlchemyUserRepository(UserRepository):
def __init__(self, session):
self.session = session
def get_by_id(self, user_id: int) -> Optional[User]:
return self.session.query(User).get(user_id)
def get_all(self) -> List[User]:
return self.session.query(User).all()
def save(self, user: User) -> User:
self.session.add(user)
self.session.commit()
return user
def delete(self, user_id: int) -> None:
user = self.get_by_id(user_id)
if user:
self.session.delete(user)
self.session.commit()
3.2 Unit of Work模式
class UnitOfWork:
def __init__(self):
self.session = Session()
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
if exc_type is None:
self.commit()
else:
self.rollback()
self.session.close()
def commit(self):
self.session.commit()
def rollback(self):
self.session.rollback()
def get_repository(self, repo_type):
if repo_type == UserRepository:
return SQLAlchemyUserRepository(self.session)
# 其他repository...
四、查询优化
4.1 懒加载vs急加载
# 懒加载(默认)
users = session.query(User).all()
for user in users:
print(user.orders) # 每次访问都会触发查询
# 急加载
from sqlalchemy.orm import joinedload
users = session.query(User).options(joinedload(User.orders)).all()
for user in users:
print(user.orders) # 不会触发额外查询
4.2 批量操作
# 批量插入
users = [
User(username='user1', email='user1@example.com'),
User(username='user2', email='user2@example.com'),
]
session.add_all(users)
session.commit()
# 批量更新
session.query(User).filter(User.id.in_([1, 2, 3])).update({
User.status: 'active'
})
session.commit()
4.3 原生SQL
# 执行原生SQL
result = session.execute(
'SELECT COUNT(*) FROM users WHERE status = :status',
{'status': 'active'}
)
count = result.scalar()
# 使用text对象
from sqlalchemy import text
stmt = text('SELECT * FROM users WHERE id = :id')
result = session.execute(stmt, {'id': 1})
五、事务管理
5.1 声明式事务
from sqlalchemy import text
with session.begin_nested():
try:
# 执行操作
session.execute(text('UPDATE accounts SET balance = balance - 100 WHERE id = 1'))
session.execute(text('UPDATE accounts SET balance = balance + 100 WHERE id = 2'))
except Exception as e:
# 自动回滚
session.rollback()
raise
5.2 分布式事务
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
# 多个数据库
engine1 = create_engine('postgresql://user:pass@db1/db')
engine2 = create_engine('postgresql://user:pass@db2/db')
session1 = sessionmaker(bind=engine1)()
session2 = sessionmaker(bind=engine2)()
try:
# 在两个数据库上执行操作
session1.execute(text('INSERT INTO table1 VALUES (1)'))
session2.execute(text('INSERT INTO table2 VALUES (2)'))
# 提交两个事务
session1.commit()
session2.commit()
except:
session1.rollback()
session2.rollback()
raise
六、实战:数据层架构
6.1 项目结构
project/
├── src/
│ ├── db/
│ │ ├── __init__.py
│ │ ├── base.py
│ │ ├── session.py
│ │ └── repositories/
│ │ ├── user_repository.py
│ │ └── order_repository.py
│ ├── models/
│ │ ├── __init__.py
│ │ ├── user.py
│ │ └── order.py
│ └── services/
│ └── user_service.py
└── tests/
└── test_repositories.py
6.2 服务层
class UserService:
def __init__(self, repository: UserRepository):
self.repository = repository
def get_user(self, user_id: int) -> Optional[User]:
return self.repository.get_by_id(user_id)
def create_user(self, username: str, email: str) -> User:
user = User(username=username, email=email)
return self.repository.save(user)
def update_user(self, user_id: int, **kwargs) -> Optional[User]:
user = self.repository.get_by_id(user_id)
if user:
for key, value in kwargs.items():
setattr(user, key, value)
return self.repository.save(user)
return None
七、数据库迁移
7.1 使用Alembic
alembic init alembic
配置alembic.ini:
sqlalchemy.url = postgresql://user:pass@localhost/dbname
创建迁移:
alembic revision --autogenerate -m "create users table"
alembic upgrade head
八、最佳实践
8.1 连接池配置
from sqlalchemy import create_engine
engine = create_engine(
'postgresql://user:pass@localhost/db',
pool_size=20,
max_overflow=10,
pool_timeout=30,
pool_recycle=1800,
)
8.2 避免N+1查询
# 不好:N+1查询
users = session.query(User).all()
for user in users:
print(user.orders) # 额外N次查询
# 好:使用joinedload
users = session.query(User).options(joinedload(User.orders)).all()
for user in users:
print(user.orders) # 只有1次查询
8.3 数据验证
from pydantic import BaseModel, EmailStr, validator
class UserCreate(BaseModel):
username: str
email: EmailStr
@validator('username')
def username_must_not_be_empty(cls, v):
if not v.strip():
raise ValueError('Username cannot be empty')
return v
九、总结
数据库设计是后端开发的核心。通过使用ORM、Repository模式和合理的查询优化,我们可以构建高效、可维护的数据层架构。
关键要点:
- 使用ORM:SQLAlchemy提供强大的数据访问能力
- Repository模式:隔离数据访问逻辑
- 查询优化:使用joinedload避免N+1问题
- 事务管理:确保数据一致性
- 连接池:合理配置提升性能
从Python转向Rust后,我发现Rust的SQLx库提供了类型安全的数据库访问,编译时检查SQL语法,这是一个很大的优势。
延伸阅读
- SQLAlchemy官方文档
- Alembic迁移工具
- SQLx Rust库
- 《数据库系统概念》书籍
更多推荐


所有评论(0)