简介
cppdb 是一个跨平台的 C++ 数据库操作类库,可以从 sourceforge 下载源码包或者直接从 SVN 库中检出。
编译 (VS2008)
首先使用 CMake 生成项目文件,下载后解压,运行 /bin/cmakegui.exe,需要设定 cppdb 的代码目录和项目文件的输出目录(比如在 cppdb 下面新建一个 build 目录,清楚一些)。
然后是配置,大致步骤:
- 点击 Configure 按钮,选择 VS2008
- 选中 DISABLE 组下面的的:DISABLE_ODBC、DISABLE_PQ、DISABLE_SQLITE
- 选中 MYSQL 组下面的 MYSQL_BACKEND_INTERNAL(这样最终就生成一个 cppdb.dll,不然还要附带一个 cppdb_mysql.dll),并分别设定 MYSQL_LIB 和 MYSQL_PATH 为 C:/Program Files (x86)/MySQL/MySQL Server 5.0/lib/opt/libmysql.lib 和 C:\Program Files (x86)\MySQL\MySQL Server 5.0\include(我机器上的操作系统是 64 位 Win7)。
- 再点击 Configure,应该没有红色的配置项了
- 点击 Generate,项目文件将在指定的目录下(cppdb/build)生成
然后就可以用 VS2008 来打开 cppdb/build/cppdb.sln 了,直接编译会碰到两个问题:
1. error C2146: syntax error : missing ‘;’ before identifier ‘fd’
这个需要在 mysql_backend.cpp 的开头加上一句:
#include <winsock2.h>
2. illegal token on right side of ‘::’
这个错误的相关讨论可以参照这篇文章,文中给出的方法需要将代码中的
if(v > std::numeric_limits<T>::max() || v < std::numeric_limits<T>::min())
修改成:
if(v > (std::numeric_limits<T>::max)() || v < (std::numeric_limits<T>::min)())
但评论中还有更直接的方法,在项目属性里面定义一个 NOMINMAX 就好了。
使用中碰到的问题
1. cppdb::statement::affected()
我代码中有时需要更新一条可能不存在的记录,如果不存在,就直接插入一条新记录,而存在与否,就是调用这个 affected() 来判断,然后碰到的问题是明明记录已经存在,更新操作也执行成功(虽然字段内容没变),但 affected 返回的值仍是 0。
跟踪了下 cppdb 的代码,最终调用的是 mysql_stmt_affected_rows(),然后查到 MySQL 的官方文档里是这样解释的:
For UPDATE statements, the affected-rows value by default is the number of rows actually changed. If you specify the CLIENT_FOUND_ROWS flag to mysql_real_connect() when connecting to mysqld, the affected-rows value is the number of rows “found”; that is, matched by the WHERE clause.
找到原因就好办了,直接修改 mysql_backend.cpp,将
if(!mysql_real_connect(conn_,phost,puser,ppassword,pdatabase,port,punix_socket,0))
中最后一个参数 0 修改成 CLIENT_FOUND_ROWS 就好了。
2. cppdb::statement::reset()
示意代码:
cppdb::statement st = _conn << ….
cppdb::result r = st.query();
st.reset();
r.fetch(“”, v); // bang!!!
必须在 r 使用完成之后,才能调用 st.reset()。
3. cppdb::statement::bind()
传入的字段值类型是 std::string 时,bind 操作内部直接使用了 std::string::c_str() 生成的临时字符串!所以如果 std::string 自身也是临时变量的话,就要当心了。。。
std::string getValue(…) { …}
…
cppdb::statement st = _conn << …
st.bind(1, getValue(…));
…
st.exec(); // bang!!!
只能这样写:
…
std::string s = getValue(…);
st.bind(1, s);
…
st.exe(); // ok~