刚开始接触时候一脸懵逼,这个东西感觉挺有意思的,现在就就来学习一下
查看fisco中的console下的合约目录,除了最最开始也是最简单的HelloWorld合约,接着就是对于CRUD合约最为关键的Table.sol
这里面主要内容就是KVTable合约读写接口和Table合约的CRUD接口,将SOlidity合约中数据存储早fisco平台中AMDB表结构中,达到数据逻辑分离效果
Table中CRUD
首先创建指定合约TableFactory 然后通过createTable传递表名,主键名,字段名。可以有多个字段,字段之间使用逗号分隔
查看这个合约内容首先是第一个合约TableFactory 这是用来创建一个表和根据名字打开一个表的合约。
contract TableFactory {
/**
* @brief 打开表,返回Table合约地址
* @param tableName 表的名称
* @return 返回Table的地址,当表不存在时,将会返回空地址即address(0x0)
*/
function openTable(string tableName) public constant returns (Table);
/**
* @brief 创建表,返回是否成功
* @param tableName 表的名称
* @param key 表的主键名
* @param valueFields 表的字段名,多个字段名以英文逗号分隔
* @return 返回错误码,成功为0,错误则为负数
*/
function createTable(string tableName,string key,string valueFields) public returns(int);
}
Table合约
通过TableFactory 创建的Table就可以通过openTable根据表名打开指定的Table,然后进行类似与传统Mysql中的select、update、insert、delete操作
Table :CRUD接口中一个key可以有多个记录,使用时候会进行批量操作,在我们传统关系型数据库MySQL中就在进行大量类似操作,在这里使用MySQL比较合适
//Table main contract
contract Table {
function select(string memory, Condition) public view returns (Entries) {}
function insert(string memory, Entry) public returns (int256) {}
function update(string memory, Entry, Condition) public returns (int256) {}
function remove(string memory, Condition) public returns (int256) {}
function newEntry() public view returns (Entry) {}
function newCondition() public view returns (Condition) {}
}
Condition条件查询
Condition 合约,类似使用where来进行条件查询,只是这里通过一个外部方法指定,用来在Table合约中对数据库进行传统的判断操作,简单来说就是指定进行操作的条件
// 查询条件
contract Condition {
//等于
function EQ(string, int) public;
function EQ(string, string) public;
//不等于
function NE(string, int) public;
function NE(string, string) public;
//大于
function GT(string, int) public;
//大于或等于
function GE(string, int) public;
//小于
function LT(string, int) public;
//小于或等于
function LE(string, int) public;
//限制返回记录条数
function limit(int) public;
function limit(int, int) public;
}
Entry单条数据记录实体
Entry :用于创建一条记录的实体,通过记录实体中一系列方法传递一个字段,返回指定类型信息,或者通过set设置指定字段值
//one record
// 单条数据记录
contract Entry {
function getInt(string memory) public view returns (int256) {}
function getUInt(string memory) public view returns (uint256) {}
function getAddress(string memory) public view returns (address) {}
function getBytes64(string memory) public view returns (bytes1[64] memory) {}
function getBytes32(string memory) public view returns (bytes32) {}
function getString(string memory) public view returns (string memory) {}
function set(string memory, int256) public {}
function set(string memory, uint256) public {}
function set(string memory, string memory) public {}
function set(string memory, address) public {}
}
Entries:多条数据记录集合
存放多条数据记录,通过size查询条数,通过get获取指定条数的单条记录
//record sets
//数据记录集合,可以查看数据集合数量或通过get获取一条数据实体(ENTRY)
contract Entries {
function get(int256) public view returns (Entry) {}
function size() public view returns (int256) {}
}
通过官方文档案例来学习
pragma solidity >=0.6.10 <0.8.20;
pragma experimental ABIEncoderV2;
import "./Table.sol";
contract TableTest {
event CreateResult(int256 count);
event InsertResult(int256 count);
event UpdateResult(int256 count);
event RemoveResult(int256 count);
TableFactory tableFactory;
string constant TABLE_NAME = "t_test";
constructor() public {
tableFactory = TableFactory(0x1001); //The fixed address is 0x1001 for TableFactory
// the parameters of createTable are tableName,keyField,"vlaueFiled1,vlaueFiled2,vlaueFiled3,..."
tableFactory.createTable(TABLE_NAME, "name", "item_id,item_name");
}
//select records
function select(string memory name)
public
view
returns (string[] memory, int256[] memory, string[] memory)
{
Table table = tableFactory.openTable(TABLE_NAME);
Condition condition = table.newCondition();
Entries entries = table.select(name, condition);
string[] memory user_name_bytes_list = new string[](
uint256(entries.size())
);
int256[] memory item_id_list = new int256[](uint256(entries.size()));
string[] memory item_name_bytes_list = new string[](
uint256(entries.size())
);
for (int256 i = 0; i < entries.size(); ++i) {
Entry entry = entries.get(i);
user_name_bytes_list[uint256(i)] = entry.getString("name");
item_id_list[uint256(i)] = entry.getInt("item_id");
item_name_bytes_list[uint256(i)] = entry.getString("item_name");
}
return (user_name_bytes_list, item_id_list, item_name_bytes_list);
}
//insert records
function insert(string memory name, int256 item_id, string memory item_name)
public
returns (int256)
{
Table table = tableFactory.openTable(TABLE_NAME);
Entry entry = table.newEntry();
entry.set("name", name);
entry.set("item_id", item_id);
entry.set("item_name", item_name);
int256 count = table.insert(name, entry);
emit InsertResult(count);
return count;
}
//update records
function update(string memory name, int256 item_id, string memory item_name)
public
returns (int256)
{
Table table = tableFactory.openTable(TABLE_NAME);
Entry entry = table.newEntry();
entry.set("item_name", item_name);
Condition condition = table.newCondition();
condition.EQ("name", name);
condition.EQ("item_id", item_id);
int256 count = table.update(name, entry, condition);
emit UpdateResult(count);
return count;
}
//remove records
function remove(string memory name, int256 item_id) public returns (int256) {
Table table = tableFactory.openTable(TABLE_NAME);
Condition condition = table.newCondition();
condition.EQ("name", name);
condition.EQ("item_id", item_id);
int256 count = table.remove(name, condition);
emit RemoveResult(count);
return count;
}
}
KVTable中键值型操作
KVTable合约实现键值型读写数据的方式,
contract KVTableFactory {
function openTable(string memory) public view returns (KVTable) {}
function createTable(string memory, string memory, string memory) public returns (int256) {}
}
//KVTable per permiary key has only one Entry
contract KVTable {
function get(string memory) public view returns (bool, Entry) {}
function set(string memory, Entry) public returns (int256) {}
function newEntry() public view returns (Entry) {}
}
通过以下小案例和注释学习一下操作方法(KVTable)
pragma solidity ^0.4.24;
import './Table.sol';
contract three {
event SetResult(int256 count);
KVTableFactory tableFactory;
string constant TABLE_NAME = "t_kvtest";
constructor() public {
//The fixed address is 0x1010 for KVTableFactory
tableFactory = KVTableFactory(0x1010);
tableFactory.createTable(TABLE_NAME, "id", "item_price,item_name");
// 表名,主键,字段
}
//get record
function get(string id) public view returns (bool, int256, string) {
// 根据id查询表中数据
KVTable table = tableFactory.openTable(TABLE_NAME);
// 打开表
bool ok = false;
Entry entry;
(ok, entry) = table.get(id);
// 返回bool类型和一个实体,使用创建好的实体进行接受
int256 item_price;
string memory item_name;
if (ok) {
// 接收成功后执行entry查询到实体的get方法获取数据
item_price = entry.getInt("item_price");
item_name = entry.getString("item_name");
}
return (ok, item_price, item_name);
// 返回值查询是否成功
// 商品价格、商品名字
}
//set record
function set(string id, int256 item_price, string item_name)
public
returns (int256)
{
KVTable table = tableFactory.openTable(TABLE_NAME);
// 根据表名打开表
Entry entry = table.newEntry();
// 根据接口获取一个实体
// the length of entry's field value should < 16MB
entry.set("id", id);
entry.set("item_price", item_price);
entry.set("item_name", item_name);
// 通过实体set方法插入数据
// the first parameter length of set should <= 255B
int256 count = table.set(id, entry);
// 通过table中id和实体插入数据,返回影响行数
emit SetResult(count);
return count;
}
}
为实现AMDB创建的表可被多个合约共享访问,其表名是群组内全局可见且唯一的,所以无法在同一条链上的同一个群组中,创建多个表名相同的表
为实现AMDB创建的表可被多个合约共享访问,其表名是群组内全局可见且唯一的,所以无法在同一条链上的同一个群组中,创建多个表名相同的表。 Table的CRUD接口一个key下可以有多条记录,使用时会进行数据批量操作,包括批量写入和范围查询。对应此特性,推荐使用关系型数据库MySQL作为后端数据库。 使用KVTtable的get/set接口时,推荐使用RocksDB作为后端数据库,因RocksDB是Key-Value存储的非关系型数据库,使用KVTable接口时单key操作效率更高。