Base/Repository 包详解------小白也能看懂
📍 原文位置:
D:\AI0409\Day22\Repository-学习指南.md本文档的目标:让完全不懂数据库操作的小白也能理解这个包在做什么、怎么用、为什么这样设计。
前置知识:在看这个之前,你需要知道......
🗄️ 数据库是什么
数据库 = 专门存数据的仓库,就像一个超级强大的 Excel:
Excel 表格:
┌──────┬───────┬───────┐
│ ID │ 姓名 │ 年龄 │
├──────┼───────┼───────┤
│ 1 │ 张三 │ 25 │
│ 2 │ 李四 │ 30 │
│ 3 │ 王五 │ 28 │
└──────┴───────┴───────┘
数据库表(程序看到的):
同样的结构,但可以:
- 存储**百万、千万、甚至上亿条**数据
- 一秒钟查询**几千条**记录
- 支持**多人同时访问**
- **不会像 Excel 那样卡死**
📝 SQL 是什么
SQL = 和数据库对话的语言。
sql
-- 查所有用户
SELECT * FROM users;
-- 查年龄大于25的用户
SELECT * FROM users WHERE age > 25;
-- 插入新用户
INSERT INTO users (name, age) VALUES ('赵六', 22);
-- 更新用户年龄
UPDATE users SET age = 26 WHERE name = '张三';
-- 删除用户
DELETE FROM users WHERE name = '王五';
问题来了:每次都要写 SQL 很麻烦,而且容易写错!
🔧 Repository 包解决了什么问题
不用写 SQL,用 Python 代码就能操作数据库。
python
# ❌ 传统方式:手动写 SQL
cursor.execute("SELECT * FROM users WHERE id = 1")
user = cursor.fetchone()
# ✅ Repository 方式:像操作 Python 对象一样操作数据库
user = User.get_by_id(1) # 一行搞定!
第1步:理解分层架构------这是理解一切的钥匙
🏠 生活类比:餐厅吃饭
你(顾客)
│
│ "我要一份宫保鸡丁"
▼
服务员(接单员)
│
│ "好的,记下了"
│
▼
厨房(厨师)
│
│ 实际炒菜
▼
菜品端上桌
对应到数据库操作:
┌─────────────────────────────────────┐
│ 模型层 (Model Layer) │ ← 你写代码直接打交道的
│ User.save() User.get_by_id(1) │ 就像"顾客点菜"
└─────────────┬───────────────────────┘
│
│ "帮我执行这个操作"
▼
┌─────────────────────────────────────┐
│ 连接层 (Connection Layer) │ ← 帮你传话的"服务员"
│ 管理连接池、执行SQL、事务管理 │ 你不直接碰它
└─────────────┬───────────────────────┘
│
│ "我要连数据库"
▼
┌─────────────────────────────────────┐
│ 实现层 (Implementation) │ ← 实际干活的"厨房"
│ MySQLConnection / PostgreSQL... │ 不同数据库有不同的"厨师"
└─────────────────────────────────────┘
为什么要分层?
| 不分层 | 分层 |
|---|---|
| 所有代码写一起,改一处全乱 | 每层只管自己的事 ✅ |
| 换数据库要改所有代码 | 换数据库只改实现层 ✅ |
| 出错了不知道哪儿出问题 | 分层调试,快速定位 ✅ |
第2步:从连接数据库开始------基础操作
2.1 三种数据库,三种连接方式
┌────────────────────────────────────────────────────────────┐
│ 关系型数据库 │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ MySQL │ │ PostgreSQL │ │ SQLite │ │
│ │ 企业首选 │ │ 复杂查询强 │ │ 小项目测试 │ │
│ │ 生产环境 │ │ JSON支持好 │ │ 无需安装 │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ ↓ ↓ ↓ │
│ 端口3306 端口5432 文件或内存 │
│ 需要安装 需要安装 无需安装 │
└────────────────────────────────────────────────────────────┘
2.2 MySQL 连接详解
python
from Base.Repository.connections.mysqlConnection import MySQLConnection
mysql_db = MySQLConnection(
host="localhost", # 数据库服务器的地址
# localhost = 本机
# 192.168.1.100 = 远程服务器
user="root", # 用户名
password="your_password", # 密码
database="my_app", # 数据库名
port=3306, # 端口号(MySQL默认3306)
charset="utf8mb4", # 字符编码(支持中文)
# 🔑 连接池参数(重点!)
mincached=2, # 池子里最少保持2个空闲连接
maxcached=10, # 池子里最多保持10个空闲连接
maxconnections=20, # 总共最多创建20个连接
blocking=False, # 连接池满了直接报错,不等待
)
2.3 什么是连接池------核心概念
连接池 = 数据库连接的"停车场"。
没有连接池时:
程序要查数据库:
Step 1: 建立连接(3秒) ← 慢!
Step 2: 发送 SQL 查询(0.1秒)
Step 3: 断开连接(1秒) ← 浪费时间!
总耗时:4.1秒
如果查100次:4.1秒 × 100 = 410秒 = 6.8分钟!💥
有连接池时:
程序启动时:
建好 2 个连接,放在"停车场"(池子)里待命
程序要查数据库:
Step 1: 从停车场拿一个连接(0.01秒)← 快!
Step 2: 发送 SQL 查询(0.1秒)
Step 3: 用完还回停车场(0.01秒) ← 不用断开!
总耗时:0.12秒
如果查100次:0.12秒 × 100 = 12秒!✅
类比:
| 场景 | 没有连接池 | 有连接池 |
|---|---|---|
| 打电话 | 每次都要拨号、等接通 | 专线直连,拿起来就说 |
| 银行 | 每次去都要排队取号 | VIP专属窗口,随到随办 |
| 停车 | 每次都要找车位、停好 | 有专属车位,来了就停 |
连接池参数详解:
python
mincached=2 # 最少保留 2 个空闲连接
# 像银行"至少开2个窗口"
maxcached=10 # 最多保留 10 个空闲连接
# 像银行"最多开10个窗口"
maxconnections=20 # 总共最多 20 个连接(含正在用的+空闲的)
# 像银行"整个大厅最多容纳20人"
blocking=False # False = 窗口满了直接拒绝
# True = 窗口满了排队等
2.4 PostgreSQL 和 SQLite 的区别
python
# PostgreSQL(比 MySQL 更强大,适合复杂查询)
from Base.Repository.connections.postgresConnection import PostgreSQLConnection
pg_db = PostgreSQLConnection(
host="localhost",
user="postgres",
password="your_password",
database="my_app",
port=5432, # PostgreSQL 默认端口
)
# SQLite(最简单,无需安装,适合测试)
from Base.Repository.connections.sqliteConnection import SQLiteConnection
# 方式1:存文件(持久保存)
file_db = SQLiteConnection(database="my_app.db")
# 方式2:内存数据库(程序结束就没了,适合测试)
mem_db = SQLiteConnection(database=":memory:")
三种数据库对比:
| 数据库 | 适用场景 | 安装难度 | 性能 | 功能 |
|---|---|---|---|---|
| MySQL | 企业生产环境 | 中等 | 高 | 全面 |
| PostgreSQL | 复杂查询、JSON数据 | 中等 | 高 | 最强 |
| SQLite | 测试、小项目、手机App | 无需安装 | 中 | 简单 |
第3步:用 BaseDBModel 操作数据库------最常用部分
3.1 BaseDBModel 是什么
BaseDBModel = 数据库表的"Python 替身"。
数据库里的 users 表:
┌────┬──────┬───────┬──────┐
│ id │ name │ email │ age │
├────┼──────┼───────┼──────┤
│ 1 │ 张三 │ zs@.. │ 25 │
│ 2 │ 李四 │ ls@.. │ 30 │
└────┴──────┴───────┴──────┘
Python 里的 User 类:
class User(BaseDBModel):
id: int
name: str
email: str
age: int
一个 User 对象 = 表里的一行数据 ✅
3.2 定义一个模型(定义表结构)
python
from Base.Repository.base.baseDBModel import BaseDBModel
from typing import Optional, ClassVar
class User(BaseDBModel):
"""用户表模型"""
# ━━━━ 第1部分:表名和建表SQL(可选)━━━━
table_alias: ClassVar[str] = "users" # 指定表名
create_table_sql: ClassVar[str] = """ # 建表SQL
CREATE TABLE `users` (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(255) NOT NULL,
age INT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
"""
# ━━━━ 第2部分:字段定义(必填)━━━━
id: Optional[int] = None # 主键,None表示"新记录,还没存入数据库"
name: str # 必填字段(不能为空)
email: str # 必填字段
age: Optional[int] = None # 可选字段(可以为空)
# ━━━━ 第3部分:自定义方法(按需添加)━━━━
@classmethod
def get_by_email(cls, email: str):
"""按邮箱查找用户"""
results = cls.find_by(email=email, limit=1)
return results[0] if results else None
字段类型说明:
python
# 不同的 Python 类型对应不同的数据库类型
id: int → INT(整数)
name: str → VARCHAR(字符串)
age: Optional[int] → INT(可为空)
price: float → DECIMAL/DOUBLE(小数)
is_active: bool → TINYINT(1)(布尔值)
created_at: datetime → TIMESTAMP(时间戳)
description: Optional[str] → TEXT(长文本,可为空)
3.3 CRUD 操作详解------增删改查
📌 创建(Create)------ 插入新数据
python
# 方式1:创建对象后 save()
user = User(name="张三", email="zs@example.com", age=25)
new_id = user.save() # 返回新插入的 ID,比如 new_id = 5
# 方式2:批量插入(比循环 save() 快10倍以上!)
users = [
User(name="张三", email="zs@example.com"),
User(name="李四", email="ls@example.com"),
User(name="王五", email="ww@example.com"),
]
ids = User.bulk_insert(users, batch_size=500)
# 返回 [5, 6, 7] 三个新ID
# batch_size=500 表示每500条一批(避免SQL太长)
save() 的智能判断:
python
# 情况1:id 是 None(新记录)→ 执行 INSERT
user = User(name="新用户") # id 自动为 None
user.save() # → INSERT INTO users (name) VALUES ('新用户')
# 情况2:id 有值(已有记录)→ 执行 UPDATE
user = User(id=5, name="改过的用户")
user.save() # → UPDATE users SET name='改过的用户' WHERE id=5
📌 读取(Read)------ 查询数据
python
# ━━━━ 按 ID 查一条 ━━━━
user = User.get_by_id(1) # 返回 User 对象,或 None
print(user.name) # "张三"
# ━━━━ 查所有 ━━━━
users = User.get_all() # 返回 [User, User, User, ...]
for user in users:
print(user.name)
# ━━━━ 分页查询 ━━━━
users = User.get_all(limit=10, offset=0) # 第1页,每页10条
users = User.get_all(limit=10, offset=10) # 第2页(跳过前10条)
users = User.get_all(limit=10, offset=20) # 第3页(跳过前20条)
# ━━━━ 按条件查询 ━━━━
users = User.find_by(age=25) # 查年龄=25的所有用户
users = User.find_by(age=25, name="张三") # 多条件(AND逻辑)
# WHERE age=25 AND name='张三'
# ━━━━ 只取第一条 ━━━━
user = User.find_one_by(email="zs@example.com")
# ━━━━ 统计数量 ━━━━
total = User.count() # 总记录数
count = User.count(age=25) # 年龄=25的有多少条
📌 更新(Update)------ 修改数据
python
# 方式1:查出来 → 改属性 → save()
user = User.get_by_id(1)
user.age = 26 # 改年龄
user.email = "new@example.com" # 改邮箱
user.save() # 保存修改
# 方式2:直接 update()
user = User.get_by_id(1)
user.update(age=27) # 直接传参更新
user.update(age=28, email="another@example.com") # 同时更新多个字段
📌 删除(Delete)------ 删除数据
python
# 方式1:查出来后删除
user = User.get_by_id(1)
user.delete() # 删除这条记录
# 方式2:按ID直接删除
User.delete_by_id(1) # 不用先查询
3.4 CRUD 操作速查表
python
# ===== 创建 =====
user = User(name="张三")
user.save() # 单条插入
User.bulk_insert([user1, user2]) # 批量插入
# ===== 查询 =====
User.get_by_id(1) # 按ID查一条
User.get_all() # 查所有
User.get_all(limit=10, offset=0) # 分页
User.find_by(age=25) # 按条件查
User.find_one_by(email="x@x.com") # 只取第一条
User.count() # 统计总数
# ===== 更新 =====
user.age = 26; user.save() # 方式1
user.update(age=26) # 方式2
# ===== 删除 =====
user.delete() # 删除实例
User.delete_by_id(1) # 按ID删除
3.5 建表操作
python
# 检查表是否存在
if not User.table_exists():
# 用 create_table_sql 中定义的SQL建表
User.create_table()
print("表创建成功!")
else:
print("表已存在,跳过创建")
第4步:连接管理------多数据库场景
4.1 什么时候需要多数据库
| 场景 | 说明 |
|---|---|
| 读写分离 | 写操作走主库,读操作走从库 |
| 分库分表 | 订单库、用户库分开存 |
| 测试环境 | 测试库和生产库分开 |
4.2 连接优先级------重要概念
一个模型到底用哪个数据库连接?优先级如下:
优先级最高:实例级连接
│ user.set_connection(write_db) ← 这个实例专用
↓ 没找到?
优先级中等:类级连接
│ User.set_db_connection(user_db) ← 这个类专用
↓ 没找到?
优先级最低:全局默认连接
│ BaseDBModel.set_default_db_connection(mysql_db) ← 全局默认
图解:
┌─────────────────────────────────────────────┐
│ 全局默认连接 │
│ BaseDBModel.set_default_db_connection(db) │
│ ↓ 所有模型都默认用这个 │
└─────────────────────────────────────────────┘
▲
│ 覆盖
┌─────────────────────────────────────────────┐
│ 类级连接 │
│ User.set_db_connection(user_db) │
│ ↓ User 类用这个,其他类还是用全局默认 │
└─────────────────────────────────────────────┘
▲
│ 覆盖
┌─────────────────────────────────────────────┐
│ 实例级连接 │
│ user.set_connection(write_db) │
│ ↓ 这个 user 实例用这个 │
└─────────────────────────────────────────────┘
4.3 读写分离实战
python
# Step 1:创建两个连接
read_db = MySQLConnection(host="192.168.1.100", ...) # 读库(从库)
write_db = MySQLConnection(host="192.168.1.101", ...) # 写库(主库)
# Step 2:设置全局默认为读库(安全,大部分操作都是读)
BaseDBModel.set_default_db_connection(read_db)
# Step 3:查询自动用读库
users = User.get_all() # 走读库 ✅
user = User.get_by_id(1) # 走读库 ✅
# Step 4:写入时临时切换到写库
new_user = User(name="新用户")
new_user.set_connection(write_db) # 这条走写库 ✅
new_user.save() # INSERT → 主库
# 或者改完后切回来
new_user.set_connection(read_db) # 后续查询又走读库
4.4 ConnectionManager------统一管理多个连接
python
from Base.Repository.base.connectionManager import ConnectionManager
# 注册连接(给每个连接起个名字)
ConnectionManager.register("read", read_db, is_default=True) # 设为默认
ConnectionManager.register("write", write_db)
ConnectionManager.register("order", order_db) # 订单库
ConnectionManager.register("user", user_db) # 用户库
# 获取连接
default_db = ConnectionManager.get_default() # 获取默认连接(read)
write_db = ConnectionManager.get("write") # 按名字获取
all_names = ConnectionManager.list_keys() # ['read', 'write', 'order', 'user']
# 程序退出时清理
ConnectionManager.close_all()
4.5 项目预设的模型基类
项目已经帮你创建了两个带连接配置的基类:
python
# ━━━━ 使用默认数据库连接 ━━━━
from Base.Repository.models.defaultDbModel import DefaultDbModel
class MyModel(DefaultDbModel):
id: Optional[int] = None
name: str
# 继承后自动绑定默认数据库,不用再设置连接
# ━━━━ 使用 base_module 数据库连接 ━━━━
from Base.Repository.models.moduleDbModel import BaseModuleDBModel
class ConfigModel(BaseModuleDBModel):
id: Optional[int] = None
key: str
value: str
# 继承后自动绑定 base_module 数据库
区别:连接的目标数据库不同,其他完全一样。
第5步:向量数据库(Milvus)------AI 时代的新物种
5.1 什么是向量数据库
向量数据库 = 专门存"向量"的数据库。
传统数据库 vs 向量数据库
| 传统数据库 | 向量数据库 | |
|---|---|---|
| 存什么 | 文本、数字、日期 | 向量(一串数字) |
| 查什么 | "年龄=25" | "和这段话最相似" |
| 怎么查 | 精确匹配 | 计算向量距离 |
| 例子 | 查"张三的订单" | 查"和'人工智能入门'最像的文章" |
5.2 向量是什么------核心概念
向量 = 把文字/图片变成一串数字。
文字:"特斯拉 Model Y 续航"
↓ AI 模型处理
向量:[0.72, 0.15, 0.88, 0.34, 0.56, ...] ← 768个数字
文字:"Model Y 能跑多远"
↓ 同一个 AI 模型处理
向量:[0.70, 0.18, 0.85, 0.30, 0.58, ...] ← 768个数字
对比两串数字:
0.72 vs 0.70 ← 接近
0.15 vs 0.18 ← 接近
0.88 vs 0.85 ← 接近
...
结论:这两句话意思相近 ✅
5.3 向量搜索的过程
用户提问:"特斯拉电池能用多久?"
│
▼
Step 1: 把问题转成向量
│ [0.65, 0.22, 0.71, ...]
▼
Step 2: 在向量数据库里找"距离最近"的向量
│
│ ┌────────────────────────────────┐
│ │ Milvus 向量数据库 │
│ │ │
│ │ [0.72, 0.15, ...] → "特斯拉续航550km" ← 距离近 ✅
│ │ [0.68, 0.20, ...] → "Model Y续航强" ← 距离近 ✅
│ │ [0.30, 0.85, ...] → "今天天气真好" ← 距离远 ❌
│ │ │
│ └────────────────────────────────┘
▼
Step 3: 返回最相似的几条记录
│
▼
["特斯拉续航550km", "Model Y续航强", ...]
5.4 两种向量:密集向量 vs 稀疏向量
┌─────────────────────────────────────────────────────┐
│ 密集向量 │
│ │
│ 每个"维度"都有值: │
│ [0.72, 0.15, 0.88, 0.34, 0.56, 0.12, ...] │
│ │
│ 用途:语义相似度("意思相近") │
│ 例子:"续航" ≈ "能跑多远" ≈ "电池寿命" │
│ │
│ 生成方式:AI 模型(BERT、GPT Embedding 等) │
└─────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────┐
│ 稀疏向量 │
│ │
│ 大部分维度是 0,只有少数位置有值: │
│ [0, 0, 0.85, 0, 0, 0.72, 0, 0, 0, 0.45, 0, ...] │
│ ↑ ↑ ↑ │
│ 关键词1 关键词2 关键词3 │
│ │
│ 用途:关键词匹配("包含这个词") │
│ 例子:"续航" → 只匹配包含"续航"的文档 │
│ │
│ 生成方式:BM25 算法(类似搜索引擎的倒排索引) │
└─────────────────────────────────────────────────────┘
为什么要两种向量?
场景:用户问"特斯拉的续航如何?"
纯密集向量搜索:
→ 可能匹配到"Model Y 能跑多远" ✅(语义对)
→ 但也可能匹配到"电动车电池技术发展" ❌(有关联但不准确)
纯稀疏向量搜索:
→ 只匹配包含"特斯拉"和"续航"的文档
→ 如果用户说"Model Y 电池能用多久" → 匹配不到 ❌(词不一样)
混合搜索(两种向量结合):
→ 密集向量找到语义相近的
→ 稀疏向量找到关键词匹配的
→ 综合排序 → 最准确 ✅
5.5 定义向量模型
python
from Base.Repository.base.baseVDB import BaseVDBModel
from typing import Optional
from pydantic import Field
class Document(BaseVDBModel):
"""文档向量模型"""
# ━━━━ 主键字段 ━━━━
id: Optional[int] = Field(
default=0,
json_schema_extra={
'is_primary': True, # 这是主键
'auto_id': True # 自动生成ID
}
)
# ━━━━ 普通文本字段 ━━━━
title: str = Field(
default="",
json_schema_extra={'max_length': 256} # 最大长度256
)
# ━━━━ BM25 文本字段(会被分词,用于关键词搜索)━━━━
content: str = Field(
default="",
json_schema_extra={
'enable_match': True, # 启用匹配
'enable_analyzer': True, # 启用分词
'max_length': 65535 # 最大长度
}
)
# ━━━━ 密集向量字段 ━━━━
embedding: list[float] = Field(
default=[],
json_schema_extra={'dim': 768} # 768维(必须和你的embedding模型一致)
)
# ━━━━ 稀疏向量字段(自动从 content 生成)━━━━
content_sparse: list[float] = Field(
default=[],
json_schema_extra={
'is_sparse_vector': True, # 这是稀疏向量
'bm25_source_field': 'content' # 从 content 字段生成
}
)
# ━━━━ 集合配置 ━━━━
collection_alias = "my_documents" # Milvus 集合名
description = "文档向量集合"
5.6 向量数据库操作详解
📌 插入数据
python
# 方式1:单条插入
doc = Document(
title="AI入门教程",
content="人工智能是研究如何使计算机模拟人类智能的学科...",
embedding=[0.1, 0.2, 0.3, ...] # 768维向量
)
doc.save() # 自动生成 ID
# 方式2:批量插入
docs = [
Document(title="文档1", content="...", embedding=[...]),
Document(title="文档2", content="...", embedding=[...]),
]
Document.batch_insert(docs)
📌 纯向量搜索
python
# 找和某个向量最相似的 10 条记录
results = Document.search(
data=[0.1, 0.2, 0.3, ...], # 查询向量(768维)
limit=10 # 返回10条
)
for r in results:
print(f"标题:{r.title}")
print(f"内容:{r.content}")
print(f"相似度:{r.distance}") # 距离越小越相似
print("---")
📌 混合搜索(推荐)------语义 + 关键词
python
results = Document.hybrid_search(
queries=[
{
'data': [0.1, 0.2, ...], # 密集向量
'field': 'embedding', # 搜索这个字段
'type': 'dense', # 类型:密集向量
},
{
'data': "人工智能", # 关键词文本
'field': 'content_sparse', # 搜索这个字段
'type': 'sparse', # 类型:稀疏向量
}
],
limit=10, # 返回10条
weights=[0.7, 0.3] # 密集向量权重0.7,稀疏向量权重0.3
)
# 权重解释:
# weights=[0.7, 0.3] → 密集向量更重要,侧重"语义相似"
# weights=[0.3, 0.7] → 稀疏向量更重要,侧重"关键词匹配"
# weights=[0.5, 0.5] → 两者均衡
📌 标量查询(按条件过滤)
python
# 类似 SQL 的 WHERE 条件
results = Document.query(
filter='title like "AI%"', # 标题以"AI"开头
limit=10
)
results = Document.find_by(filter='title like "AI%"')
count = Document.count(filter='title like "AI%"')
📌 删除和更新
python
# 删除
Document.delete(filter='title == "过期文档"')
# 更新(存在则更新,不存在则插入)
doc = Document(id=1, title="新标题", ...)
Document.upsert([doc])
5.7 BaseVDBModel 的自动化能力
python
# 你不需要手动创建集合,第一次使用时自动创建
# 你不需要手动定义 Schema,框架根据 Field 自动推断
# 你不需要手动建索引,默认自动创建:
# - 密集向量:HNSW 索引(COSINE 距离)
# - 稀疏向量:BM25 索引
# 你只需要定义好模型,然后直接用!
第6步:完整数据流示例
6.1 关系型数据库完整流程
python
# Step 1:创建连接
from Base.Repository.connections.mysqlConnection import MySQLConnection
db = MySQLConnection(
host="localhost",
user="root",
password="password",
database="my_app"
)
# Step 2:定义模型
from Base.Repository.base.baseDBModel import BaseDBModel
class User(BaseDBModel):
table_alias = "users"
create_table_sql = """
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100),
email VARCHAR(255),
age INT
)
"""
id: Optional[int] = None
name: str
email: str
age: Optional[int] = None
# Step 3:设置连接
User.set_db_connection(db)
# Step 4:建表(如果不存在)
if not User.table_exists():
User.create_table()
# Step 5:CRUD 操作
# 创建
user = User(name="张三", email="zs@example.com", age=25)
user.save()
print(f"新用户ID:{user.id}")
# 查询
found = User.get_by_id(user.id)
print(f"查到用户:{found.name}")
# 更新
found.age = 26
found.save()
# 删除
found.delete()
6.2 向量数据库完整流程
python
# Step 1:创建连接
from Base.Repository.connections.milvusConnection import MilvusVDBConnection
vdb = MilvusVDBConnection(
host="localhost",
port="19530"
)
# Step 2:定义向量模型
from Base.Repository.base.baseVDB import BaseVDBModel
class Article(BaseVDBModel):
collection_alias = "articles"
id: Optional[int] = Field(0, json_schema_extra={'is_primary': True, 'auto_id': True})
title: str = Field("", json_schema_extra={'max_length': 256})
content: str = Field("", json_schema_extra={'enable_match': True, 'enable_analyzer': True})
embedding: list[float] = Field([], json_schema_extra={'dim': 768})
content_sparse: list[float] = Field([], json_schema_extra={'is_sparse_vector': True, 'bm25_source_field': 'content'})
# Step 3:设置连接
Article.set_vdb_connection(vdb)
# Step 4:插入数据(假设已有 embedding 函数)
def get_embedding(text):
# 调用 AI 模型生成向量
return [0.1, 0.2, ...] # 768维
article = Article(
title="AI入门",
content="人工智能是研究如何使计算机模拟人类智能...",
embedding=get_embedding("AI入门 人工智能是研究如何使计算机模拟人类智能...")
)
article.save()
# Step 5:混合搜索
query_text = "什么是AI?"
query_vector = get_embedding(query_text)
results = Article.hybrid_search(
queries=[
{'data': query_vector, 'field': 'embedding', 'type': 'dense'},
{'data': query_text, 'field': 'content_sparse', 'type': 'sparse'}
],
limit=5,
weights=[0.7, 0.3]
)
for r in results:
print(f"标题:{r.title}")
print(f"相似度:{r.distance}")
第7步:FAQ 深度解答
Q1:连接失败会怎样?程序会崩溃吗?
答:不会崩溃,优雅降级。
python
# 连接失败时,内部 _is_available = False
db = MySQLConnection(host="不存在的地址", ...)
# 后续所有操作静默跳过,返回安全的默认值
User.get_all() # 返回 []
User.save() # 返回 -1
User.count() # 返回 0
# 程序继续运行,只是数据库功能暂时不可用
类比:就像银行系统------某个窗口关闭了,其他窗口还能办业务,只是这一个功能暂时不可用。
Q2:我该继承 DefaultDbModel 还是 BaseDBModel?
┌─────────────────────────────────────────┐
│ DefaultDbModel │
│ 已绑定默认数据库 │
│ 适合:大多数场景 │
│ 用法:直接继承,不用设置连接 │
└─────────────────────────────────────────┘
┌─────────────────────────────────────────┐
│ BaseDBModel │
│ 需要手动设置连接 │
│ 适合:多数据库、读写分离 │
│ 用法:继承后调用 set_db_connection() │
└─────────────────────────────────────────┘
建议:优先用 DefaultDbModel,简单省事 ✅
Q3:SQLite 和 MySQL 使用上有什么区别?
答:对模型层来说,几乎没区别。
python
# MySQL
mysql_db = MySQLConnection(host="localhost", ...)
User.set_db_connection(mysql_db)
user = User.get_by_id(1) # 正常工作
# SQLite
sqlite_db = SQLiteConnection(database="app.db")
User.set_db_connection(sqlite_db)
user = User.get_by_id(1) # 同样正常工作!
# 底层差异(占位符)已被框架处理:
# MySQL: SELECT * FROM users WHERE id = %s
# SQLite: SELECT * FROM users WHERE id = ?
# 你不需要关心!
Q4:批量插入 bulk_insert 为什么快?
python
# ❌ 循环 save():每条一个 SQL
for user in users:
user.save()
# 执行 100 次 SQL:
# INSERT INTO users (name) VALUES ('张三')
# INSERT INTO users (name) VALUES ('李四')
# ...(100次)
# ✅ bulk_insert():一条 SQL 插多行
User.bulk_insert(users, batch_size=100)
# 执行 1 次 SQL:
# INSERT INTO users (name) VALUES ('张三'),('李四'),(...),...(100条)
# 性能对比:
# 循环 save(): 100条 × 10ms = 1000ms = 1秒
# bulk_insert(): 1条 × 50ms = 50ms
# 快 20 倍!
Q5:什么时候需要向量数据库?
┌─────────────────────────────────────────┐
│ ✅ 适合向量数据库的场景 │
├─────────────────────────────────────────┤
│ 语义搜索:"找和这段话意思相近的文章" │
│ 图片搜索:"找和这张图最像的图" │
│ 推荐系统:"找和这个用户兴趣相似的其他用户" │
│ 问答系统:"找和历史问题相似的问题" │
└─────────────────────────────────────────┘
┌─────────────────────────────────────────┐
│ ❌ 不需要向量数据库的场景 │
├─────────────────────────────────────────┤
│ 精确查询:"查ID=1001的订单" │
│ 范围查询:"查2026年7月的所有订单" │
│ 统计聚合:"统计每个用户的订单数量" │
│ 事务操作:"转账、退款" │
└─────────────────────────────────────────┘
结论:
精确/范围/统计 → MySQL ✅
语义相似搜索 → Milvus ✅
两者结合 → 最强 ✅
Q6:向量维度(dim=768)怎么确定?
答:由你用的 Embedding 模型决定。
不同的 AI 模型输出不同维度:
OpenAI text-embedding-3-small: 1536 维
OpenAI text-embedding-3-large: 3072 维
阿里云 text-embedding-v3: 1024 维
BERT-base: 768 维
MiniLM: 384 维
你必须保持一致:
模型输出 768 维 → dim=768 ✅
模型输出 1536 维 → dim=1536 ✅
模型输出 768 维 → dim=1024 ❌ 报错!
一句话总结
┌─────────────────────────────────────────────────────┐
│ │
│ Repository 包 = 数据库操作的"翻译官" │
│ │
│ 你用 Python 对象: │
│ user.save() │
│ User.get_by_id(1) │
│ doc.search(vector) │
│ │
│ 它帮你翻译成: │
│ INSERT INTO users ... │
│ SELECT * FROM users WHERE id=1 │
│ 向量相似度搜索 │
│ │
│ 你不用写 SQL,不用关心底层细节 │
│ │
│ 三层架构: │
│ 模型层(你用的) │
│ → 连接层(帮你传话的) │
│ → 实现层(干活的) │
│ │
└─────────────────────────────────────────────────────┘