【原创】13. MYSQL++之SSQLS(基本用法篇)
1. 综述
终于来到了SSQLS( Specialized SQL Structure),照我看来这是一个很类似于Hibernate的功能。也就是说,通过SSQLS可以将一张表完全对应到一个C++结构体中,然后只要对于这个结构体进行操作,同时再加入到对应的mysqlpp:: Query对应的方法中,我们就可以执行对应的SQL语句。
值得说一下的是,该功能在实际项目中还是相当有用的,但是笔者所在公司由于其业务的特殊性,通常来说表的结构会非常非常大(有一些表居然有近200个字段)。根据作者的manual,MYSQL++默认只支持不超过25个字段的表结构,但是可以通过在编译前调整一些参数来修改这个限制。于是笔者进行了一下测试,通过这里的说法,修改为200个字段,然后编译整个MYSQL++重建,发现不是一般的卡,笔者刚开始以为,只是在编译MYSQL++的时候会比较卡,但是实际上,每一个运用了MYSQL++的程序都在编译时非常的卡!原因?后面你会看到的。
最后来说一下SSQLS的限制,其实编译慢也就算了,他最大的缺点是源自于C++的劣根性。我们知道,如果我们申明了一个变量int i,如果没有为其初始化,他的值就是个乱码。由于在SSQLS的“表-结构”对应中也有可能会用到int, double,long这种最原始的数据类型,所以也就存在这个问题,即,他没有办法为你赋初值的(但是由于SQL表中的varchar和char,在MYSQL++中用std::string表示的,所以字符类型没有初始化问题)。笔者为此吃过不少亏,因为在执行SQL语句的时候(利用SSQLS做一句insert)返回了一个语法错误!原来笔者的表里面有一些double,然后由于内存垃圾的缘故,导致了这个double被写成了1.23E10之类的,在insert的时候需要一个数字的地方却有了这么个东西,于是返回出错。退一万步来说,即使没有这个返回错误,这样的表你敢用吗?
2. 用法
老规矩,在分析原理之前,我们先来看一下如何用。最好的文档还是manual和示例程序。
- ”表与结构体映射”宏sql_create_#
如果我们有这样的表
CREATE TABLE stock (
item CHAR(30) NOT NULL,
num BIGINT NOT NULL,
weight DOUBLE NOT NULL,
price DECIMAL(6,2) NOT NULL,
sdate DATE NOT NULL,
description MEDIUMTEXT NULL)
为了使用SSQLS,我们需要对此表“类型化”,如何做?使用作者提供的sql_create_#宏。
sql_create_6(
stock, 1, 6,
mysqlpp::sql_char, item,
mysqlpp::sql_bigint, num,
mysqlpp::sql_double, weight,
mysqlpp::sql_decimal, price,
mysqlpp::sql_date, sdate,
mysqlpp::Null<mysqlpp::sql_mediumtext>, description)
当然,这里需要提供一个除了“mysql++.h”之外的另外一个头文件ssqls.h才能够用这个宏。他具体是怎么实现的我们先不管,我们主要关注他怎么用。
sql_create_#(NAME, COMPCOUNT, SETCOUNT, TYPE1, ITEM1, ... TYPE#, ITEM#)
首先这个#表示这个表中有多少字段。NAME你就把它当做是表名(当然后面会提到这么一种情况:我有两张表结构一模一样的表格,主要用来互换,这里需要sql_create_#两次?显然大牛老外没有这么蠢,他提供了一些方法来让一个结构体为多张同构不同名表服务的机制)。COMPCOUNT是什么?这个参数的意思就是从第一个字段开始之后的COMPCOUNT个字段共同参与了比较。这个机制在有主键的表中特别合适,比如上面的例子中,item自己就形成了“主键”。SETCOUNT是从第一个字段开始之后的SETCOUNT个字段会行程构造器的参数,和类型内的set方法的参数(由sql_create_#创建出来的类型一定会有四个构造函数,分别是无参数版本,仅包含主键版本——即COMPCOUNT所指定的数目,仅有const mysqlpp:: Row&的版本,以及包含有SETCOUNT所指定的数目的参数的构造函数。该类型也会有3个set方法,分别是以单参数const mysqlpp::Row,以主键类型为参数,以SETCOUNT所指定的数目和顺序为参数的版本)。例如
sql_create_6(
some_table, 1, 3,
mysqlpp::sql_char, item,
mysqlpp::sql_bigint, num,
mysqlpp::sql_double, weight,
mysqlpp::sql_decimal, price,
mysqlpp::sql_date, sdate,
mysqlpp::Null<mysqlpp::sql_mediumtext>, description)
some_table foo;
some_table foo(row); //这个row是mysqlpp:: Row类型
some_table foo(“Hotdog”);
some_table foo("Hotdog", 52, 20);
foo.set(row);
foo.set("hello");
foo.set("hello", 500, 300);
在manual中还提到过由于C++的语法不可以将COMPCOUNT和SETCOUNT写为同一个数字,work around是为SETCOUNT设置0,即提示MYSQL++不要生成对应的构造器,具体原理下面讲。
- 获取数据
mysqlpp::Query query = con.query("select item,description from stock");
vector<stock> res;
query.storein(res);
vector<stock>::iterator it = res.begin();
cout << it->description;
或者,如果我们知道获取到的数据只有一条记录,那么可以不用存储在vector里面。
mysqlpp::Query query = con.query("select item,description from stock limit 1 "); mysqlpp::StoreQueryResult res = query.store(); stock row = res[0];
用起来还是很方便的,和Hibernate很像。我们看到,上面的select语句只抽取item和description两个字段,然后通过mysqlpp:: Query的与SSQLS相关的方法吧结果防止到vector<stock>这个容器中,随后就像普通类型一样用。
有一点需要注意的是,这里只用到了两个字段,所以我们大可在sql_create_#中只用声明两个字段,即使stock表有6个字段之多(见sql_create_#的相关说明)。MYSQL++非常智能,他会根据SELECT出来的字段填充同名类型字段,如果没有这个同名类型字段,MYSQL++则会直接忽略它。
值得一提的是,作者在manual中解释了为什么要这么设计,貌似是因为大家把MYSQL都当做是分布式数据库来用,所以对于schema的改动可能会有先后。所以要让MYSQL++尽量高可拓展。
- 增加数据
stock row("Hot Dogs", 100, 1.5, …);
mysqlpp::Query query = con.query( );
query.insert(row).execute( );
或者
stock row("Hot Dogs", 100, 1.5, …);
vector<stock> rows;
rows.push_back(row);
mysqlpp::Query query = con.query( );
query.insert(rows.begin( ), rows.end( )) .execute( );
基本语法还是很直观的,和声明你要插入的表的对应类型的实例,然后调用mysqlpp:: Query中与SSQLS相关的方法接口就可以了。
但是,作者在这里重点突出了一个地方,那就是insert policy。我记得我在介绍mysql:: Query源代码的时候就说过这个东西,他在源代码中是以直接在private域里面做#include的等方式加入的。
那么,这个insert policy在什么地方会用到?
待会我们就会看到,如果某个vector里面有两个元素(分别为row1和row2),那么在Query:: insert(sth.begin(), sth.end() )中,实际上会把一句insert语句拓展成(意会而已)
“insert into XXX(…) values (row1), (row2)”
然后作者提到说,MySQL has a limit on the size of the SQL query it will process.这就暗示我们了一种情况,如果这个vector里面有几百万个对象,展开的SQL语句超过了MYSQL对于query的limit,那么这句语句必然失败。显然,更改MYSQL的这个limit换汤不换药。那么,更好的办法是什么?
我们可以设置某些“门槛”,一旦query的长度(或者涉及到的条数,或者某个对象的大小)超过了这个“门槛”,那么就截断这条query,让他送出去。剩下的继续来生成下一条query语句。
MYSQL++就是采用这个insert policy机制来实现它的。
mysqlpp::Query::MaxPacketInsertPolicy<> insert_policy(1000);
query.insertfrom(stock_vector.begin(), stock_vector.end(), insert_policy);
有哪些insert policy?
Insert Policy |
说明 |
MaxPacketInsertPolicy |
如果当前已经插入的rows的总体的大小查过了某个threshold,那么can_add就返回false |
SizeThresholdInsertPolicy |
如果当前想要插入的row的大小大于预设的threshold,那么can_add就返回false。即放弃那些row的大小超过某个值的数据行。当你的数据内每一行都比较短小的时候(例如没有BLOB数据字段),使用该限制对象,将使你的插入更加高效和合理。 |
RowCountInsertPolicy |
如果当前已经插入的rows的数目超过了某个threshold,那么can_add就返回false |
- 修改数据
// 先获取一条出来
mysqlpp::Query query = con.query("select item,description from stock limit 1 ");
mysqlpp::StoreQueryResult res = query.store();
stock row = res[0];
row.item = “abc”;
query.update(orig_row, row);
query.execute();
- 删除数据
看了一下mysqlpp:: Query的源代码,貌似没有发现有和update类似的delete方法,所以我估计,在MYSQL++中,如果需要删除一些数据,也只能够通过以下方式进行
mysqlpp::Query query = con.query("delete from stock where … ");
query.execute();
- 当表名与结构体名不一致时
记得在讲sql_create_#宏的时候,第一个参数就是该结构体和其所对应的表名(两者一般是一样的)。但是在我所在的公司,由于业务上的需要,通常一张表(以下假设该表名为stock)可能会有两个版本,即第一天用stock1,第二天用stock2。这种情况下,我们该怎么办?显然使用sql_create_#两次来创建两个一模一样的结构体是一种办法。但是效率显然是低下的,即使在数据库中,为了实现这个功能我们确实需要创建两个一模一样的表。但是在程序中,一个同构stock结构体就可以解决这些事情了。
根据默认的情况,SSQLS默认结构体的名字就是你所需要找的表的名字。那么上面的情况怎么处理?
方法一是全局修改表名,使得这个SSQLS结构体能够匹配特定的表。
stock::table(“stock1”);
这里的stock是SSQLS结构体。
方法二是针对不同的实例(instance)都修改对应的表。例如,
stock s1; s1.instance_table("stock1"); stock s2; s1.instance_table("stock2");
这样插入s1这个实例就会插向stock1, 插入s2这个实例就会插向stock2。
- 当把SSQLS结构类型当做基类
我们确实可以把一个SSQLS结构类型当做基类型使用,但是为了确保你所派生出来的类型他还是一个SSQLS类型,你必须要把所有被sql_create_#所隐藏了的构造函数都显式地列出来,这是因为SSQLS需要使用这些构造函数(还记得不,在介绍sql_create_#的时候有说过这种类型一定有4个构造函数),如果我们没有这些构造函数,那么如果将该类型作为SSQLS所使用,就会出现编译错误。同时不要去试图override那些需要被MYSQL++ internal use的方法。
下面是manual上的一个派生例子。
sql_create_2(
Base, 1, 2,
mysqlpp::sql_varchar, a,
mysqlpp::sql_int, b);
class Derived : public Base
{
public:
// default constructor
Derived() : Base() { }
// for-comparison constructor
Derived(const mysqlpp::sql_varchar& _a) : Base(_a) { }
// full creation constructor
Derived(const mysqlpp::sql_varchar& _a, const mysqlpp::sql_int& _b) : Base(_a, _b) { }
// population constructor
Derived(const mysqlpp::Row& row) : Base(row) { }
// functionality added to the SSQLS through inheritance
bool do_something_interesting(int data);
};
原创作品,转载请注明出处www.cnblogs.com/aicro。
【原创】13. MYSQL++之SSQLS(基本用法篇)的更多相关文章
- 【原创】MYSQL++源码剖析——前言与目录
终于完成了! 从第一次想写到现在真的写好大概花了我3个月时间.原来一直读人家的系列文章,总感慨作者的用心良苦和无私奉献,自己在心里总是会觉得有那么些冲动也来写一个. 最开始的麻烦是犹豫该选哪个主题.其 ...
- 【原创】14. MYSQL++之SSQLS(原理解析)
从之前所介绍的SSQLS的介绍中我们可以感受到,SSQLS的精髓应该在sql_create_#这个宏,他所创建出来的这个结构体将会是突破的关键,所以我将会从以下顺序入手. 1. sql_create_ ...
- Mysql高手系列 - 第14篇:详解事务
这是Mysql系列第14篇. 环境:mysql5.7.25,cmd命令中进行演示. 开发过程中,会经常用到数据库事务,所以本章非常重要. 本篇内容 什么是事务,它有什么用? 事务的几个特性 事务常见操 ...
- Mysql高手系列 - 第18篇:mysql流程控制语句详解(高手进阶)
Mysql系列的目标是:通过这个系列从入门到全面掌握一个高级开发所需要的全部技能. 这是Mysql系列第18篇. 环境:mysql5.7.25,cmd命令中进行演示. 代码中被[]包含的表示可选,|符 ...
- Docker基础用法篇
Docker基础用法篇 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.安装docker 1>.依赖的基础环境 64 bits CPU Linux Kerner 3.10+ ...
- mysql那些事之索引篇
mysql那些事之索引篇 上一篇博客已经简单从广的方面介绍了一下mysql整体架构以及物理结构的内容. 本篇博客的内容是mysql的索引,索引无论是在面试还是我们日常工作中都是非常的重要一环. 索引是 ...
- Mysql高手系列 - 第7篇:玩转select条件查询,避免踩坑
这是Mysql系列第7篇. 环境:mysql5.7.25,cmd命令中进行演示. 电商中:我们想查看某个用户所有的订单,或者想查看某个用户在某个时间段内所有的订单,此时我们需要对订单表数据进行筛选,按 ...
- Mysql高手系列 - 第9篇:详解分组查询,mysql分组有大坑!
这是Mysql系列第9篇. 环境:mysql5.7.25,cmd命令中进行演示. 本篇内容 分组查询语法 聚合函数 单字段分组 多字段分组 分组前筛选数据 分组后筛选数据 where和having的区 ...
- Mysql高手系列 - 第10篇:常用的几十个函数详解,收藏慢慢看
这是Mysql系列第10篇. 环境:mysql5.7.25,cmd命令中进行演示. MySQL 数值型函数 函数名称 作 用 abs 求绝对值 sqrt 求二次方根 mod 求余数 ceil 和 ce ...
随机推荐
- [置顶]
Kubernetes1.7新特性:新增自动伸缩条件和参数
一.核心概念 Horizontal Pod Autoscaling,简称HPA,是Kubernetes中实现POD水平自动伸缩的功能.云计算具有水平弹性的特性,这个是云计算区别于传统IT技术架构的主要 ...
- ng 变量和常量服务
<!DOCTYPE html> <html ng-app="myApp"> <head lang="en"> <met ...
- bzoj 2131 免费的馅饼
Written with StackEdit. Description Input 第一行是用空格隔开的二个正整数,分别给出了舞台的宽度\(W\)(\(1\)到\(10^8\)之间)和馅饼的个数\(n ...
- Fillder手机抓包的使用
1.Fillder下载地址: http://www.onlinedown.net/soft/73207.htm 2.网络设置 手机和电脑需链接网络相同 3.fillder设置 3.1打开fillder ...
- 【转】C# Socket编程(3)编码和解码
[转自:https://www.cnblogs.com/IPrograming/archive/2012/10/13/CSharp_Socket_3.html] 在网络通信中,很多情况下:比如说QQ聊 ...
- LG2120 [ZJOI2007]仓库建设
题意 L公司有N个工厂,由高到底分布在一座山上. 工厂1在山顶,工厂N在山脚. 由于这座山处于高原内陆地区(干燥少雨),L公司一般把产品直接堆放在露天,以节省费用. 突然有一天,L公司的总裁L先生接到 ...
- linux 使用asciinema 进行命令行屏幕录制共享
1. 安装 yum install asciinema 2. 使用 录制 asciinema rec filename(可选,方便进行后期的回放play) 同时生成一个url 地址方便传递 https ...
- 【转】Python自动化测试 (一) Eclipse+Pydev 搭建开发环境
原文网址:http://www.cnblogs.com/TankXiao/archive/2013/05/29/3033640.html C#之所以容易让人感兴趣,是因为安装完Visual Studi ...
- sublime文件对比插件--sublimerge
网上很多文件对比的基本都要收费,所以还是干脆看看sublime有没插件算了. 结果还是有一个:sublimerge 1 先安装该插件: 2 然后在sublime下都打开要对比的两个文件: 3 然后在其 ...
- aspupload ,在winows server 2008 下无法使用
aspupload ,在winows server 2008 下无法使用.求助解决办法 2014-01-12 13:31 goolean | 浏览 775 次 操作系统 aspupload64位,安装 ...