测试代码:
sql_warpper sql_("tcp://127.0.0.1:3306", "root", "407043", "gamed");
bool ret_ = false;
ret_ = sql_.create("create table test (id_ double, name_ varchar(64), password_ varchar(64)); ");
ret_ = sql_.insert("insert into test values(5.12056683, \"humorly\", \"chen123\");");
ret_ = sql_.insert("insert into test values(5.12056684, \"humorly\", \"chen123\");");
ret_ = sql_.insert("insert into test values(5.12056685, \"humorly\", \"chen123\");");
ret_ = sql_.remove("delete from test where id_ = 5.12056684;");
ret_ = sql_.update("update game.test set id_ = 5.55555555 where id_ = 5.12056683;");
// 待搜索的字段信息
std::tuple<:string std::string> params_("id_", "name_", "password_");
std::vector<:tuple std::string>> user_content_;
ret_ = sql_.select("SELECT * FROM test", user_content_, params_);
std::cout << "content:" << std::endl;
for (auto & val : user_content_)
{
std::cout << "id_ = " << std::get<0>(val) << ", ";
std::cout << "name_ = " << std::get<1>(val) << ", ";
std::cout << "password_ = " << std::get<2>(val) << std::endl;
}
return 0;
封装过程:
使用mysql等数据库在查询时无法避免一个问题,在作select操作时,经常要调用mysql对象中的getInt、getString、getByte、getDouble...,并且要将mysql中的sql::ResultSet对象公开(或以接口提供),其中mysql提供的cppconn也没有很好的解决方案。这里做了一番思考,为何不把对象的查询字段做一个tuple封装,传递给查询接口对应的”字段名称“。再做一个tuple传递结果字段的对应类型,并将查询到的“字段值”存储到其中。该过程中对tuple进行展开让编译器去调用getInt、getString、getByte、getDouble...等,代码设计如下:
1:设计一个获取字段值的tuple,必须与select操作需要的字段值对应,用来将其中的“字段名称”传递给getInt等方法作为参数,例如设计搜索表user_content中的"id_", "name_", "password_"(其中id_值类型为int,其他为varchar(string)); 则有展开字段模板:
std::tuple<:string std::string> params_("id_", "name_", "password_");
2:设计一个接收结果的tuple,用来接收表中搜索到的字段类型结果:
std::vector<:tuple std::string>> user_content_;
3:将select语句、content_、parm_传递到展开接口separation中:
bool select(const std::string & command, std::vector<__dest_type> & dest, __set parm)
{
try {
pstmt_ = con_->prepareStatement(command.c_str());
res_ = pstmt_->executeQuery();
res_->afterLast();
while (res_->previous())
{
// 这里进行参数展开
// 将res传入其中,待稍后参数展开时get对应的字段值
separation<__dest_type sql::resultset __set __type params...>(dest, res_, parm);
}
delete res_;
delete pstmt_;
}
catch (sql::SQLException &e) {
std::string str_logger_("sql error by create select -> code is " +
std::to_string(e.getErrorCode()) + " & describe is " + std::string(e.what()));
wstd::log_writer::log_store(str_logger_, __FILE_LINE__);
return false;
}
return true;
}
4:展开过程解释:
std::vector<__dest_type> & separation(std::vector<__dest_type> & dest, __value_type * src, __set parm)
{
__dest_type tu_;
// 获取字段列表parm待展开的参数数目
constexpr int size_ = sizeof...(params);
// 对参数进行递归展开
get_class<0, size_>::template get<__dest_type __value_type __set t params...>(tu_, src, parm);
dest.push_back(tu_);
return dest;
}
5:逐字段赋值过程
template
struct get_class
{
template
inline static void get(__dest & dest, __src * src, __set parm)
{
constexpr integer_type index_ = N + 1;
// 对tuple中的第N个元素赋值
// 右侧通过偏特化dest中的模板参数调用对应的get value方法
std::get(dest) = get_value_type::template get_value(src, std::get(parm).c_str());
// 递归下一字段
get_class::template get<__dest __src __set params...>(dest, src, parm);
}
};
// 递归到末元素时只赋值无需继续递归
// 末元素即为N = M,即偏特化M,M
template
struct get_class
{
template
inline static void get(__dest & dest, __src * src, __set parm)
{
// 末元素赋值
std::get(dest) = get_value_type::template get_value(src, std::get(parm).c_str());
}
};
6:偏特化get value过程:
template
struct get_value_type
{
inline static auto get_value(__dest_type * val, __parm parm) {}
};
// bigint
template
struct get_value_type
{
inline static auto get_value(__dest_type * val, __parm parm) -> decltype(val->getInt64(parm))
{
return val->getInt64(parm);
}
};
// varchar
template
struct get_value_type<:string __dest_type __parm>
{
inline static std::string get_value(__dest_type * val, __parm parm)
{
return val->getString(parm).c_str();
}
};
// 其他类型在这里照例补充偏特化