【原创】3. MYSQL++ Query类型与SQL语句执行过程(非template与SSQLS版本)

时间:2022-09-17 19:24:12

我们可以通过使用mysqlpp:: Query来进行SQL语句的增删改查。

首先来看一下mysqlpp::Query的一些最简单的调用,

conn.connect(mysqlpp::examples::db_name, "127.0.0.1",   "root", "root");
 
mysqlpp::Query query = conn.query("select item from stock");
mysqlpp::StoreQueryResult res = query.store();
 
// OR
mysqlpp::Query query = conn.query("select * from stock"); 
{
      mysqlpp::UseQueryResult res = query.use();
      while (mysqlpp::Row row = res.fetch_row()) {
 
            // row[0]; 第一列
 
       }
}

在mysqlpp::Connection.query( )方法中,他其实是这样调用的。

【原创】3. MYSQL++ Query类型与SQL语句执行过程(非template与SSQLS版本)

MYSQL++ 的mysqlpp::Query类型

【原创】3. MYSQL++ Query类型与SQL语句执行过程(非template与SSQLS版本)

请注意,这里的Query居然继承了std: :ostream!这个是为什么?

我认为,这样做的一个好处是,可以运用如下的方式

mysqlpp::Query q(0);

q << mysqlpp::quote << “test”;

当然,mysqlpp::quote是一个enum【在mani.h中定义】,这里有很多技巧,放在专门的“escape与quote”相关内容中介绍。

  1. 用法

首先需要说明的是,通常情况下,APP并不会直接创建这个mysqlpp::Query对象,而是call mysqlpp::Connection::query() to get one tied to that connection.

该类型提供了一些能够执行select,insert等SQL语句的方法。有下面几种方法来执行一句SQL语句

  • pass a SQL statement in either the form of a C or C++ string to one of the exec*(),store*(),or use() methods
  • build up the query string over several C++ statements using Query's stream interface.
  • "template queries",This is something like C's printf() function. You call the parse() method to tell the Query object that the query string contains placeholders.
  • Use Specialized SQL Structures (SSQLS) to manipulate the db only by data structure.

Query有一些最基本的用法,包括

  • 直接利用已经拼凑好了的SQL语句调用mysqlpp::Query::exec*(),mysqlpp::Query::store()或者mysqlpp::Query::use()
  • 使用ostream接口,像构造cout一样构造SQL语句,然后再调用mysqlpp::Query::exec*(),mysqlpp::Query::store()或者mysqlpp::Query::use()
  • 类似于printf一样使用template queries
  • 类似于Hibernate那样使用Specialized SQL Structures feature(SSQLS)

这里只介绍最简单的两个情况,template queries和SSQLS的原理放到其他章节。

仔细来看一下Query提供的各个重要方法的重构方式(类似的方法族还有store)

  • 首先关注参数

1)

UseQueryResult mysqlpp::Query::use  (const char *  str, size_t  len ) 

该方法主要是我们已经有了一个已经”成熟“的SQL语句,类似于,我们在UI工具上已经打好了,然后贴过去的那种,这种语句必须要已经经过了escape等转义工作,MYSQL++内部并不做进一步的转义操作。

2)

UseQueryResult mysqlpp::Query::use ( const SQLTypeAdapter &  str )

SQLTypeAdaper就是这个可以将普通的,未经过转义的SQL语句,或者如果“基本语句”(就是上面mysqlpp::Connection.query()传入的char*)是一个template query,那么可以将某个int,double等转义为可以供底层API所使用的string形式的工具类。(例如,如果update set a = 'sth' , 在这个sth周围就需要加上引号,而我们所传入的可能就是这个“sth”)

所以这个方法的工作就是将原始的SQL字符串 str 转换为可以供底层API所使用的字符串

3)

UseQueryResult mysqlpp::Query::use ( SQLQueryParms &  p ) 

SQLQueryParms是一个为了template query而准备的PARAM相关的类型,例如,如果有类似于这样的sql template 语句(可能和实际的MYSQL++用法不一致,只是表意

select * from where id = %d, name = ‘%s’.

则我们可以这样设置SQLQueryParms

SQLQueryParms sqp;

sqp << 1 << "root";

4)

UseQueryResult mysqlpp::Query::use ( )

这个方法就是使用“基本语句”进行逐条执行。

  • 再来关注返回值

