C++ ORM与数据库访问层设计:Repository模式实战
创建日期 : 2026-03-25
更新日期 : 2026-03-25
作者 : zry
标签: C++, ORM, Repository模式, 数据库, 数据访问层, MySQL
📋 目录
引言
在现代C++应用程序开发中,数据库访问层的设计直接影响系统的可维护性和可扩展性。Repository模式通过将数据访问逻辑与业务逻辑分离,提供了一种清晰、可测试的数据访问方案。
本文基于AIDC自动气象站数据收集系统的实践,深入讲解如何在C++中实现一个类型安全、高效的ORM风格的数据库访问层。
为什么需要Repository模式
传统数据访问的问题
传统方式:混乱的数据访问
直接SQL
直接SQL
直接SQL
业务逻辑
数据库
数据库
数据库
传统方式的痛点:
- SQL语句散落在业务代码中,难以维护
- 数据模型变更需要修改多处代码
- 数据库切换成本高
- 单元测试困难,难以Mock
- 重复代码多,DRY原则被破坏
Repository模式的优势
Repository模式:清晰的分层
使用Repository
统一接口
ORM
业务逻辑层
Repository层
数据访问层
数据库
Repository模式的核心价值:
| 优势 | 说明 |
|---|---|
| 关注点分离 | 业务逻辑与数据访问解耦 |
| 可测试性 | 易于Mock,支持单元测试 |
| 可维护性 | 数据访问逻辑集中管理 |
| 类型安全 | 编译期检查,减少运行时错误 |
| 代码复用 | 通用CRUD操作抽象复用 |
Repository模式架构设计
整体架构
数据访问层架构
继承/使用
连接池
实现
依赖接口
Repository
DbManager
MySQL连接
具体仓储
StationRepository
DeviceRepository
DataRepository
业务服务
类层次结构
Repository<T>
+Insert(args...) : Result<int>
+QueryAll() : Result<vector<T>>
+QueryWhere(args...) : Result<vector<T>>
+Update(args...) : Result<int>
+Delete(args...) : Result<int>
StationRepository
+FindByStationNum(num) : Station
+FindActiveStations() : vector<Station>
DeviceRepository
+FindByType(type) : vector<Device>
+UpdateStatus(id, status) : bool
核心代码实现
1. 基础Repository模板类
cpp
/**
* @file db_repository.hpp
* @brief 数据访问基类模板
* @date 2026-03-25
*/
#ifndef ZRY_DB_REPOSITORY_HPP
#define ZRY_DB_REPOSITORY_HPP
#include "db_manager.hpp"
#include "db_all.hpp"
#include "../base/error.hpp"
#include <vector>
#include <optional>
namespace zry::db {
/**
* @brief 通用Repository模板类
*
* 提供类型安全的CRUD操作,所有具体仓储类都继承此类
*
* @tparam T 实体类型,需要满足:
* - 有默认构造函数
* - 支持反射(YLT_REFL宏标记字段)
*/
template<typename T>
class Repository {
public:
using Entity = T;
/**
* @brief 插入记录
* @tparam Args 可变参数类型
* @param args 插入参数
* @return Result<int> 插入行数或错误
*
* @code
* auto result = repo.Insert(station);
* if (result) {
* std::cout << "插入 " << result.Value() << " 行\n";
* }
* @endcode
*/
template<typename... Args>
Result<int> Insert(Args&&... args) {
auto& db = DbManager::Instance().GetDb();
auto result = db.insert(std::forward<Args>(args)...);
if (result < 0) {
return ErrorCode::ERROR_DB_INSERT;
}
return result;
}
/**
* @brief 查询所有记录
* @return Result<std::vector<T>> 记录列表或错误
*/
Result<std::vector<T>> QueryAll() {
auto& db = DbManager::Instance().GetDb();
auto result = db.query<T>();
return result;
}
/**
* @brief 条件查询
* @tparam Args 查询条件类型
* @param args 查询条件(支持字符串条件或lambda谓词)
* @return Result<std::vector<T>> 符合条件的记录
*
* @code
* // 方式1:字符串条件
* auto result = repo.QueryWhere("status = 1");
*
* // 方式2:lambda谓词
* auto result = repo.QueryWhere([](const Station& s) {
* return s.status == 1;
* });
* @endcode
*/
template<typename... Args>
Result<std::vector<T>> QueryWhere(Args&&... args) {
auto& db = DbManager::Instance().GetDb();
auto result = db.query<T>(std::forward<Args>(args)...);
return result;
}
/**
* @brief 更新记录
* @tparam Args 更新参数类型
* @param args 更新参数
* @return Result<int> 更新行数或错误
*/
template<typename... Args>
Result<int> Update(Args&&... args) {
auto& db = DbManager::Instance().GetDb();
auto result = db.update(std::forward<Args>(args)...);
if (result < 0) {
return ErrorCode::ERROR_DB_QUERY;
}
return result;
}
/**
* @brief 删除记录
* @tparam Args 删除条件类型
* @param args 删除条件
* @return Result<int> 删除行数或错误
*/
template<typename... Args>
Result<int> Delete(Args&&... args) {
auto& db = DbManager::Instance().GetDb();
auto result = db.delete_records<T>(std::forward<Args>(args)...);
if (result < 0) {
return ErrorCode::ERROR_DB_QUERY;
}
return result;
}
/**
* @brief 根据ID查询单条记录
* @tparam IdType ID类型
* @param id 记录ID
* @return std::optional<T> 记录或空
*/
template<typename IdType>
std::optional<T> FindById(IdType id) {
auto result = QueryWhere([&id](const T& entity) {
return entity.id == id;
});
if (result && !result.Value().empty()) {
return result.Value()[0];
}
return std::nullopt;
}
/**
* @brief 批量插入(事务保护)
* @tparam Iterator 迭代器类型
* @param begin 开始迭代器
* @param end 结束迭代器
* @return Result<int> 插入行数或错误
*/
template<typename Iterator>
Result<int> BatchInsert(Iterator begin, Iterator end) {
auto& db = DbManager::Instance().GetDb();
// 开启事务
db.begin_transaction();
int total = 0;
try {
for (auto it = begin; it != end; ++it) {
auto result = db.insert(*it);
if (result < 0) {
db.rollback();
return ErrorCode::ERROR_DB_INSERT;
}
total += result;
}
db.commit();
return total;
} catch (...) {
db.rollback();
return ErrorCode::ERROR_DB_INSERT;
}
}
};
} // namespace zry::db
#endif // ZRY_DB_REPOSITORY_HPP
2. 具体仓储类实现
cpp
/**
* @file station_repository.hpp
* @brief 站点数据仓储
* @date 2026-03-25
*/
#ifndef ZRY_STATION_REPOSITORY_HPP
#define ZRY_STATION_REPOSITORY_HPP
#include "db_repository.hpp"
#include "db_station.hpp"
namespace zry::db {
/**
* @brief 站点数据仓储
*
* 提供站点相关的数据访问方法
*/
class StationRepository : public Repository<StationInfo> {
public:
/**
* @brief 根据站点编号查询
* @param station_num 站点编号
* @return std::optional<StationInfo> 站点信息
*/
std::optional<StationInfo> FindByStationNum(const std::string& station_num) {
auto result = QueryWhere([&station_num](const StationInfo& s) {
return s.station_num == station_num;
});
if (result && !result.Value().empty()) {
return result.Value()[0];
}
return std::nullopt;
}
/**
* @brief 查询活跃站点
* @return std::vector<StationInfo> 活跃站点列表
*/
std::vector<StationInfo> FindActiveStations() {
auto result = QueryWhere([](const StationInfo& s) {
return s.status == 1;
});
if (result) {
return result.Value();
}
return {};
}
/**
* @brief 根据区域查询站点
* @param region 区域代码
* @return std::vector<StationInfo> 站点列表
*/
std::vector<StationInfo> FindByRegion(const std::string& region) {
auto result = QueryWhere([®ion](const StationInfo& s) {
return s.region_code == region;
});
if (result) {
return result.Value();
}
return {};
}
/**
* @brief 更新站点状态
* @param station_num 站点编号
* @param status 新状态
* @return bool 是否成功
*/
bool UpdateStatus(const std::string& station_num, int status) {
auto result = Update([&station_num, &status](StationInfo& s) {
if (s.station_num == station_num) {
s.status = status;
s.update_time = TimeTool::Now();
return true;
}
return false;
});
return result && result.Value() > 0;
}
};
/**
* @brief 设备数据仓储
*/
class DeviceRepository : public Repository<DeviceInfo> {
public:
/**
* @brief 根据设备类型查询
* @param device_type 设备类型
* @return std::vector<DeviceInfo> 设备列表
*/
std::vector<DeviceInfo> FindByType(const std::string& device_type) {
auto result = QueryWhere([&device_type](const DeviceInfo& d) {
return d.device_type == device_type;
});
if (result) {
return result.Value();
}
return {};
}
/**
* @brief 查询站点下的所有设备
* @param station_num 站点编号
* @return std::vector<DeviceInfo> 设备列表
*/
std::vector<DeviceInfo> FindByStation(const std::string& station_num) {
auto result = QueryWhere([&station_num](const DeviceInfo& d) {
return d.station_num == station_num;
});
if (result) {
return result.Value();
}
return {};
}
};
} // namespace zry::db
CRUD操作详解
创建(Create)
cpp
/**
* @brief 创建记录的最佳实践
*/
class CreateExamples {
public:
// 方式1:直接插入实体
void CreateStation() {
StationRepository repo;
StationInfo station;
station.station_num = "54511";
station.name = "北京站";
station.latitude = 39.9042;
station.longitude = 116.4074;
station.status = 1;
station.create_time = TimeTool::Now();
auto result = repo.Insert(station);
if (result) {
ZRY_LOG_INFO("创建站点成功,ID: {}", result.Value());
} else {
ZRY_LOG_ERROR("创建站点失败: {}", result.Error().ToString());
}
}
// 方式2:批量插入
void BatchCreateStations() {
StationRepository repo;
std::vector<StationInfo> stations = {
{"54511", "北京站", 39.9, 116.4},
{"54512", "天津站", 39.1, 117.2},
{"54513", "石家庄", 38.0, 114.5}
};
auto result = repo.BatchInsert(stations.begin(), stations.end());
if (result) {
ZRY_LOG_INFO("批量插入 {} 条记录", result.Value());
}
}
};
读取(Read)
cpp
/**
* @brief 查询操作的各种模式
*/
class ReadExamples {
public:
// 简单查询
void SimpleQuery() {
StationRepository repo;
// 查询所有
auto all_result = repo.QueryAll();
if (all_result) {
for (const auto& station : all_result.Value()) {
std::cout << station.name << "\n";
}
}
}
// 条件查询
void ConditionalQuery() {
StationRepository repo;
// 查询活跃站点
auto active = repo.FindActiveStations();
// 根据编号查询
auto station = repo.FindByStationNum("54511");
if (station) {
std::cout << "找到站点: " << station->name << "\n";
}
}
// 复杂条件查询
void ComplexQuery() {
DeviceRepository repo;
auto result = repo.QueryWhere([](const DeviceInfo& d) {
return d.device_type == "TEMP" &&
d.status == 1 &&
d.last_report > TimeTool::AddDays(TimeTool::Today(), -7);
});
if (result) {
ZRY_LOG_INFO("找到 {} 个活跃温度设备", result.Value().size());
}
}
};
更新(Update)
cpp
/**
* @brief 更新操作的各种模式
*/
class UpdateExamples {
public:
// 单条更新
void UpdateSingle() {
StationRepository repo;
auto result = repo.Update([](StationInfo& s) {
if (s.station_num == "54511") {
s.status = 0;
s.update_time = TimeTool::Now();
return true; // 返回true表示需要更新
}
return false;
});
if (result && result.Value() > 0) {
ZRY_LOG_INFO("更新成功");
}
}
// 批量更新
void BatchUpdate() {
StationRepository repo;
// 将所有北京区域的站点状态设为活跃
auto result = repo.Update([](StationInfo& s) {
if (s.region_code == "110000") {
s.status = 1;
return true;
}
return false;
});
}
};
删除(Delete)
cpp
/**
* @brief 删除操作的各种模式
*/
class DeleteExamples {
public:
// 条件删除
void ConditionalDelete() {
StationRepository repo;
// 删除已停用的站点
auto result = repo.Delete([](const StationInfo& s) {
return s.status == 0;
});
if (result) {
ZRY_LOG_INFO("删除 {} 条记录", result.Value());
}
}
// 软删除(推荐)
void SoftDelete() {
StationRepository repo;
// 不真正删除,只标记状态
auto result = repo.Update([](StationInfo& s) {
if (s.station_num == "54511") {
s.status = -1; // -1表示已删除
s.delete_time = TimeTool::Now();
return true;
}
return false;
});
}
};
复杂查询实现
分页查询
cpp
/**
* @brief 分页查询支持
*/
template<typename T>
class PaginatedRepository : public Repository<T> {
public:
struct PageResult {
std::vector<T> data;
int total_count;
int page;
int page_size;
int total_pages;
};
/**
* @brief 分页查询
* @tparam Predicate 谓词类型
* @param predicate 查询条件
* @param page 页码(从1开始)
* @param page_size 每页大小
* @return PageResult 分页结果
*/
template<typename Predicate>
PageResult QueryPage(Predicate predicate, int page, int page_size) {
auto& db = DbManager::Instance().GetDb();
// 查询总数
int total = db.query_count<T>(predicate);
// 查询当前页数据
int offset = (page - 1) * page_size;
auto data = db.query<T>(predicate, offset, page_size);
return {
data,
total,
page,
page_size,
(total + page_size - 1) / page_size
};
}
};
// 使用示例
void UsePagination() {
PaginatedRepository<StationInfo> repo;
auto page = repo.QueryPage(
[](const StationInfo& s) { return s.status == 1; },
1, // 第1页
20 // 每页20条
);
std::cout << "总计: " << page.total_count << "\n";
std::cout << "页数: " << page.total_pages << "\n";
for (const auto& station : page.data) {
std::cout << station.name << "\n";
}
}
关联查询
cpp
/**
* @brief 关联查询支持
*/
class StationDeviceRepository {
public:
struct StationWithDevices {
StationInfo station;
std::vector<DeviceInfo> devices;
};
/**
* @brief 查询站点及其设备
* @param station_num 站点编号
* @return std::optional<StationWithDevices> 结果
*/
std::optional<StationWithDevices> FindStationWithDevices(
const std::string& station_num) {
StationRepository station_repo;
DeviceRepository device_repo;
// 查询站点
auto station = station_repo.FindByStationNum(station_num);
if (!station) {
return std::nullopt;
}
// 查询设备
auto devices = device_repo.FindByStation(station_num);
return StationWithDevices{*station, devices};
}
/**
* @brief 查询所有站点及其设备数量
*/
std::vector<std::pair<StationInfo, int>> FindStationsWithDeviceCount() {
StationRepository station_repo;
DeviceRepository device_repo;
auto stations = station_repo.FindActiveStations();
std::vector<std::pair<StationInfo, int>> result;
for (const auto& station : stations) {
auto devices = device_repo.FindByStation(station.station_num);
result.emplace_back(station, devices.size());
}
return result;
}
};
性能优化策略
1. 连接池复用
cpp
/**
* @brief 连接池优化
*/
class OptimizedRepository : public Repository<DataEntity> {
public:
/**
* @brief 批量操作使用同一连接
*/
void BatchOperationWithSingleConnection() {
auto& db = DbManager::Instance().GetDb();
// 获取连接后保持,多次操作复用
auto conn = db.get_connection();
db.begin_transaction();
try {
for (int i = 0; i < 1000; ++i) {
DataEntity data;
// 填充数据...
db.insert(data);
}
db.commit();
} catch (...) {
db.rollback();
throw;
}
}
};
2. 缓存策略
cpp
/**
* @brief 带缓存的Repository
*/
template<typename T>
class CachedRepository : public Repository<T> {
private:
mutable std::unordered_map<std::string, std::pair<T,
std::chrono::steady_clock::time_point>> cache_;
mutable std::mutex cache_mutex_;
std::chrono::seconds cache_ttl_{60}; // 默认60秒
public:
/**
* @brief 带缓存的查询
*/
std::optional<T> FindByIdCached(const std::string& id) {
{
std::lock_guard<std::mutex> lock(cache_mutex_);
auto it = cache_.find(id);
if (it != cache_.end()) {
// 检查缓存是否过期
auto now = std::chrono::steady_clock::now();
if (now - it->second.second < cache_ttl_) {
return it->second.first;
}
}
}
// 缓存未命中,查询数据库
auto result = this->FindById(id);
if (result) {
std::lock_guard<std::mutex> lock(cache_mutex_);
cache_[id] = {*result, std::chrono::steady_clock::now()};
}
return result;
}
/**
* @brief 使缓存失效
*/
void InvalidateCache(const std::string& id) {
std::lock_guard<std::mutex> lock(cache_mutex_);
cache_.erase(id);
}
};
最佳实践
1. 错误处理
cpp
/**
* @brief Repository错误处理最佳实践
*/
void ErrorHandlingBestPractice() {
StationRepository repo;
// 使用Result类型处理错误
auto result = repo.FindByStationNum("54511");
if (!result) {
// 错误处理
switch (result.Error().Code()) {
case ErrorCode::ERROR_DB_CONNECTION:
ZRY_LOG_ERROR("数据库连接失败");
// 尝试重连或降级
break;
case ErrorCode::ERROR_DB_QUERY:
ZRY_LOG_ERROR("查询执行失败: {}", result.Error().Message());
break;
default:
ZRY_LOG_ERROR("未知错误: {}", result.Error().ToString());
}
return;
}
// 处理结果
auto station = result.Value();
// ...
}
2. 事务管理
cpp
/**
* @brief 事务管理最佳实践
*/
class TransactionExample {
public:
void TransferData() {
auto& db = DbManager::Instance().GetDb();
// RAII事务管理器
struct TransactionGuard {
DbManager& db_;
bool committed_ = false;
explicit TransactionGuard(DbManager& db) : db_(db) {
db_.begin_transaction();
}
void Commit() {
db_.commit();
committed_ = true;
}
~TransactionGuard() {
if (!committed_) {
db_.rollback();
}
}
};
TransactionGuard tx(db);
try {
// 执行多个操作
StationRepository station_repo;
DeviceRepository device_repo;
station_repo.UpdateStatus("54511", 0);
device_repo.Delete([](const DeviceInfo& d) {
return d.station_num == "54511";
});
tx.Commit(); // 提交事务
} catch (const std::exception& e) {
ZRY_LOG_ERROR("事务失败: {}", e.what());
// 事务会在TransactionGuard析构时回滚
}
}
};
3. 单元测试
cpp
/**
* @brief Repository单元测试示例
*/
class MockDbManager {
public:
MOCK_METHOD(Result<std::vector<StationInfo>>, query, ());
MOCK_METHOD(Result<int>, insert, (const StationInfo&));
};
TEST(StationRepositoryTest, FindByStationNum) {
// 使用Mock进行测试
StationRepository repo;
// 设置Mock期望
// ...
auto result = repo.FindByStationNum("54511");
EXPECT_TRUE(result.has_value());
EXPECT_EQ(result->station_num, "54511");
}
总结
本文详细介绍了在C++中实现Repository模式的完整方案:
- 基础Repository类:提供类型安全的CRUD操作
- 具体仓储类:针对特定实体的扩展方法
- 复杂查询:分页、关联查询的实现
- 性能优化:连接池、缓存策略
- 最佳实践:错误处理、事务管理、单元测试
关键设计决策
| 决策 | 选择 | 理由 |
|---|---|---|
| ORM风格 | 轻量级ORM | 平衡便利性和性能 |
| 模板实现 | 编译期类型检查 | 类型安全,零运行时开销 |
| Result类型 | 显式错误处理 | 强制处理错误,避免异常滥用 |
| 连接池 | 单例管理 | 全局统一管理数据库连接 |
该Repository模式已在AIDC项目中广泛应用,支撑日均百万级的数据库操作。
本文基于AIDC项目数据库访问层实践编写,完整代码可在 src_refactored/include/db/ 目录查看。