如何使用SOCI对std::vector自定义对象执行批量插入?
使用SOCI实现自定义对象vector的批量插入
方法1:利用SOCI原生批量绑定API(推荐)
SOCI内置了批量操作支持,核心是通过statement对象绑定批量数据的连续内存,底层会根据数据库驱动自动选择最优的批量插入方式(如MySQL的多行插入、PostgreSQL的COPY),性能远高于循环单条插入。
假设你的one_min_equity结构体及类型转换已完成,示例代码如下:
#include <soci/soci.h> #include <vector> #include <string> #include <tm.h> namespace models { struct one_min_equity { std::string symbol; std::tm trade_time; double open_price; double close_price; // 其他字段... }; } // 已实现的type_conversion模板(示例框架) namespace soci { template<> struct type_conversion<models::one_min_equity> { typedef values base_type; static void from_base(values const& v, indicator ind, models::one_min_equity& e) { // 字段读取逻辑 e.symbol = v.get<std::string>("symbol"); e.trade_time = v.get<std::tm>("trade_time"); // ...其他字段 } static void to_base(models::one_min_equity const& e, values& v, indicator& ind) { // 字段写入逻辑 v.set("symbol", e.symbol); v.set("trade_time", e.trade_time); // ...其他字段 ind = i_ok; } }; } void bulk_insert_equity(soci::session& sql, const std::vector<models::one_min_equity>& rows) { if (rows.empty()) return; // 提取每个字段的批量数据(也可手动构造vector) std::vector<std::string> symbols; std::vector<std::tm> trade_times; std::vector<double> open_prices; std::vector<double> close_prices; symbols.reserve(rows.size()); trade_times.reserve(rows.size()); open_prices.reserve(rows.size()); close_prices.reserve(rows.size()); for (const auto& row : rows) { symbols.push_back(row.symbol); trade_times.push_back(row.trade_time); open_prices.push_back(row.open_price); close_prices.push_back(row.close_price); } // 准备批量插入语句,绑定批量字段 soci::statement st = sql.prepare << "INSERT INTO one_min_equity (symbol, trade_time, open_price, close_price) " "VALUES (:sym, :time, :open, :close)", soci::use(symbols, "sym"), soci::use(trade_times, "time"), soci::use(open_prices, "open"), soci::use(close_prices, "close"); // 执行批量插入,true开启批量模式 st.execute(true); }
说明
soci::use接收vector时会自动识别为批量数据,驱动会根据数据库特性优化插入逻辑。execute(true)触发批量执行,SOCI会自动处理数据提交的批次大小,平衡性能与内存占用。
方法2:构造多行VALUES语句(适合简单场景)
如果数据库支持多行INSERT语法(如INSERT INTO table (col1,col2) VALUES (v1,v2),(v3,v4)...),可手动构造SQL语句一次性执行,适合数据量不大的场景。
示例代码:
void bulk_insert_equity(soci::session& sql, const std::vector<models::one_min_equity>& rows) { if (rows.empty()) return; const size_t batch_size = 1000; // 分批次避免SQL过长 for (size_t start = 0; start < rows.size(); start += batch_size) { size_t end = std::min(start + batch_size, rows.size()); std::ostringstream oss; oss << "INSERT INTO one_min_equity (symbol, trade_time, open_price, close_price) VALUES "; // 构造VALUES片段 for (size_t i = start; i < end; ++i) { if (i > start) oss << ", "; oss << "(:sym" << i << ", :time" << i << ", :open" << i << ", :close" << i << ")"; } soci::statement st = sql.prepare << oss.str(); // 绑定当前批次的所有字段 for (size_t i = start; i < end; ++i) { st.exchange(soci::use(rows[i].symbol, "sym" + std::to_string(i))); st.exchange(soci::use(rows[i].trade_time, "time" + std::to_string(i))); st.exchange(soci::use(rows[i].open_price, "open" + std::to_string(i))); st.exchange(soci::use(rows[i].close_price, "close" + std::to_string(i))); } st.execute(); } }
注意
- 需按批次拆分数据,避免触发数据库的SQL长度限制。
- 性能略逊于原生批量绑定,适合快速实现小批量插入。
关键提示
- 确保自定义类型的
type_conversion模板逻辑正确,批量操作依赖单个对象的字段映射规则。 - 不同数据库驱动对批量操作的优化不同,优先使用方法1的原生批量绑定以获得最佳性能。
内容的提问来源于stack exchange,提问作者srilakshmikanthanp
相关产品推荐
相关产品推荐