为了讲述方便,我们先来看一下在result.h(Declares classes for holding information about SQL query)中所定义的各种类型的关系。这几个类型不在这里做仔细介绍,可以查看相关章节。

【原创】3. MYSQL++ Query类型与SQL语句执行过程(非template与SSQLS版本)

1)

bool exec(const std::string& str);

这里返回的是bool,表示的是“语句是否执行成功”,我认为适合于那种update, delete,insert,且都不关心有多少rows被touch的情况。



2)

SimpleResult execute();

这里的SimpleResult正如其名,其中只有如下信息

  • the last value used for an AUTO_INCREMENT field

    (ulonglong insert_id() const)

  • the number of rows affected by the query

    (ulonglong rows( ) const)

  • any additional information about the query returned by the server(const char* info( ) const)

3)

UseQueryResult use();

由于use的语义类似于使用游标,也就是支持一行一行地拉出内容,所以UseQueryResult 也就自然而然地支持一些关于fetch row的功能。

4)

StoreQueryResult store();

StoreQueryResult它本身就是从vector<Row>继承而来,所以它就是vector。所以用户程序可以直接使用下标的形式来获取所有的ROW。这也就是说在这个store之后,所有的ROW的内容都在了这个vecor<Row>里面了。

  • for_each,store_if,storein,storein_set,storein_sequence

这些方法都是模仿STL中的<algorithm>里面的迭代器的处理函数,具体可以看看文档。

  • insert,update,insertfrom,replace,replacefrom

这些方法都是给SSQLS所使用的。

2. 实现

1) insert policy

首先我们看到了在mysqlpp::Query类型的一开始,就在private定义下面定义了一个#include

【原创】3. MYSQL++ Query类型与SQL语句执行过程(非template与SSQLS版本)

通过查看这个头文件,他定义了一系列的辅助类型,他们控制着在哪些条件下ROW是可以被插入的。文档中说,这些类型都是为SSQLS服务的(核心作用是在Query::insertfrom() )

他们的核心方法是一个叫做can_add的方法

  • RowCountInsertPolicy——如果当前已经插入的rows查过了某个threshold,那么can_add就返回false
  • SizeThresholdInsertPolicy——如果当前想要插入的row的大小大于预设的threshold,那么can_add就返回false
  • MaxPacketInsertPolicy——如果当前已经插入的rows的总体的大小查过了某个threshold,那么can_add就返回false

2) 最简单的实现流程(普通query,而非SSQLS或者template query)

我们假设有如下的调用Query代码

conn.connect(mysqlpp::examples::db_name, "127.0.0.1",   "root", "root"); 
mysqlpp::Query query = conn.query("select item from stock");
mysqlpp::StoreQueryResult res = query.store();

mysqlpp::Query query = conn.query("select item from stock");

当代码进入到Connection::query的时候,该函数实际上在栈上新添了一个mysqlpp::Query对象,此时调用的构造函数是

【原创】3. MYSQL++ Query类型与SQL语句执行过程(非template与SSQLS版本)

需要注意的是两个变量

  • sbuffer,他是一个std::stringbuf,用来存储assembled query。另外,init和imbue方法都是std::ostream的方法。
  • template_defaults,这是一个SQLQueryParms,这个变量实际上视为template query做准备的,他用作“default template parameters, used for filling in parameterized queries”

注意看到上面的红色框中的内容

  • 初始化列表中的内容都会在进入构造器之前完成,所以如果有类型在初始化列表中被构造(如下面的a(1),和上面例子中的template_defailt(this)),编译器都会在包含类型构造之前先行构造。(我原来以为,被一个包含类型只会被调用无参默认构造函数,其实可以在成员初始化列表中调用其他构造函数)

如果有如下代码

class A
{
public:
    A(int i) { cout << "in cons A " << i << endl;}
}
 
class B
{
public:
    B() : a(1) { cout << "in cons B" << endl;}
private:
    A a;
}
 
输出结果将会是
in cons A 1
in cons B
 

  • 根据上面的理论,template_defaults(this),实际上是调用了SQLQueryParms(Query * q)这个构造函数来构造SQLQueryParms.
  • 其他的都是将sql语句加入到sbuffer中。但是需要注意的是上面提到的imbue用法,我们需要使用的是最通用的locale。

query.store( );

