异常处理

try
{
*pwnd->m_spDb->m_spSession << "select f_id from t_user where f_name=? and f_pwd=?",
use(user), use(pwd), into(fid), now;
}
catch (const Poco::Exception& ex)
{
g_logger->error("cmdType_frontend_login: get user info failed. {}", ex.displayText());
}

事务处理

try
{
m_spDb->m_spSession->begin();
*m_spDb->m_spSession << strSql, now;
for (auto&it : vIdxCol)
{
*m_spDb->m_spSession << "CREATE INDEX idx_" << strInstId<< it << " ON " << tableName << " (" << it << ")", now;
*m_spDb->m_spSession << "CREATE INDEX idx_" << strInstId<< it<<"_alarm " << " ON " << tableName + "_alarm" << " (" << it << ")", now;
}
m_spDb->m_spSession->commit();
}
catch (const Poco::Exception& ex)
{
m_spDb->m_spSession->rollback();
g_logger->error("checkDbDataTable: create data table failed. {}", ex.displayText());
}

简单的选择

从数据库中取数据的操作与之类似。into关键字将数据库返回的值与C++对象匹配起来。并且支持指定默认值以防数据库返回null值。
此处需要注意的是,指定默认值的into,其定义为:into(T& t, const Position& pos, const T& def),使用的是模样类。在有些编译器下,不能隐式转换数据类型,所以需要显示的让第一个参数和第三个参数的数据类型保持一致。

Poco::Data::Session ses(MySQL::Connector::KEY, _dbConnString);
int count = 0;
ses << "SELECT COUNT(*) FROM SMART_U_STREET",into(count),now;
std::cout<<"street has "<<count<<std::endl;

std::string name;
session << "SELECT fN FROM tbA",into(name),now;
session << "SELECT fN FROM tbA",into(name,0,std::string("default")),now;

std::string name;
std::string match="wandoer";
session << "SELECT fN FROM tbA WHERE fN=?",into(name),use(match),now;

选择循环处理

struct MapObj
{
int64_t fk_user_id;
int64_t f_datasId;
int64_t f_datasType;
string f_datas;
};
MapObj mapObj;

Statement select(*m_spDbSrc->m_spSession);
select << "select fk_user_id,f_datasId,f_datasType,f_datas from t_ui_map",
into(mapObj.fk_user_id),into(mapObj.f_datasId),into(mapObj.f_datasType),into(mapObj.f_datas), range(0, 1);

try
{
m_spDbDest->m_spSession->begin();

while (!select.done())
{
select.execute();
*m_spDbDest->m_spSession << "insert into t_ui_map (fk_user_id,f_datasId,f_datasType,f_datas) values (?,?,?,?);",
useRef(mapObj.fk_user_id), useRef(mapObj.f_datasId), useRef(mapObj.f_datasType), useRef(mapObj.f_datas), now;
}
m_spDbDest->m_spSession->commit();
}
catch (const Poco::Exception& ex)
{
m_spDbDest->m_spSession->rollback();
g_logger->error("checkDbDataTable: create data table failed. {}", ex.displayText());
}

使用容器

Json::Value jsonObj;
typedef Poco::Tuple<int64_t, std::string> Person;
typedef std::vector<Person> People;
People people;

*pwnd->m_spDb->m_spSession << "select f_ui_id,f_param from t_user where f_param is not null",into(people), now;
for (auto&it: people)
{
jsonObj = readJsonFromString(it.get<1>());
jsonObj["userid"] = it.get<0>();
string ss = jsonObj.toStyledString();
jsonRet["datas"].append(jsonObj);
}

参数化

std::string name="wandoer"; 
session << "INSERT INTO tbA VALUES(?)",use(name), now;

通用的语法

创建索引

CREATE INDEX index_name ON table_name (column_name);

创建唯一索引

CREATE UNIQUE INDEX index_name ON table_name (column_name)

降序索引

CREATE INDEX PersonIndex ON Person (LastName DESC)

索引多个列

