eos 连接mysql_【许晓笛】EOS 数据库与持久化 API —— 实战

EOS 数据库开发实战

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

基本步骤

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

定义对象

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

定义主键

:在刚才的类/结构体中,定义一个

const

类型的成员函数

primary_key()

,返回值必须为

uint64_t

类型,返回值即为主键。

定义索引

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

为每个索引定义

键提取器(key extractor)

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

建立数据表

:实例化

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++ 模板不熟悉的可以百度一下)

cpp

eosio::multi_index

我们需要填入以下

multi_index

的模板参数:

TableName

为数据表名称,12字符以内,只能使用小写字母,数字1-5,小数点“.”。

T

为数据对象类型,这里就是我们定义的

service_rec

结构体。

Indices

为索引列表,最多十六个。为了降低开发难度,官方推荐使用

const_mem_fun

模板,大家可以模仿官方的做法:

按照需求,我们这样设置

multi_index

的模板参数:

using servicetabletype = multi_index

/设置索引->/indexedby >

;

这里并没有实例化

multi_index

,只是将填入相应模板参数的

multi_index

设置了一个别名:

service_table_type

。依然,对这里的做法不熟悉的可以看一下 C++ 模板类以及 C++ 的 using 关键字。

下面我们实例化

multi_index

,构造函数需要两个参数:

cpp

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

(以维修技师账户命名)的数据表。

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

pic1

d35e4436abbb763fede7962370af7ed8.png

操作数据

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

新增数据

新增数据需要用到

multi_index

emplace

方法:

const_iterator emplace( unit64_t payer, Lambda&& constructor )

其中的

payer

参数位储存空间支付账户,也就是由谁来提供新加入的这个数据对象的存储空间,这里填入维修技师

mechanic

账户。

constructor

是个 Lambda 表达式,也叫匿名函数,是向

emplace

方法传入了一个构造函数,用来构造这个新的数据对象。

service_table.emplace(mechanic,/*

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

)查询数据。

cpp

auto customer_index = service_table.template get_index();

这样我们就得到了

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 (custitr != servicetable.end() /customer == customeracct/

// 业务逻辑,对数据进行处理

cust_itr++;//迭代器自增,指向下一条数据

}

修改数据

在迭代器指向数据后,可以对数据进行修改,使用

modify

方法:

servicetable.modify(custitr,/

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

方法:

cpp

service_table.erase( cust_itr/*

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

https://github.com/EOSIO/eos/wiki/Persistence-API

相关文章和视频推荐

*圆方圆学院汇集大批区块链名师,打造精品的区块链技术课程。 在各大平台都长期有优质免费公开课,欢迎报名收看。

*

公开课地址:

https://ke.qq.com/course/345101

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值