EOS 数据库与持久化 API —— 实战

转载自:http://blog.51cto.com/13625500/2119083

上次的文章详细讲解了 EOS 数据库的架构,本文将以官方示例为基础,详解 EOS 数据库的开发实战。

基本步骤

在智能合约里与 EOS 数据库交互,首先要定义存储的数据:

  • 定义对象:具体就是定义一个 C++ 类或者 C++ 结构体,数据表就由一个个对象组成。

  • 定义主键:在刚才的类/结构体中,定义一个const类型的成员函数primary_key(),返回值必须为uint64_t类型,返回值即为主键。

  • 定义索引:EOS 数据表不光可以按照主键搜索数据,还可以定义多达 16 种索引。而且索引键(Key)不止支持64位无符号整数,还支持 128、256位整数以及双精度、四精度浮点数。

  • 为每个索引定义键提取器(key extractor)。

存储数据定义好之后,就可以与数据库交互了:

  • 建立数据表:实例化 multi_index,建立数据表。

  • 增删数据:使用emplace方法在表中添加数据;使用erace方法删除数据。

  • 修改数据:使用modify方法修改数据。

  • 查询数据:使用getfind方法和其他迭代器操作查询数据。

需求分析

我们参考 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表示了同一个数据表的不同部分,互相独立读写。这两种理解的结果是一样的,就是唯一确定一个数据表需要三个参数:TableNamecodescope

实例化multi_index

service_table_type service_table( current_receiver(), mechanic );

上面的code = current_receiver(),表示当前的智能合约,即“汽车维修店合约”。如果这里的code为其他合约,那么说明这个multi_index指向了其他账户名下的数据表,在本合约中就只能进行读取操作了。scope = mechanic表明实例化的这个multi_index指向了细分名称为mechanic(以维修技师账户命名)的数据表。

我们所建立的数据表结构如下图所示。

å¾1.png

操作数据

一般数据库的基本操作是增、删、改、查,EOS 数据库当然也具有这些功能。

新增数据

新增数据需要用到multi_indexemplace方法:

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_nameservice_dateodometer要在实际开发时使用有意义的变量。

查询数据

由于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_customernew_service_datenew_odometer请使用有意义的变量。也可以只修改其中部分变量。

删除数据

在迭代器指向数据后,可以对数据进行删除,使用erase方法:

service_table.erase( cust_itr/*<-迭代器*/ );

至此,带领大家了初步解了 EOS 数据库开发的思路与方法,EOS 数据库还有很多 API 可以供智能合约使用,大家可以查阅官方 Wiki: 
https://github.com/EOSIO/eos/wiki/Persistence-API

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
EOS 是由 Block.one 公司开发的一个新的区块链软件系统,它的目标是将一切去中心(decentralize everything)。从 2017 年年中开始,经过一年的代币众筹后,它于 2018 年 6 月 15 通过由数十个区块生产者(block producer,BP,又称超级节点)组成的社区上线了主网,EOS 主网这条主要的区块链开始正式运转。 通过 EOS Tracker 可以查看 EOS 区块链网络(EOS 主网)的情况。 要注意,虽然有一个 EOS 主网,但实际情况要复杂得多,任何人都可以用 EOS 提供的 EOSIO 开源软件建立自己的一条链,且 EOS 鼓励开发者这么做。接下来,我们分几个主题介绍 EOS 这个基础公链和它的应用开发。EOS 这个基础公链可说是为应用而生的。EOS VS 以太坊了解 EOS 的方式之一是拿它与以太坊、比特币进行比较。 从开发目标上来讲,比特币、以太坊、EOS 是渐进的,分别是区块链 1.0、区块链 2.0、区块链 3.0,重心分别是货币、合约、应用。以太坊在实际应用中是以通证为主的。以太坊、EOS 均是借鉴与延续之前的思路重新开发,以太坊是比特币的改进,EOS 是以太坊的改进。 这里先用比喻的方式来对比比特币、以太坊、EOS,见下图。 比特币的设计思路类似于黄金。在数字世界中,按工作量证明共识机制,挖矿节点进行加密计算,获得比特币形式的挖矿奖励。挖矿节点也可以获得交易费收益,不过,虽然在比特币网络中的资产价值高,但交易并不频繁,交易费收益目前在矿工收益中的占比并不高。 以太坊的设计思路类似于高速公路。在这条收费高速公路上,车辆行驶需要付费。它早期募集资金,建设“高速公路”,早期投资者享有“高速公路”的主要权益。之后,一起建设与维护“高速公路”的挖矿节点也可以获得挖矿奖励与交易费收益。在以太坊网络中,由于各类项目已经基于它生成了大量的通证,以太坊网络的交易量相对较多,挖矿节点获得的交易费收益占比高于比特币。 EOS 的设计思路则类似于房地产开发。Block.one 公司在将土地售卖出去之后,逻辑上它用获得的资金进行基础的开发,此后每年再以类似填海造田的方式增加 5% 的土地出来。 EOS 的繁荣主要取决于,已经竞购得到大量土地的开发商是不是开发和经营好自己的地块?EOS 网络要依靠超级节点(即区块生产者)来各自建设、共同运营,按现在的设计,这些节点共同获得每年 1% 新增发的 EOS 作为回报。 与以太坊不同,EOS 网络的设计是不再收取网络交易费,持有 EOS 通证则拥有对应的网络使用权利。但是,如果一个应用的开发者不持有足够的 EOS 通证,可能就要从市场中购买和付费租用,以获得使用主网的权利。类比来看,这种设计类似于购买或租用办公楼。 当然,以上用比喻的方式讨论只是为了便于理解。EOS 实际的情况是:Block.one 公司募集资金开发一个名为 EOSIO 的开源软件。EOS 社区用这个软件来运行 EOS 主网,且从逻辑上来讲,这个主网并非由 Block.one 公司运行,而是由社区运行的。另外,其他人也用 EOSIO 这个开源软件建立替代网(altnet)。 替代网(altnet)是一个模仿替代币(altcoin)而创造出来的新词。在社区运行的 EOS 主网(mainnet)之外,EOS 鼓励其他人用 EOSIO 开源软件架设新的区块链网络,这些区块链网络是类似于替代币的替代网。比特币的替代币是与比特币的价值无关的,类似地,替代网也与 EOS 主网无关。EOS 是对以太坊的改进,各个用 EOSIO 开源软件运行起来的区块链网络,可以做几乎所有以太坊能做的事,如编写智能合约、发行通证。为什么 EOS 有超级节点竞选EOS 所采用的共识机制是 DPOS(委托权益证明),即一些节点在获得足够多的投票支持后,成为见证人(witness)节点或 EOS 中所说的区块生产者(BP,也称超级节点),负责区块链的区块生成。 对于比特币系统,任何人都可以接入网络,以算力竞争记账权利,生成区块。而对于 EOS,只有超级节点才有资格生产区块。这是因为两者所采用的共识机制不同:比特币和以太坊采用的是工作量证明共识机制,而 EOS 采用的是 DPOS(委托权益证明)共识机制。 围绕 POW 与 DPOS 的比较,讨论主要集中在能源消耗、效率、安全等方面。但我们也可以从去中心网络形成的角度来看,为什么 DPOS 是一种可行的选择。 基于区块链的思路开发的软件系统有以下三个关键要求:一是性能。它的去中心网络的整体性能能否支撑大量应用?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值