CREATE INDEX PersonIndex ON Person (LastName, FirstName)

索引是否存在

sqlite

select * from sqlite_master

SELECT count(*) FROM sqlite_master WHERE name = 'idx_number_data'

https://www.digitalocean.com/community/articles/sqlite-vs-mysql-vs-postgresql-a-comparison-of-relational-database-management-systems

SQLite

SQLite的优点

基于文件
整个数据库完全由磁盘上的一个文件构成,这使得它的可移植性非常好。

标准化
尽管它看起来像一个“简化版”的数据库实现,但是SQLite确实支持SQL。它省略了一些功能(RIGHT OUTER JOIN和FOR EACH STATEMENT),但同时也增加了一些额外的功能。

非常适合开发甚至是测试
在大多数应用程序的开发阶段,大部分开发人员可能都非常需要一个能够支持并发扩展的解决方案。SQLite 包含丰富的功能,所能提供的特性超乎开发所需,使用起来也非常简洁——只需要一个文件和一个C链接库。

SQLite的缺点

没有用户管理
高级数据库都支持用户系统,例如管理连接对数据库和表的访问权限。鉴于SQLite的目的和性质(没有多客户端并发的高层设计),它并不包含这些功能。

缺少通过优化获得额外性能的空间
还是由于设计方面的原因,无法通过优化SQLite获得大量的额外性能。这个类库非常容易调整、也非常容易使用。它并不复杂,所以从技术上无法让它变得更快,因为它已经很快了。

何时应该使用SQLite

嵌入式应用程序
所有需要可移植性、不需要扩展的应用程序,例如单用户的本地应用、移动应用或者游戏。

替代磁盘访问
在很多情况下,需要直接读写磁盘文件的应用程序可以切换到SQLite从而受益于SQLite提供的额外功能以及使用结构化查询语言(SQL)所带来的简便性。

测试
对大部分应用程序而言没必要使用额外的进程测试业务逻辑(例如应用程序的主要目标:功能)。

何时不应该使用SQLite

多用户应用程序
如果有多个客户端需要访问并使用同一个数据库,那么最好使用功能完整的关系型数据库(例如MySQL),而不是选择SQLite。

需要高写入量的应用程序
写操作是SQLite的一个局限。该DBMS在同一时刻仅允许一个写操作,因而也限制了其吞吐量。

MySQL

MySQL的优点

易用
很容易安装。第三方工具,包括可视化工具,让用户能够很容易入门。

功能丰富
MySQL支持关系型数据库应该有的大部分功能——或者直接支持、或者间接支持。

安全
支持很多安全特性,有些非常高级,并且是内置于MySQL中。

可扩展也非常强大
MySQL能够处理大量数据,并且在需要的时候可以规模化使用。

快速
放弃某些标准让MySQL能够非常高效、简捷地工作,因而速度更快。

MySQL的缺点

已知限制
MySQL从一开始就没有打算做所有事情,因而它在功能方面有一定的局限性,并不能满足一些先进应用程序的要求。

可靠性问题
MySQL对某些功能(例如引用、事务、审计等)的实现方式使得它与其他的关系型数据库相比缺少了一些可靠性。

开发停滞
尽管MySQL依然是一款开源产品,但是自从它被收购之后人们就对其开发进展有很多抱怨。需要注意的是有一些基于MySQL的、完整集成的数据库在标准的MySQL之上附加了其他价值,例如MariaDB。

何时应该使用MySQL

分布式操作
如果SQLite不能满足你的需求,那么将MySQL引入到开发栈中,就像任何其他独立的数据库服务器一样,它能够给你带来大量的操作自由度以及一些先进的功能。

高安全性
MySQL的安全机制通过一种简单的方式为数据的访问和使用提供了可靠的保护。

网站和Web应用
尽管有一些约束,但是绝大部分网站和Web应用都可以简单地运行在MySQL上。相关的灵活可扩展的工具非常易于使用和管理——事实证明这些工具在长期运行时非常有用。