【原创】3. MYSQL++ Query类型与SQL语句执行过程(非template与SSQLS版本)

  • AutoFlag其实就是一个RAII,在构造函数中将 template_defaults.processing_ 置为 true,在析构函数中将其置为false
  • Query: :store有以下四个不同的overload,具体的不同点请参看上文,以下四者殊途同归,最终调用的都是最后一个版本
StoreQueryResult store();
StoreQueryResult store(SQLQueryParms& p);
StoreQueryResult store(const SQLTypeAdapter& str);
StoreQueryResult store(const char* str, size_t len);

再来看一下Query: :str( SQLQueryParms)的源代码

【原创】3. MYSQL++ Query类型与SQL语句执行过程(非template与SSQLS版本)

先解释一下什么是parse_elems_,他的定义是 std::vector<SQLParseElement> parse_elems_; 表示 List of template query parameters

所以很显然,在我们的这一章节所关注的用法中,Query:: str( SQLQueryParms& )直接返回的就是sbuffer_.str( ),也就是构造Query时候所传入的SQL语句。

当回到Query:: store( )的时候,该方法直接调用的就是Query:: store(const SQLTypeAdapter& ),其中str的返回值(string)到SQLTypeAdapter是隐式转换并进行构造的(因为SQLTypeAdapter有一个以string为param的构造器)

【原创】3. MYSQL++ Query类型与SQL语句执行过程(非template与SSQLS版本)

该方法又会调用最为核心的store版本。StoreQueryResult store(const char* str, size_t len);(else里面的那句)

该版本其实也不难理解,

【原创】3. MYSQL++ Query类型与SQL语句执行过程(非template与SSQLS版本)

523行到530行这一段是对template query的处理,这里不涉及,先略过。

从531行开始然后就是调用DbDriver的exec( )方法进行SQL语句执行,并通过DbDriver:: store_result( ) 方法获取表示结果集的 MYSQL_RES。

536行开始,针对res的结果进行处理,这里强调区分了SQL语句无返回值和SQL语句执行失败(res返回的是null,但是sql_error==0)两种情况。

对于非template query,需要做的是直接reset(调用Query:: reset( )),然后构造一个StoreQueryResult返回

最后来说一下这个Query:: reset( )函数

【原创】3. MYSQL++ Query类型与SQL语句执行过程(非template与SSQLS版本)

该方法直接将ostream的buffer放空,并调整指针位置,重置所有的变量,防止下一次的执行情况和这一次的冲突。

最后需要说明的一点是,对于MYSQL C API而言,需要返回结果行的语句(如select)和不需要返回结果行的语句(如insert, delete)都是通过mysql_query( )函数进行的,所以其实在mysqlpp:: Query类型中,store( )和execute( )系列方法在最终执行上是一致的,即都是通过调用DbDriver:: execute(const char* qstr, size_t length)进行的。所以store( )和execute( )的唯一区别在于store( )其实最终返回的是带有结果的 StoreQueryResult类型,而execute( )返回的是 SimpleResult

原创作品,转载请注明出处www.cnblogs.com/aicro

