fisco中的CRUD合约

刚开始接触时候一脸懵逼,这个东西感觉挺有意思的,现在就就来学习一下

查看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操作效率更高。

 

好的,我可以为您解答关于在 SpringBoot 调用 FISCO BCOS 合约的问题。 首先,您需要在项目引入 FISCO BCOS 的 Java SDK 包,可以通过 Maven 或 Gradle 依赖来实现。然后,您需要创建一个合约的 Java 接口,该接口需要继承自 org.fisco.bcos.sdk.contract.Contract 接口,并定义您合约的方法,如下所示: ```java public interface MyContract extends Contract { public RemoteCall<TransactionReceipt> myMethod(int param1, String param2); } ``` 在接口,您需要定义您合约的方法,方法的返回值类型需要使用 RemoteCall 包装,以便异步调用合约并获取合约返回结果。 接下来,您需要实现该接口,实现类需要继承自 org.fisco.bcos.sdk.contract.ContractImpl 类,并在构造函数调用父类的构造函数,同时将合约地址、私钥、公钥等信息传递给父类,如下所示: ```java public class MyContractImpl extends ContractImpl implements MyContract { public MyContractImpl(String contractAddress, Web3j web3j, Credentials credentials, BigInteger gasPrice, BigInteger gasLimit) { super(contractAddress, web3j, credentials, gasPrice, gasLimit); } @Override public RemoteCall<TransactionReceipt> myMethod(int param1, String param2) { // 执行合约方法 return executeRemoteCallTransaction(FunctionEncoder.encode(function), gasPrice, gasLimit); } } ``` 在实现类,您需要实现接口定义的方法,并在方法调用合约的方法。 最后,在您的 SpringBoot 应用程序,您可以通过以下方式进行合约的调用: ```java @Autowired private Web3j web3j; @Autowired private Credentials credentials; public void callContract() { String contractAddress = "0x..."; // 合约地址 MyContract myContract = new MyContractImpl(contractAddress, web3j, credentials, gasPrice, gasLimit); RemoteCall<TransactionReceipt> remoteCall = myContract.myMethod(1, "test"); TransactionReceipt receipt = remoteCall.sendAsync().get(); // 处理合约返回结果 } ``` 在 SpringBoot ,您可以通过注入 Web3j 和 Credentials 对象来连接 FISCO BCOS 区块链网络,并通过调用 MyContractImpl 类定义的方法来调用合约。最后,您可以通过异步调用 RemoteCall 对象的 sendAsync 方法来执行合约方法,并获取合约返回结果。 希望这些信息对您有所帮助。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值