定制解决方案
MySQL有丰富的配置项和运行模式,如果你需要一个高度量身定制的解决方案,那么MySQL能够非常容易地尾随并执行你的规则。

何时不应该使用MySQL

SQL遵从性
因为MySQL并没有打算实现完整的SQL标准,所以它并不完全符合SQL。如果你可能需要与这样的关系型数据库集成,那么从MySQL切换过去可能并不容易。

并发性
尽管MySQL和一些其他的存储引擎能够非常好地执行读操作,但是并发读写可能会有问题。

缺少功能
MySQL缺少某些功能,例如全文本搜索。

PostgreSQL

PostgreSQL的优点

开源且遵从SQL标准
PostgreSQL是一款开源的、免费的、功能非常强大的关系型数据库。

强大的社区
由一个忠实的、经验丰富的社区支持,用户可以通过知识库和Q&A网站获得全天候的免费服务。

强有力的第三方支持
除了非常先进的特性之外,PostgreSQL还有很多优秀的、开源的第三方工具可以辅助系统的设计、管理和使用。

可扩展
可以通过存储过程扩展PostgreSQL的功能。

面向对象
PostgreSQL不仅是一个关系型数据库,它还是一个面向对象的数据库——支持嵌套等功能。

PostgreSQL的缺点

性能:
对于简单繁重的读取操作,使用PostgreSQL可能有点小题大做,同时性能也比MySQL这样的同类产品要差。

流行程度
尽管有大量的部署,但是鉴于该数据库的性质,它的受欢迎程序并不高。

托管
由于上面提到的几点,很难找到提供托管PostgreSQL实例的主机或者服务提供商。

何时应该使用PostgreSQL

数据完整性
当绝对需要可靠性和数据完整性的时候,PostgreSQL是更好的选择。

复杂的定制程序
如果需要数据库执行定制程序,那么可扩展的PostgreSQL是更好的选择。

集成:
如果将来可能需要将整个数据库迁移到其他合适的解决方案上(例如Oracle),那么PostgreSQL可能兼容性最好也更容易切换。

复杂的设计
与其他开源且免费的数据库相比,对于复杂的数据库设计PostgreSQL在功能方面最全面,潜力最大,不需要你放弃其他有价值的资产。

何时不应该使用PostgreSQL

速度
如果你只需要快速读取操作,那么PostgreSQL并不合适。

简单
除非你需要绝对的数据完整性,ACID遵从性或者设计复杂,否则PostgreSQL对于简单的场景而言有点多余。

复制
对于缺少数据库和系统管理经验的人而言使用MySQL实现复制要更简单,除非你愿意花费时间、精力和资源。

基于技术模型进行设计-RBAC(Role-Based Access Control)模型

如下图即是 RBAC 模型中最基本的模型:用户与角色可为多对一或多对多的关系,当一个用户的角色为多对多时,当前用户的权限是多个角色的并集。
此时只需要为角色赋予权限,能够大大减轻管理负担,同时将用户与权限解耦,提供更大的灵活性。

20190823_105347.png
  1. 页面权限优先于操作和数据权限
    必须配置了页面模块权限后,才能配置当前页面模块下具体的操作权限,以及页面模块的数据展示权限。

  2. 查看权限优先于增删改权限

正常情况下,一定要先能查看某个模块或操作,其它的增删改操作才有意义。因此在设计时,应在获取查看权限前限制其它权限的配置,或者配置其它权限时默认赋予查看权限。

节点包括:

用户;
用户组;
角色;
角色组;
权限(页面、操作、数据);
权限组(页面、操作、数据)。

关系包括:

是/否关系;
继承关系;
限制关系(互斥、范围限制、边界限制、字段限制……);

管理的目标是什么:在计划期内完成项目。在合理范围内保证质量(时间短,质量一定低;时间长,质量不一定高)。

项目立项时的输出:关键的功能需求,关键的开发时间点,达成共识

