PHP 源码碎片 - 宏的回调
#include <stdio.h> #define D1(a) printf("a:%s\n",a) #define D2(_,y) _(y) #define D3(b) D2(D1,b) int main(int argc, const char * argv[]) { D3("2"); return 0; }
EOS 数据库开发实战
上次的文章详细讲解了 EOS 数据库的架构,本文将以官方示例为基础,详解 EOS 数据库的开发实战。
在智能合约里与 EOS 数据库交互,首先要定义存储的数据:
const类型的成员函数primary_key(),返回值必须为uint64_t类型,返回值即为主键。存储数据定义好之后,就可以与数据库交互了:
multi_index,建立数据表。emplace方法在表中添加数据;使用erace方法删除数据。modify方法修改数据。get、find方法和其他迭代器操作查询数据。我们参考 EOS 的官方示例,建立一个“汽车修理店”智能合约所需要的数据库。数据库服务的对象是维修技师和车主。每次车辆维修保养后,维修技师都可以添加本次维修服务的信息,可以更科学地管理每位客户的车辆维修保养服务。而且维修技师和车主都可以更新车辆目前的里程,以便技师确定车辆是否应该保养。我们需要一个数据表:维修数据表(service Table)。
维修数据表中,每一条数据对象就是一次车辆维修保养的数据,包含以下成员:
我们还想方便的查询每个顾客的维修记录,所以需要一个以顾客账户名为键(Key)的索引。
这样我们就得到了 service_rec 结构体:
struct service_rec {
uint64_t pkey; // 主键
account_name customer; // 顾客账户
uint32_t service_date; // 维修日期
uint32_t odometer; // 车辆里程
//设置主键
auto primary_key()const { return pkey; }
//设置索引
account_name get_customer()const { return customer; }
//SERIALIZE 宏可以帮助提高编译速度
EOSLIB_SERIALIZE( service_rec, (pkey)(customer)(service_date)(odometer) )
};
下面就可以建立数据表了,首先,multi_index是个模板类:(对 C++ 模板不熟悉的可以百度一下)
eosio::multi_index <uint64_t TableName, typename T, typename... Indices>
我们需要填入以下multi_index的模板参数:
TableName为数据表名称,12字符以内,只能使用小写字母,数字1-5,小数点“.”。T为数据对象类型,这里就是我们定义的service_rec结构体。Indices为索引列表,最多十六个。为了降低开发难度,官方推荐使用const_mem_fun模板,大家可以模仿官方的做法:按照需求,我们这样设置multi_index的模板参数:
using service_table_type = multi_index<service/*<-数据表名称*/, service_rec,/*<-数据对象类型*/
/*设置索引->*/indexed_by< N(bycustomer), const_mem_fun<service_rec, account_name, &service_rec::get_customer> >
>;
这里并没有实例化multi_index,只是将填入相应模板参数的multi_index设置了一个别名:service_table_type。依然,对这里的做法不熟悉的可以看一下 C++ 模板类以及 C++ 的 using 关键字。
下面我们实例化multi_index,构造函数需要两个参数:
multi_index( uint64_t code, uint64_t scope )
其中,code为数据表的拥有者,scope为数据表的细分名称。这里有两种理解,一种理解是不同的 scope 就是不同的数据表,也就是说,在同一个账户下,存在着TableName相同的多个数据表,他们的scope互不相同;另一种理解:scope表示了同一个数据表的不同部分,互相独立读写。这两种理解的结果是一样的,就是唯一确定一个数据表需要三个参数:TableName,code,scope。
实例化multi_index:
service_table_type service_table( current_receiver(), mechanic );
上面的code = current_receiver(),表示当前的智能合约,即“汽车维修店合约”。如果这里的code为其他合约,那么说明这个multi_index指向了其他账户名下的数据表,在本合约中就只能进行读取操作了。scope = mechanic表明实例化的这个multi_index指向了细分名称为mechanic(以维修技师账户命名)的数据表。
我们所建立的数据表结构如下图所示。
一般数据库的基本操作是增、删、改、查,EOS 数据库当然也具有这些功能。
新增数据需要用到multi_index的emplace方法:
const_iterator emplace( unit64_t payer, Lambda&& constructor )
其中的payer参数位储存空间支付账户,也就是由谁来提供新加入的这个数据对象的存储空间,这里填入维修技师mechanic账户。constructor是个 Lambda 表达式,也叫匿名函数,是向emplace方法传入了一个构造函数,用来构造这个新的数据对象。
service_table.emplace(mechanic,/*<-储存空间支付账户*/ [&]( auto& s_rec )/*<-匿名函数*/ {
s_rec.pkey = service_table.available_primary_key(); /*<-系统生成可用主键*/ //匿名函数体
s_rec.customer = eosio::chain::string_to_name(customer_name); //匿名函数体
s_rec.service_date = service_date; //匿名函数体
s_rec.odometer = odometer; //匿名函数体
});
其中的customer_name、service_date、odometer要在实际开发时使用有意义的变量。
由于service_table数据表的主键是没有意义的,所以我们需要使用bycustomer索引来根据顾客账户名(customer)查询数据。
auto customer_index = service_table.template get_index<N(bycustomer)>();
这样我们就得到了bycustomer索引,我们可以使用索引的find方法来按照索引查找特定customer的数据对象。
//建立要查找的账户,注意这里的customer_name要使用有意义的字符串
account_name customer_acct = eosio::chain::string_to_name(customer_name);
//使用`find`方法查找数据,使cust_itr(迭代器)指向所需数据
auto cust_itr = customer_index.find(customer_acct);
如果没有查找到,cust_itr(迭代器)就是service_table.end(),也就是搜索到最后也没有找到对应的数据。如果查找成功,cust_itr(迭代器)就会指向所需的数据对象。
之后,可以使用下面的代码可以遍历数据表中所有我们所需的条目。(因为顾客账户名不是唯一的,用find方法会找到符合条件的第一条数据)
while (cust_itr != service_table.end() /*<-判断迭代器位置*/&& cust_itr->customer == customer_acct/*<-判断数据是否符合*/) {
// 业务逻辑,对数据进行处理
cust_itr++;//迭代器自增,指向下一条数据
}
在迭代器指向数据后,可以对数据进行修改,使用modify方法:
service_table.modify(cust_itr,/*<-迭代器*/, mechanic, /*<-储存空间支付账户*/ [&]( auto& s_rec )/*<-匿名函数*/ {
s_rec.customer = new_customer; //匿名函数体
s_rec.service_date = new_service_date; //匿名函数体
s_rec.odometer = new_odometer; //匿名函数体
});
匿名函数中的new_customer、new_service_date、new_odometer请使用有意义的变量。也可以只修改其中部分变量。
在迭代器指向数据后,可以对数据进行删除,使用erase方法:
service_table.erase( cust_itr/*<-迭代器*/ );
至此,带领大家了初步解了 EOS 数据库开发的思路与方法,EOS 数据库还有很多 API 可以供智能合约使用,大家可以查阅官方 Wiki:
https://github.com/EOSIO/eos/wiki/Persistence-API
微信关注我们
转载内容版权归作者及来源网站所有!
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
近一个月的开发和优化,本站点的第一个app全新上线。该app采用极致压缩,本体才4.36MB。系统里面做了大量数据访问、缓存优化。方便用户在手机上查看文章。后续会推出HarmonyOS的适配版本。
为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。
Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。
Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。