1. 程式人生 > >EOS 數據庫與持久化 API —— 架構

EOS 數據庫與持久化 API —— 架構

EOS 數據庫 EOS持久化

EOS 數據庫結構詳解

在 EOS 中,智能合約執行完畢後,所占用的內存會釋放。程序中的所有變量都會丟失。如果智能合約裏要持久地記錄信息,比如遊戲智能合約要記錄每位用戶遊戲記錄,本次合約執行完畢後數據不能丟失,就需要將數據存儲到 EOS 數據庫中。與數據庫交互的 API 被官方成為 Persistence API,中文可以叫做持久化 API。下圖說明了 EOS 智能合約在執行 Action 時,與數據庫的交互過程。

技術分享圖片

為了方便智能合約與 EOS 數據庫的交互,EOS 仿造了 Boost 庫中的 Multi-Index Containers,開發了 C++ 類:eosio::multi_index(以下簡稱 multi_index

),中文可以叫做多索引列表類。

multi_index 頭文件地址:
https://github.com/EOSIO/eos/blob/master/contracts/eosiolib/multi_index.hpp

在 EOS 見證人硬盤中,為每個賬戶都預留了數據庫空間(大小與代幣持有量有關),每個賬戶名下可以建立多個數據表。智能合約無法直接操作存儲在見證人硬盤中的數據表,需要使用multi_index作為中間工具(或者叫容器),每個multi_index實例都與一個特定賬戶的特定數據表進行交互(取決於實例化時的參數)。EOS智能合約與EOS數據庫的數據交互如下圖所示。

技術分享圖片

數據表

multi_index是一個非常方便的數據庫交互容器,可以存儲任何 C++ 數據類型。每一個multi_index

都相當於傳統數據庫的一個數據表(table),但將傳統數據庫的行與列的形式改為了單純的列。也就是說multi_index是一個線性排列的表,只有一列,每一行都只存儲一個對象。但是一般來說multi_index存儲的對象都是結構體或者類,裏面含有多個成員變量,所以multi_index存儲數據的靈活性也是不亞於傳統數據庫的。

我們使用官方的“汽車維修店”示例,我們建立一個數據表,儲存每個汽車維修店客戶的賬戶名、保養時間、車輛裏程。那麽multi_index數據表儲存的項目中,每個都是如下的結構體:

struct service_rec {
    uint64_t        pkey;           // 主鍵
    account_name    customer;       // 車主用戶名
    uint32_t        service_date;   // 維修保養時間
    uint32_t        odometer;       // 車輛裏程};

在傳統數據庫中,需要建立一個 4 列的數據表,用來儲存每個用戶的這個 4 個數據,而multi_index的每個數據表只有一列,只存儲每個用戶的 service_rec 整個結構體即可。下圖為multi_index數據結構。

技術分享圖片

多索引

首先,每個數據表要有一組主鍵,主鍵必須是無符號 64 位整數類型(64-bit integer),這就是上面的service_rec結構體中第一個變量為uint64_t類型的原因。在數據表中,所有的對象就是按照主鍵升序排列的,小的在前,大的在後。主鍵可以是有意義的,也可以是沒有意義的,讓系統產生一個在這個數據表中沒有被使用的主鍵即可。為了設置主鍵,我們需要在之前的service_rec結構體添加一個叫做primary_key()的成員函數函數的返回值為主鍵。

    auto    primary_key()const { return pkey; }

這樣就將pkey這個變量設置成了主鍵。

multi_index從字面上看就是能使用多個索引的數據表。EOS 中,每個multi_index或者說每個數據表都可以設置最多16個索引。索引相當於使用特定的方式給數據表中的對象重新排序。比如在我們經常使用的 windows 文件管理器中,可以按照文件名排序、按照文件修改時間排序、按照文件大小排序,這就有了3個索引。EOS 數據庫索引更加靈活,可以單獨按照結構體中的某個變量索引,也可以將變量之間的運算結果(函數輸出)進行索引。如果我們想使用車主用戶名進行索引,需要在結構體中添加一個get_customer()成員函數,函數的返回值為索引變量。

account_name    get_customer()const { return customer; }

這樣就將customer這個變量設置成了數據表的一個索引,下圖右側為customer索引。

技術分享圖片

叠代器

multi_index是如何操作數據表中的每個對象的呢?答案是 Iterators(叠代器)。大家可以搜索 “C++ 叠代器”或者設計模式中的“叠代器模式”來了解叠代器的設計思路。在 EOS 數據庫中,我更願意將叠代器比喻為一個“電梯”,在整個數據表中上下穿梭。所有對數據的操作必須通過叠代器完成。典型的數據修改過程是這樣的:首先使用叠代器的find()方法,在特定的索引中尋找需要的數據,比如在車主用戶名索引中尋找某個用戶。叠代器會移動到需要的數據對象上。然後就可以使用叠代器的modify()方法修改當前叠代器對應的數據。下圖為叠代器指向用戶 Sue 的情況。

技術分享圖片

本篇文章介紹了 EOS 數據庫的基本結構,以後的文章會詳細介紹 EOS 數據庫使用實戰,敬請期待。


EOS 數據庫與持久化 API —— 架構