soci第三方库的安装与环境配置
git clone https://github.com/SOCI/soci.git
cd soci
mkdir build
cd build
cmake ..
make
sudo make install
安装好之后需要手动链接库-lsoci_core -lsoci_mysql -lmysqlclient
运行之后遇到报错 error while loading shared libraries: libsoci_core.so.4.1: cannot open shared object file: No such file or directory的解决方案: 运行命令:find /usr/lib /usr/local/lib -name "libsoci_core.so*”,会返回文件所在位置:
/usr/local/lib/libsoci_core.so.4.1.0 /usr/local/lib/libsoci_core.so.4.1 /usr/local/lib/libsoci_core.so
找到缺损文件的对应版本(我的缺省版本是4.1),复制路径执行
echo "{path}" | sudo tee /etc/ld.so.conf.d/soci.conf sudo ldconfig
将{path}替换为find命令的输出路径,之后运行sudo ldconfig更新库缓存,报错就解决了
soci的使用方法之数据插入
引入头文件
#include <iostream>
#include "soci/soci.h"
#include "soci/soci-platform.h"
初始化session
soci::session sql("mysql", "dbname=music user=wxx password=Wangxinxue666666");
// 如果要连接远程数据库,添加host和port字段 host=remote_host port=3306
第一个参数为使用的后端数据库类型,第二个参数为数据库连接参数,可以指定的参数包括host port dbname user passowrd
等,以空格分隔
insert插入表
std::string userid = "111";
std::string listid = "2222";
std::string listname = "33333";
sql << "insert into music_list values(:userid, :listid, :listname)",
soci::use(userid), soci::use(listid), soci::use(listname);
- 补充(需要注意的事项):
①通过流的方式传递sql语句,用use语法传递参数;
②其中
Person(first_name, last_name)
为数据库table名和column名,values(:first_name, :last_name)
里的为参数的占位符,这里可以随便书写;③需要注意的是
use
函数里的参数的生命周期,切记不能将函数返回值作为use
函数的参数
查询mysql执行结果:
long long id;
int affected_rows = sql.get_last_insert_id("Person", id);
cout << "Query OK, " << affected_rows << " row(s) affected" << endl;
get_last_insert_id
函数可以获取自增长主键(通常是 AUTO_INCREMENT
)相关的插入操作所产生的 ID,它可以用于获取新插入行的唯一标识符,以便在应用程序中跟踪或与其他表建立关联。这在涉及具有自增主键的表时尤其常见。SOCI 库在处理不同数据库时,按需提供了不同的实现。
- 完整示例:
#include <iostream>
#include "soci/soci.h"
#include "soci/soci-platform.h"
using namespace std;
int main() {
try {
soci::session sql("mysql", "dbname=music user=wxx password=Wangxinxue666666");
// 如果要连接远程数据库,添加host和port字段:host=remote_host;port=3306;
string userid = "111";
string listid = "2222";
string listname = "33333";
sql << "insert into music_list values(:userid, :listid, :listname)",
soci::use(userid), soci::use(listid), soci::use(listname);
long long id;
int affected_rows = sql.get_last_insert_id("music_list ", id);
cout << "Query OK, " << affected_rows << " row(s) affected" << endl;
} catch (const soci::soci_error& e) {
cout << "Database error: " << e.what() << endl;
return -1;
} catch (const std::exception& e) {
cout << "Standard exception: " << e.what() << endl;
return -1;
}
return 0;
}
soci使用方法之查询select
可以使用类似流的接口从行对象中提取数据,其中每个提取的变量应该具有对应于其在链中的位置的匹配类型:
soci::session sql("mysql", "dbname=music user=wxx password=Wangxinxue666666");
string list_ID = "1111";
string song_id = "222222";
soci::row r;
sql << "SELECT music_name,author_name,album_name FROM list_content WHERE list_ID=:list_ID AND song_id=:song_id",
into(r), soci::use(list_ID), soci::use(song_id);
但是请注意,此接口与标准的std::istream
类不兼容,并且一次只能提取单行——出于“安全”原因,保留行边界,并且有必要为每个连续的行显式地执行提取操作。
string musicname, singer, album;
r >> musicname >> singer >> album;
cout << "musicname: " << musicname << "\\tsinger: " << singer << "\\talbum: " << album << endl;
上述方法对于只针对查询出一条结果,如果查询结果有多条呢?就需要使用下面的方法:
对于只有一个字段的多条结果集:
string list_ID = "17243903906429226";
soci::rowset<string> rs = (sql.prepare << "SELECT music_name FROM list_content WHERE list_ID=:list_ID",
soci::use(list_ID));
for (soci::rowset<string>::const_iterator it = rs.begin(); it != rs.end(); ++it) {
cout << *it << endl;
}
对于一条语句有多个字段的结果集
string list_ID = "17243903906429226";
soci::rowset<soci::row> rs = (sql.prepare << "SELECT music_name,author_name,album_name FROM list_content WHERE list_ID=:list_ID",
soci::use(list_ID));
for (soci::rowset<soci::row>::const_iterator it = rs.begin(); it != rs.end(); ++it) {
soci::row const& row = *it;
cout << "music_name: " << row.get<string>(0)
<< "\\t\\t\\t\\tauthor_name: " << row.get<string>(1)
<< "\\t\\t\\t\\talbum_name: " << row.get<string>(2)
<< endl;
}
注意:当只有一条结果集的时候,rs里的类型是string、int或其他,如果有多个结果的时候,类型为soci::row
,对于只有一个字段的结果集,也可以使用下面的方法,兼容性更高。
- 完整示例:
int select() {
try {
soci::session sql("mysql", "dbname=music user=wxx password=Wangxinxue666666");
/*
// 只有一条结果
string list_ID = "17243903906429226";
string song_id = "222222";
soci::row r;
sql << "SELECT music_name,author_name,album_name FROM list_content WHERE list_ID=:list_ID",
into(r), soci::use(list_ID);
if (!sql.got_data()) {
std::cout << "No record found." << std::endl;
return 0;
}
string musicname, singer, album;
r >> musicname >> singer >> album;
cout << "musicname: " << musicname << "\\tsinger: " << singer << "\\talbum: " << album << endl;
*/
/*
//结果集只有一个字段
string list_ID = "17243903906429226";
soci::rowset<string> rs = (sql.prepare << "SELECT music_name FROM list_content WHERE list_ID=:list_ID", soci::use(list_ID));
for (soci::rowset<string>::const_iterator it = rs.begin(); it != rs.end(); ++it) {
cout << *it << endl;
}
*/
/*
// 结果集有多个字段
string list_ID = "17243903906429226";
soci::rowset<soci::row> rs = (sql.prepare << "SELECT music_name,author_name,album_name FROM list_content WHERE list_ID=:list_ID", soci::use(list_ID));
for (soci::rowset<soci::row>::const_iterator it = rs.begin(); it != rs.end(); ++it) {
soci::row const& row = *it;
cout << "music_name: " << row.get<string>(0)
<< "\\t\\t\\t\\tauthor_name: " << row.get<string>(1)
<< "\\t\\t\\t\\talbum_name: " << row.get<string>(2)
<< endl;
}
*/
} catch (const soci::soci_error& e) {
cout << "Database error: " << e.what() << endl;
return -1;
} catch (const std::exception& e) {
cout << "Standard exception: " << e.what() << endl;
return -1;
}
return 0;
}
soci使用方法之删除delete
有时候我们需要关注delete操作是否真的删除了数据,mysql本身也会返回操作影响的行数,可以采用如下方法获取:
soci::session sql("mysql", "dbname=music user=wxx password=Wangxinxue666666");
string list_ID = "1111";
soci::statement stmt = (sql.prepare << "DELETE FROM list_content WHERE list_ID=:name", soci::use(list_ID));
stmt.execute(true);
long long affected_rows = stmt.get_affected_rows();
std::cout << "Affected rows is " << affected_rows << "." << std::endl;
soci使用方法之更新update
在stmt执行之后,使用stmt.get_affected_rows();语句可以获取操作影响的行数
soci::session sql("mysql", "dbname=music user=wxx password=Wangxinxue666666");
string list_ID = "17243903906497807";
string id = "1111";
string first = "hello";
string last = "world";
soci::statement stmt = (sql.prepare << "update list_content set music_name=:first, author_name=:last where list_ID=:id",
soci::use(first), soci::use(last), soci::use(id));
stmt.execute(true);
long long affected_rows = stmt.get_affected_rows();
std::cout << "Affected rows is " << affected_rows << "." << std::endl;