项目管理:立项,项目计划,监控,资源管理
软件工程:需求分析,系统设计,软件实现,系统测试,用户测试,试运行,系统验收,系统上线,数据迁移,产品维护

  1. 立项:市场需求分析(或者合同),项目立项申请表,项目风险分析清单

  2. 需求分析:软件需求报告或设计方案,需求规格说明书

  3. 总体设计:概要设计说明书或功能模块描述

  4. 详细设计:详细设计说明书,包括软件接口说明,单元测试计划

  5. 软件实现:软件功能说明,源代码,注释

  6. 产品测试:测试报告

  7. 产品发布:产品说明书,使用手册

  8. 产品维护:问题反馈记录

  9. 项目总结:提交客户方的项目总结禾公司项目汇报

阶段 输出 职责及描述 负责人 备注
需求阶段 项目立项报告 明确甲乙双方责任及义务,需双方签字确认 项目经理 大部分业务建模和需求,少部分分析设计
需求阶段 业务需求说明书 需求定义,阐述业务范围及内容,开发组负责制定最优技术设计方案 项目经理/需求分析工程师 大部分业务建模和需求,少部分分析设计
需求阶段 项目开发计划 制定项目开发计划,方便所有项目干系人及时了解进度 项目经理 大部分业务建模和需求,少部分分析设计
需求阶段 项目风险分析清单 制定相应措施 全体项目干系人 大部分业务建模和需求,少部分分析设计
设计阶段 总体设计书,详细设计说明书 讨论技术架构,可能的技术难点,梳理业务流程 项目经理/架构师 大部分分析设计,部分实施及测试,开始考虑部署
设计阶段 数据库设计图 项目所需的结构图,流程图 架构师/高级工程师 大部分分析设计,部分实施及测试,开始考虑部署
设计阶段 任务分配文档 明确每个组员的开发任务及职责 项目经理 大部分分析设计,部分实施及测试,开始考虑部署
设计阶段 问题说明报告 让用户,领导及组员及时了解和发现问题 项目经理 大部分分析设计,部分实施及测试,开始考虑部署
设计阶段 业务便更文档 记录业务变更情况 需求分析工程师 大部分分析设计,部分实施及测试,开始考虑部署
实施阶段 软件功能说明 记录开发过程中实现的功能 开发工程师 最终开发成果和说明
实施阶段 源代码 源代码及数据库备份文件 开发工程师 最终开发成果和说明
实施阶段 源代码说明 功能模块的说明 开发工程师 最终开发成果和说明
测试阶段 项目测试方案及报告 记录测试方法,验证的功能 测试工程师 反复测试直到系统稳定
测试阶段 用户使用手册 使用说明书 测试工程师
上线及运行 系统使用报告 部署后的操作记录 项目经理 部署及维护
上线及运行 用户培训报告 用户培训文档 项目经理 部署及维护
上线及运行 项目验收报告 甲乙双方项目验收报告 项目经理 部署及维护
上线及运行 项目总结性报告 总结经验及不足 项目经理 部署及维护

UPDATE table_name
SET column1 = value1, column2 = value2...., columnN = valueN
WHERE [condition];


UPDATE table
SET column_1 = new_value_1,
column_2 = new_value_2
WHERE
search_condition
ORDER column_or_expression
LIMIT row_count OFFSET offset;

同步调用:对于要立即等待返回处理结果的场景,RPC是首选。
RPC相比与MQ,不仅是实现了消息层面的通信,还直接实现了作为服务端的业务逻辑,客户端在调用多个RPC服务的时候,负载均衡逻辑必须在客户端实现,即,没有解耦的功能!

MQ 适用场景

  • 业务解耦
  • 消息的发送和处理是异步的
  • 广播
  • 最终一致性
  • 错峰流控等

RPC 适用场景

  • 客户端调用哪个服务器比较明确
  • 调用需要立即得到返回结果
  • 架构简单

一次RPC调用的流程:
20190813_184052.png

使用 DLL 方式实现

poco 1.9 动态编译 dll md