目录
官网:https://tangentsoft.com/mysqlpp/home
官方手册:https://tangentsoft.com/mysqlpp/doc/html/refman/
参考博客:
https://www.cnblogs.com/aicro/category/565280.html
https://www.cnblogs.com/comoon/p/4104482.html
mysql++
1. Introduction(简介)
MySQL++是官方发布的一套C++ API;
MySQL++是对MySQL和MariaDB C api的再次封装,是 MySQL C API 的强大 C ++包装器(使用 STL 容器);
它建立在与标准c++库相同的原则之上,使处理数据库如同处理std容器(STL)一样简单。
MySQL++还提供了一些工具,可以让您在自己的代码中避免重复的SQL,为这些常见任务提供了本地c++接口。
1.1 CentOS7安装mysql++ - 3.2.5
#首先确保安装了mysql,如果已经安装了跳过此步骤
yum install mysql-devel
#下载MySQL++源码并解压
wget http://www.tangentsoft.net/mysql++/releases/mysql++-3.2.5.tar
tar -zxvf mysql++-3.2.5.tar
mv mysql++-3.2.5 mysql++
cd mysql++
#执行./configure生成makefile文件
./configure --enable-thread-check --enable-disasm LDFLAGS='-pthread'
#编译出libmysqlpp.so
make
make install
#install成功后会将.so文件拷贝到/usr/local/lib下,并把.h头文件拷贝到/usr/local/include下。
# g++编译器只会使用/lib和/usr/lib这两个目录下的库文件
# 所以添加库路径并使之生效
vim /etc/ld.so.conf
添加libmysqlpp.so的路径(/usr/local/lib),保存并退出
ldconfig
#创建so的连接:
ln -s /usr/local/lib/libmysqlpp.so /usr/lib/libmysqlpp.so
2. Overview(概述)
写代码的步骤:
- 打开连接
- 形成并执行查询
- 如果成功,则遍历结果集
- 否则,处理错误
每个步骤都对应一个 MySQL ++类或类层次结构。
2.1 The Connection Object(连接对象)
https://tangentsoft.com/mysqlpp/doc/html/refman/classmysqlpp_1_1Connection.html
Connection 对象管理与 MySQL 服务器的连接。
MySQL 支持客户端和服务器之间的许多不同类型的数据连接:
- TCP/IP、
- Unix domain sockets(Unix 域套接字)、
- Windows named pipes(Windows 命名管道)
通用 Connection 类支持所有这些(基于您传递给 Connection :: connect()的参数从而找出哪一个)。但是如果您事先知道程序只需要一种特定的连接类型,有具有更简单接口的子类。例如:如果知道程序将始终使用联网的数据库服务器,则使用 TCPConnection。
所有的链接操作可以通过使用mysqlpp::Connection类型进行;
为了方便起见,mysqlpp还提供了TCPConnection,UnixDomainSocketConnection以及WindowsNamedPipeConnection。
但是一般情况只需要通过Connection的不同Connect方法overload就可以进行连接。
2.2 The Query Object(查询对象)
通常使用由 Connection 对象创建的 Query 对象创建 SQL 查询。
查询语句的形式:
1 Query acts as a standard C++ output stream(Query充当标准的c++输出流),因此可以像向std::cout或std::ostringstream那样向它写入数据。mysql++库包括可识别类型的流操纵器,因此很容易建立语法正确的SQL。
2 Query还具有称为模板查询的功能,它的工作方式类似于C的printf()函数:您设置了一个固定的查询字符串,其中带有标记,这些标记指示在何处插入变量部分。如果有多个结构相似的查询,只需设置一个模板查询,然后在程序的各个位置使用它。
3 建立查询的第三种方法是将查询与 SSQLS 一起使用。该特性允许您创建映射数据库模式的c++结构。这些又为 Query 提供了构建许多常见 SQL 查询所需的信息。给定 SSQLS 格式的数据,它可以在表中 INSERT,REPLACE 和 UPDATE 行。它也可以产生SELECT * FROM SomeTable 查询并将结果存储为 SSQLSes 的 STL 集合。
MYSQL++支持的查询方法是
- 直接使用Query stream输入SQL语句
- 使用Template Query采用类似于printf的方式进行输入SQL语句
- 使用SSQLS,通过类似于Hibernate的方式对Data Struct进行操作来操作底层数据库
2.3 Result Sets(结果集)
MYSQL++支持三种遍历数据结果的方法,
- 所有数据结果行都拿出来到内存(store)
- 游标一样逐行操作(use)
- 类似于Hibernate的利用DataStruct进行直接操作的方式
结果集中的字段数据存储在一个特殊的std:: String类中,称为String。该类具有转换操作符,可以自动将这些对象转换为任何基本的C数据类型。另外,MySQL++定义了DateTime类,可以从一个MySQL DATETIME字符串初始化。这些自动转换受到保护,不受坏转换的影响,可以设置警告标志或抛出异常,这取决于您如何设置库。
对于结果集,MySQL++有很多不同的方式来表示它们:
2.3.1 Queries That Do Not Return Data(不返回数据的查询)
并不是所有的SQL查询都返回数据。例如:CREATE TABLE。对于这些类型的查询,有一种特殊的结果类型(SimpleResult),它只报告查询产生的状态:查询是否成功,它影响了多少行(如果有的话),等等。
2.3.2 Queries That Return Data: MySQL++ Data Structures(返回数据的查询:MySQL ++数据结构)
检索结果集最直接的方法是使用Query::store()。
这将返回一个StoreQueryResult对象,该对象派生自std::vectormysqlpp::Row,使其成为一个随机访问的行容器。
反过来,每个Row对象就像String对象的std::vector,一个对象对应结果集中的每个字段。
因此,可以将StoreQueryResult作为一个二维数组:
可以通过result[1][4]来获得第2行上的第5个字段。
还可以通过字段名访问行元素,像这样:result[2][“price”]。
处理查询结果的一种不那么直接的方法是使用query::use(),它返回一个UseQueryResult对象。
这个类的作用类似于STL输入迭代器,而不是std::vector:每次处理一行 遍历结果集,始终向前。
你无法在结果集中到处查找,而且你不知道集合中有多少结果 直到你找到结果的末尾。
但是,您可以获得更好的内存效率,因为整个结果集不需要存储在RAM中。当您需要大型结果集时,这非常有用。
2.3.3 Queries That Return Data: Specialized SQL Structures(返回数据的查询:特殊的 SQL 结构)
通过 MySQL ++的数据结构访问结果是一个相当低的抽象层次。它比使用MySQL C API好,但也差不了多少。
通过使用SSQLS 特性,您可以将问题提升到更接近问题空间的层次。
这允许您定义与数据库中的表结构相匹配的c++结构。此外,可以很容易地将SSQLSes与常规STL容器(以及算法)一起使用,因此不必处理MySQL++奇怪的数据结构。
这种方法的优点是您的程序只需要嵌入很少的SQL代码。您可以简单地执行一个查询,并以c++数据结构的形式接收结果,可以像访问任何其他结构一样访问这些数据结构。可以通过Row对象访问结果,也可以要求库将结果转储到STL容器中——顺序的或关联的,这对您来说没什么关系。考虑一下:
vector<stock> v;
query << "SELECT * FROM stock";
query.storein(v);
for (vector<stock>::iterator it = v.begin(); it != v.end(); ++it)
{
cout << "Price: " << it->price << endl;
}
用起来是不是很顺畅?
如果您不想创建SSQLSes来匹配您的表结构,从MySQL++ v3开始,现在可以在这里使用Row
而不是:
vector<mysqlpp::Row> v;
query << "SELECT * FROM stock";
query.storein(v);
for (vector<mysqlpp::Row>::iterator it = v.begin(); it != v.end(); ++it)
{
cout << "Price: " << it->at("price") << endl;
}
它缺乏某种语法上的优雅,但它有自己的用途
2.4 Exceptions(例外)
默认情况下,库在遇到错误时抛出异常。
如果愿意,您可以要求库设置一个错误标志,但异常包含更多信息。
它们不仅包含一个字符串成员,告诉您为什么抛出异常,而且还有几种异常类型,因此您可以在单个try块中区分不同的错误类型。
3. 使用(相关类的介绍)
mysqlpp::OptionalExceptions
就是一个对于一个表示“是否需要抛出异常”的变量的包装。在Connection类型的内容,会在出现错误的时候调用OpetionalExceptions.throw_exceptions( )方法来查看是否需要使用异常的手段来表示错误。
mysqlpp::Connection
这个类型是用户程序能够看到的少数几个类型,它所包含的主要的方法就是
“连接”,
“断开连接”,
“创建某个数据库" “CREATE DATABASE”,
”drop某个数据库“ DROP DATABASE实现的,
”查看某张 table 中的数据行数“,
”关闭mysql服务
等操作“。
同时,该类型也可以返回一个mysqlpp::Query类型,该类型主要负责查询操作。另外,当我们以后看到mysqlpp::Query的时候,我们很容易发现它的构造函数必定需要一个mysqlpp::Connection,也就是说mysqlpp::Query的所有操作,其实也就是再次调用mysqlpp::Connection的对应方法,后者再去调用mysqlpp::DBDriver来做真正的数据库操作。
需要注意的是,Connection其实就是一个代理类型,所有的和数据库进行操作的非查询类动作(包括了连接,查看连接是否还在,MYSQL的操作出错的错误信息和错误号,通信方式(ipc_info方法),选择当前DB)都是交给mysqlpp::DBDriver来做的。他才是真正的执行者。
mysqlpp:: Query 进行SQL语句的增删改查
mysqlpp::StoreQueryResult 所有数据结果行
mysqlpp::UseQueryResult 游标一样逐行操作
mysqlpp::ConnectionPool 连接池
3.1 mysqlpp::Connection
官方手册:
https://tangentsoft.com/mysqlpp/doc/html/refman/
https://tangentsoft.com/mysqlpp/doc/html/refman/classmysqlpp_1_1Connection.html
#include <connection.h>
3.2 mysqlpp::Query
3.3 mysqlpp::Row
3.4 mysqlpp::StoreQueryResult
3.5 mysqlpp::UseQueryResult
4. user manual.上的例子及Makefile
- helloMySQL++.cpp
#include <mysql++/mysql++.h>
int main()
{
mysqlpp::String greeting("Hello, world!");
std::cout << greeting << std::endl;
return 0;
}
- Makefile
# 头文件目录
CXXFLAGS := -I/usr/include/mysql \
-I/usr/local/include/mysql++
# 库目录
LDFLAGS := -L/usr/local/lib \
-L/usr/lib64/mysql/
# 动态库
LDLIBS := -lmysqlpp \
-lmysqlclient
# 源文件
EXECUTABLE := helloMySQL++
all: $(EXECUTABLE)
clean:
rm -f $(EXECUTABLE) *.o
[root@lwh testcpp]# ./helloMySQL++
Hello, world!
[root@lwh testcpp]#
5. /mysql+±3.2.5/examples/目录的(官方)例子
5.0 运行官方demo之前,首先得有个数据库,执行安装目录下的resetdb
./resetdb -s 127.0.0.1 -u [user]-p [password]
[root@lwh mysql++-3.2.5]# ./resetdb -s 127.0.0.1 -u root -p root123
Connecting to 'root'@'127.0.0.1', with password...
Dropping existing sample data tables...
Creating stock table...
Populating stock table...inserted 4 rows.
Creating empty images table...
Creating deadlock testing tables...
Reinitialized sample database successfully.
[root@lwh mysql++-3.2.5]#
可以看到mysql中多了一个数据库mysql_cpp_data
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| MySQLCrashCourse |
| information_schema |
| mysql |
| mysql_cpp_data | !!!!!
| performance_schema |
| sys |
+--------------------+
6 rows in set (0.01 sec)
mysql>
5.1 simple1.cpp
#include <iostream>
#include <errno.h>
#include <mysql++/mysql++.h>
using namespace std;
/*
mysql -uroot -proot123
use MySQLCrashCourse
select * from customers;
*/
int main(int argc, char *argv[])
{
mysqlpp::Connection conn(false);
if (conn.connect("mysql_cpp_data", "127.0.0.1", "root", "root123"))
{
// Retrieve a subset of the sample stock table set up by resetdb
// and display it.
mysqlpp::Query query1 = conn.query("select item from stock");
if (mysqlpp::StoreQueryResult res = query1.store())
{
cout << "We have:" << endl;
mysqlpp::StoreQueryResult::const_iterator it;
for (it = res.begin(); it != res.end(); ++it)
{
mysqlpp::Row row = *it;
cout << '\t' << row[0] << endl;
}
}
else
{
cerr << "Failed to get item list: " << query1.error() << endl;
return 1;
}
mysqlpp::Query query2 = conn.query("select * from stock");
if (mysqlpp::StoreQueryResult res = query2.store())
{
cout.setf(ios::left);
cout << setw(31) << "item"
<< setw(10) << "num"
<< setw(10) << "weight"
<< setw(10) << "price"
<< "sdate" << endl;
for (size_t i = 0; i < res.num_rows(); i++)
{
cout << setw(30) << res[i]["item"]
<< setw(9) << res[i]["num"]
<< setw(9) << res[i]["weight"]
<< setw(9) << res[i]["price"]
<< setw(9) << res[i]["sdate"] << endl;
}
}
else
{
cerr << "Failed to get item list: " << query2.error() << endl;
return 1;
}
return 0;
}
else
{
cerr << "DB connection failed: " << conn.error() << endl;
return 1;
}
}
# ./simple1++ -s 127.0.0.1 -u root -p root123 改写后不需要传参
[root@lwh mysql++test]# make
g++ -I/usr/include/mysql -I/usr/local/include/mysql++ -L/usr/local/lib -L/usr/lib64/mysql/ simple1.cpp -lmysqlpp -lmysqlclient -o helloMySQL++
[root@lwh mysql++test]# ./simple1
We have:
Nürnberger Brats
Pickle Relish
Hot Mustard
Hotdog Buns
item num weight price sdate
Nürnberger Brats 97 1.5 8.79 2005-03-10
Pickle Relish 87 1.5 1.75 1998-09-04
Hot Mustard 73 0.95 0.97 1998-05-25
Hotdog Buns 65 1.1 1.10 1998-04-23
[root@lwh mysql++test]#