【原创】3. MYSQL++ Query类型与SQL语句执行过程(非template与SSQLS版本)的更多相关文章

  1. 转:Oracle中SQL语句执行过程中

    Oracle中SQL语句执行过程中,Oracle内部解析原理如下: 1.当一用户第一次提交一个SQL表达式时,Oracle会将这SQL进行Hard parse,这过程有点像程序编译,检查语法.表名.字 ...

  2. MySql基础架构以及SQL语句执行流程

    01. mysql基础架构 SQL语句是如何执行的 学习一下mysql的基础架构,从一条sql语句是如何执行的来学习. 一般我们写一条查询语句类似下面这样: select user,password ...

  3. Oracle SQL语句执行过程

    前言 QQ群讨论的时候有人遇到这样的问题:where子句中无法访问Oracle自定义的字段别名.这篇 博客就是就这一问题做一个探讨,并发散下思维,谈谈SQL语句的执行顺序问题. 问题呈现 直接给出SQ ...

  4. SQL语句执行过程详解

    一.SQL语句执行原理: 第一步:客户端把语句发给服务器端执行 当我们在客户端执行select语句时, 客户端会把这条SQL语句发送给服务器端,让服务器端的进程来处理这语句.也就是说,Oracle客户 ...

  5. mysql优化&colon;explain分析sql语句执行效率

    Explain命令在解决数据库性能上是第一推荐使用命令,大部分的性能问题可以通过此命令来简单的解决,Explain可以用来查看SQL语句的执行效 果,可以帮助选择更好的索引和优化查询语句,写出更好的优 ...

  6. &lbrack;转&rsqb;使用mysql profiles 来查看sql 语句执行计划

    From : http://blog.csdn.net/radkitty/article/details/4632289 要使用该功能,mysql的版本必须在5.0.37版本以上.否则只能使用expl ...

  7. mysql优化–explain分析sql语句执行效率

    Explain命令在解决数据库性能上是第一推荐使用命令,大部分的性能问题可以通过此命令来简单的解决,Explain可以用来查看SQL语句的执行效 果,可以帮助选择更好的索引和优化查询语句,写出更好的优 ...

  8. Mysql explain分析sql语句执行效率

    mysql优化–explain分析sql语句执行效率 Explain命令在解决数据库性能上是第一推荐使用命令,大部分的性能问题可以通过此命令来简单的解决,Explain可以用来查看SQL语句的执行效 ...

  9. sql语句执行的时间

    统计mysql里每条SQL语句执行的时间 收藏 CrazyHarry 发表于 2年前 阅读 3785 收藏 8 点赞 3 评论 3 Google.Github 双重认证前端课程,独家硅谷内容,每周直播 ...

随机推荐

  1. 命令模式(Command Pattern)

    命令模式的本质是对命令进行封装,将发出命令的责任和执行命令的责任分割开.命令模式是为了解决命令的请求者和命令的实现者之间的耦合关系. 将来自客户端的请求传入一个对象,从而使你可用不同的请求对客户进行参 ...

  2. Linux 中,如何显示 (gcc)make时实际执行命令

    问题: 调试编译问题,如何获取,GCC(或许make)时,实际编译器和链接器正在执行的命令? 解决方法: 方法一:通用方法 使用dry run,如下 $ make -n 这将显示make 命令正在试图 ...

  3. C&num;中如何设置窗体的默认按钮和取消按钮

    可以直接在窗体的AcceptButton和CancelButton中设置相应的按钮. 也可以在后头通过代码设置: this.AcceptButton = (IButtonControl)btnSave ...

  4. 不加好友实现QQ在线代码状态临时会话

    网友在介绍怎么样使用QQ来强制聊天,才想到以前一直遇到的QQ在线生成代码后,遇到的必须添加好友才能聊天的一个疑问. 公告:“QQ在线状态”V2.0正式发布,解决了QQ2009用户点击“在线状态”后须添 ...

  5. DDD领域驱动 (一)

    说道DDD不得不说传统的架构与DDD的架构区别. 传统的架构不外乎就是三层,而在这三层里面又不断的细分,始终没有达到想要的效果,那么为什么当时还是采用三层. 当然在DDD没有提出的时候三层是大多数人的 ...

  6. hbase常用操纵操作——增删改查

    查询某个资金账户的信息 get 'dmp:hbase_tags','资金账号' 创建表 create 'emp', 'personal data', 'professional data' 在HBas ...

  7. ARM的体系结构与编程系列博客——ARM体系版本

    ARM体系版本前言 很多人都知道,ARM有许多版本,口中最长说的就是ARM7\ARM9\ARM11,诚然,这个的确是ARM处理器的版本,但绝对不是ARM的版本,其实ARM到迄今为止经历了6代版本,随着 ...

  8. Android 错误集合

    1. Error:java.util.concurrent.ExecutionException: com.android.tools.aapt2.Aapt2Exception: AAPT2 erro ...

  9. Qt treewidget样式的自定义(转)

    这个treewidget样式真是写得让人心碎,主因是那个天杀的表头,真是块古里古怪的硬骨头,令人抓狂,一直找不到给表头设定背景图的方法,让我一度决定弃用tree. 后来表头的属性找到了,下拉条又找不到 ...

  10. cocos2dx三种定时器的使用以及停止schedule,scheduleUpdate,scheduleOnce。

    今天白白跟大家分享一下cocos2dx中定时器的使用方法. 首先,什么是定时器呢?或许你有时候会想让某个函数不断的去执行,或许只是执行一次,获取你想让他每隔几秒执行一次,ok,这些都可以统统交给定时器 ...