EOS数据库操作

目录

新增

新增内容往往用到emplace构造函数,来进行数据库对象的新增。

  1. void test_da::create(account_name user, string title, string content)
  2. {
  3. require_auth( user ); //验证权限
  4. das datable( _self, user); //定义数据库对象
  5. datable.emplace(user, [&]( da & d){
  6. d.title = title;
  7. d.content = content;
  8. d.post_id = datable.available_primary_key();
  9. d.poster = user;
  10. }); //数据库内容创建
  11. }

这里需要注意的是:

  1. 定义数据库对象,其中第一个参数是合约的拥有者_self,第二个变量就是数据库的payer,也就是数据库是谁的,数据库存储在谁的账户下。
  2. emplace函数接收两个参数,一个payer,和一个lamada表达式。这个结构是固定的。

那么我们现在来看一下我们的test_da类是怎么定义的。 .hpp 

  1. class test_da : public contract {
  2. public:
  3. test_da( account_name self ):contract(self){}
  4. // @abi action
  5. void create(account_name user, string title, string content);
  6. private:
  7. // @abi table data i64
  8. struct da {
  9. uint64_t post_id;
  10. account_name poster;
  11. string title;
  12. string content;
  13. uint64_t primary_key()const { return post_id; }
  14. account_name get_poster() const { return poster; }
  15. EOSLIB_SERIALIZE(da, (post_id)(poster)(title)(content))
  16. };
  17. typedef eosio::multi_index<N(data), da, indexed_by<N(byposter), const_mem_fun<da, account_name, &da::get_poster>> > das;
  18. };
  19. } /// namespace eosio
  1. 所有的智能合约都继承自contract合约。test_da( account_name self ):contract(self){}test_da合约的构造函数。
  2. 下面是对create函数的声明。
  3. 接下来是对数据字段的定义。这里我们定义了数据结构da.
  4. primary_key函数是定义主键的函数。 
  5. 接下来我们定义了辅助主键返回poster
  6. EOSLIB_SERIALIZE宏的第一个参数是数据结构,其他参数是数据结构中的数据成员。
  7. typedef我们在这里定义了一个名字为das的类型,它用来定义数据库对象。这里我们定义的是一个具有主键及一个辅助键的数据库对象。

ABI文件 abi 非常重要,错误的abi会导致合约执行失败。

  1. {
  2. "types": [],
  3. "structs": [{
  4. "name": "da",
  5. "base": "",
  6. "fields": [{
  7. "name": "post_id",
  8. "type": "uint64"
  9. },{
  10. "name": "poster",
  11. "type": "account_name"
  12. },{
  13. "name": "title",
  14. "type": "string"
  15. },{
  16. "name": "content",
  17. "type": "string"
  18. }
  19. ]
  20. },{
  21. "name": "create",
  22. "base": "",
  23. "fields": [{
  24. "name": "user",
  25. "type": "account_name"
  26. },{
  27. "name": "title",
  28. "type": "string"
  29. },{
  30. "name": "content",
  31. "type": "string"
  32. }
  33. ]
  34. }}
  35. ],
  36. "actions": [{
  37. "name": "create",
  38. "type": "create",
  39. }
  40. ],
  41. "tables": [{
  42. "name": "data",
  43. "index_type": "i64",
  44. "key_names": [
  45. "post_id"
  46. ],
  47. "key_types": [
  48. "uint64"
  49. ],
  50. "type": "da"
  51. }
  52. ],
  53. "ricardian_clauses": []
  54. }

接下来来演示一下:

  1. 发布合约

    1. cleos set contract eosio test_da
    2. Reading WAST/WASM from test_da/test_da.wasm...
    3. Using already assembled WASM...
    4. Publishing contract...
    5. executed transaction: 3d6f04278617d3807fe876a33057f1155acf9c9e5a392ac6ed8ad51e79506009 6752 bytes 24679 us
    6. # eosio <= eosio::setcode {"account":"eosio","vmtype":0,"vmversion":0,"code":"0061736d0100000001ad011a60037f7e7e0060057f7e7e7f...
    7. # eosio <= eosio::setabi {"account":"eosio","abi":{"types":[],"structs":[{"name":"da","base":"","fields":[{"name":"post_id","...
  2. 创建数据

    1. cleos push action eosio create '{"user":"eosio","title":"first","content":"create a first one"}' -p eosio
    2. executed transaction: 830057f270fa499b1d61b82e80ad8cda1774cdc1786c1e786f558a3e0a48974c 216 bytes 17229 us
    3. # eosio <= eosio::create {"user":"eosio","title":"first","content":"create a first one"}

下面我们来查一下数据表:

  1. cleos get table eosio eosio data
  2. {
  3. "rows": [{
  4. "post_id": 0,
  5. "poster": "eosio",
  6. "title": "first",
  7. "content": "create a first one"
  8. }
  9. ],
  10. "more": false
  11. }

创建信息成功,那么我们用别的账号创建会怎样呢?

  1. cleos push action eosio create '{"user":"eostea","title":"eostea first","content":"eostea create a first one"}' -p eostea
  2. executed transaction: 8542a87e563a9c62b7dbe46ae09ccf829c7821f8879167066b658096718de148 232 bytes 2243 us
  3. # eosio <= eosio::create {"user":"eostea","title":"eostea first","content":"eostea create a first one"}

查看数据表:

  1. cleos get table eosio eostea data
  2. {
  3. "rows": [{
  4. "post_id": 0,
  5. "poster": "eostea",
  6. "title": "eostea first",
  7. "content": "eostea create a first one"
  8. }
  9. ],
  10. "more": false
  11. }

到这里,相信大家对创建数据已经没有什么疑惑了。

查询

对于数据库,最重要的功能就是查询,如果没有查询功能,数据库里的数据就不能呈现,也就没有意义。查询数据库主要分为两方面,一方面是主键查询,一方面是通过二级索引查询。

这里为了使表中数据多样化我会做一些修改,将所有数据都合到一张表中。 我将以上.cpp中的das datable( _self, user);改为das datable( _self, _self);.这样数

据都存在合约账户的表中。

主键查询

这里我添加了一个方法来查询数据并打印:

  1. void test_da::getd(uint64_t post_id){
  2. das datable(_self, _self);
  3. auto post_da = datable.find( post_id);
  4. eosio::print("Post_id: ", post_da->post_id, " Post_Tile: ", post_da->title.c_str(), " Content: ", post_da->content.c_str());
  5. }

ABI文件也做了相应的调整,执行:

  1. cleos push action eosio getd '{"post_id":1}' -p eosio
  2. executed transaction: ac8663235462d947c74542af848cca54a059c3991d193237025da7d4767d6725 192 bytes 1724 us
  3. # eosio <= eosio::getd {"post_id":1}
  4. >> Post_id: 1 Post_Tile: first Content: eosio create a first one

二级索引查询

添加二级索引查询代码如下:

  1. auto poster_index = datable.template get_index<N(byposter)>();
  2. auto pos = poster_index.find( user );
  3. for (; pos != poster_index.end(); pos++)
  4. {
  5. eosio::print("content:", pos->content.c_str(), " post_id:", pos->post_id, " title:", pos->title.c_str());
  6. }

获取二级索引并获取数据,这里我只用了find查询,其他查询就不在一一介绍。

执行getd操作:

  1. cleos push action eosio getd '{"post_id":2,"user": "eostea"}' -p eosio
  2. executed transaction: 2370e1fb1ee8a581f7321f02fb40645e51269e579d183c33ef470dba0b3afdbc 200 bytes 5403 us
  3. # eosio <= eosio::getd {"post_id":2,"user":"eostea"}
  4. >> Post_id: 2 Post_Tile: eostea first Content: eostea create a first onecontent:eostea create a first one post_id:2 title:eostea first

数据库中数据如下:

  1. cleos get table eosio eosio data
  2. {
  3. "rows": [{
  4. "post_id": 0,
  5. "poster": "eosio",
  6. "title": "first",
  7. "content": "eostea create a first one"
  8. },{
  9. "post_id": 1,
  10. "poster": "eosio",
  11. "title": "first",
  12. "content": "eostea create a first one"
  13. },{
  14. "post_id": 2,
  15. "poster": "eostea",
  16. "title": "eostea first",
  17. "content": "eostea create a first one"
  18. }
  19. ],
  20. "more": false
  21. }

更改

更改数据库内容。 这里我们先看一下目前的数据库内容。

  1. cleos get table eosio eosio data
  2. {
  3. "rows": [{
  4. "post_id": 0,
  5. "poster": "eosio",
  6. "title": "first",
  7. "content": "eostea create a first one"
  8. },{
  9. "post_id": 1,
  10. "poster": "eosio",
  11. "title": "first",
  12. "content": "eostea create a first one"
  13. },{
  14. "post_id": 2,
  15. "poster": "eostea",
  16. "title": "eostea first",
  17. "content": "eostea create a first one"
  18. }
  19. ],
  20. "more": false
  21. }

写一个更改数据的action代码如下:

  1. void test_da::change(account_name user, uint64_t post_id, string title, string content)
  2. {
  3. require_auth(user);
  4. das datable( _self, user);
  5. auto post = datable.find(post_id);
  6. eosio_assert(post->poster == user, "yonghucuowu");
  7. datable.modify(post, user, [&](auto& p){
  8. if (title != "")
  9. p.title = title;
  10. if (content != "")
  11. p.content = content;
  12. });
  13. }

前几行代码之前讲解过,现在直接说modify方法,他的第一个参数是你查询出的要更改的对象,第二个参数是payer,其他的不用多说。

下面我们执行一下命令:

  1. cleos push action eosio change '{"user":"eosio","post_id":1,"title":"change","content":"change action"}' -p eosio
  2. executed transaction: 8cb561a712f2741560118651aefd49efd161e3d73c56f6d24cf1d699c265e2dc 224 bytes 2130 us
  3. # eosio <= eosio::change {"user":"eosio","post_id":1,"title":"change","content":"change action"}

下面我们看一下数据库:

  1. cleos get table eosio eosio data
  2. {
  3. "rows": [{
  4. "post_id": 0,
  5. "poster": "eosio",
  6. "title": "first",
  7. "content": "eostea create a first one"
  8. },{
  9. "post_id": 1,
  10. "poster": "eosio",
  11. "title": "change",
  12. "content": "change action"
  13. },{
  14. "post_id": 2,
  15. "poster": "eostea",
  16. "title": "eostea first",
  17. "content": "eostea create a first one"
  18. }
  19. ],
  20. "more": false
  21. }

post_id=1的记录已经被改变,说明我们成功了。

删除数据

删除数据我又加了一个action,如下所示:

  1. void test_da::dele(account_name user, uint64_t post_id)
  2. {
  3. require_auth(user);
  4. das datable( _self, user);
  5. auto post = datable.find(post_id);
  6. eosio::print(post->title.c_str());
  7. eosio_assert(post->poster == user, "yonghucuowu");
  8. datable.erase(post);
  9. }

这里调用了erase方法删除数据,参数为一个数据对象。下面我们来看一下执行结果:

  1. cleos push action eosio dele '{"user":"eosio","post_id":1}' -p eosioexecuted transaction: 3affbbbbd1da328ddcf37753f1f2f6c5ecc36cd81a0e12fea0c789e75b59714e 200 bytes 2383 us
  2. # eosio <= eosio::dele {"user":"eosio","post_id":1}

现在再来看一下我们的数据库:

  1. cleos get table eosio eosio data
  2. {
  3. "rows": [{
  4. "post_id": 0,
  5. "poster": "eosio",
  6. "title": "first",
  7. "content": "eostea create a first one"
  8. },{
  9. "post_id": 2,
  10. "poster": "eostea",
  11. "title": "eostea first",
  12. "content": "eostea create a first one"
  13. }
  14. ],
  15. "more": false
  16. }

post_id=1的数据已经被我们删除。

到这里,数据库的增删改查已经讲解完毕,最终的智能合约:

.cpp

  1. #include "test_da/test_da.hpp"
  2. namespace eosio {
  3. void test_da::create(account_name user, string title, string content)
  4. {
  5. require_auth( user );
  6. das datable( _self, _self);
  7. datable.emplace(user, [&]( da & d){
  8. d.title = title;
  9. d.content = content;
  10. d.post_id = datable.available_primary_key();
  11. d.poster = user;
  12. });
  13. }
  14. void test_da::change(account_name user, uint64_t post_id, string title, string content)
  15. {
  16. require_auth(user);
  17. das datable( _self, user);
  18. auto post = datable.find(post_id);
  19. eosio_assert(post->poster == user, "yonghucuowu");
  20. datable.modify(post, user, [&](auto& p){
  21. if (title != "")
  22. p.title = title;
  23. if (content != "")
  24. p.content = content;
  25. });
  26. }
  27. void test_da::dele(account_name user, uint64_t post_id)
  28. {
  29. require_auth(user);
  30. das datable( _self, user);
  31. auto post = datable.find(post_id);
  32. eosio::print(post->title.c_str());
  33. eosio_assert(post->poster == user, "yonghucuowu");
  34. datable.erase(post);
  35. }
  36. void test_da::getd(uint64_t post_id, account_name user){
  37. das datable(_self, _self);
  38. auto post_da = datable.find( post_id);
  39. eosio::print("Post_id: ", post_da->post_id, " Post_Tile: ", post_da->title.c_str(), " Content: ", post_da->content.c_str());
  40. auto poster_index = datable.template get_index<N(byposter)>();
  41. auto pos = poster_index.find( user );
  42. for (; pos != poster_index.end(); pos++)
  43. {
  44. eosio::print("content:", pos->content.c_str(), " post_id:", pos->post_id, " title:", pos->title.c_str());
  45. }
  46. }
  47. }
  48. EOSIO_ABI(eosio::test_da, (create)(change)(dele)(getd))

.hpp

  1. #include <eosiolib/eosio.hpp>
  2. #include <string>
  3. namespace eosio {
  4. using std::string;
  5. class test_da : public contract {
  6. public:
  7. test_da( account_name self ):contract(self){}
  8. // @abi action
  9. void create(account_name user, string title, string content);
  10. void change(account_name user, uint64_t post_id, string title, string content);
  11. void dele(account_name user, uint64_t post_id);
  12. void getd(uint64_t post_id, account_name user);
  13. private:
  14. // @abi table data i64
  15. struct da {
  16. uint64_t post_id;
  17. account_name poster;
  18. string title;
  19. string content;
  20. uint64_t primary_key()const { return post_id; }
  21. account_name get_poster() const { return poster; }
  22. EOSLIB_SERIALIZE(da, (post_id)(poster)(title)(content))
  23. };
  24. typedef eosio::multi_index<N(data), da, indexed_by<N(byposter), const_mem_fun<da, account_name, &da::get_poster>> > das;
  25. };
  26. } /// namespace eosio

.abi

  1. {
  2. "types": [],
  3. "structs": [{
  4. "name": "da",
  5. "base": "",
  6. "fields": [{
  7. "name": "post_id",
  8. "type": "uint64"
  9. },{
  10. "name": "poster",
  11. "type": "account_name"
  12. },{
  13. "name": "title",
  14. "type": "string"
  15. },{
  16. "name": "content",
  17. "type": "string"
  18. }
  19. ]
  20. },{
  21. "name": "create",
  22. "base": "",
  23. "fields": [{
  24. "name": "user",
  25. "type": "account_name"
  26. },{
  27. "name": "title",
  28. "type": "string"
  29. },{
  30. "name": "content",
  31. "type": "string"
  32. }
  33. ]
  34. },{
  35. "name": "change",
  36. "base": "",
  37. "fields": [{
  38. "name": "user",
  39. "type": "account_name"
  40. },{
  41. "name": "post_id",
  42. "type": "uint64"
  43. },{
  44. "name": "title",
  45. "type": "string"
  46. },{
  47. "name": "content",
  48. "type": "string"
  49. }
  50. ]
  51. },{
  52. "name": "dele",
  53. "base": "",
  54. "fields": [{
  55. "name": "user",
  56. "type": "account_name"
  57. },{
  58. "name": "post_id",
  59. "type": "uint64"
  60. }
  61. ]
  62. },{
  63. "name": "get_data",
  64. "base": "",
  65. "fields": [{
  66. "name": "post_id",
  67. "type": "uint64"
  68. },{
  69. "name": "user",
  70. "type": "account_name"
  71. }
  72. ]
  73. }
  74. ],
  75. "actions": [{
  76. "name": "create",
  77. "type": "create",
  78. },{
  79. "name": "change",
  80. "type": "change",
  81. },{
  82. "name": "dele",
  83. "type": "dele",
  84. },{
  85. "name": "getd",
  86. "type": "get_data",
  87. }
  88. ],
  89. "tables": [{
  90. "name": "data",
  91. "index_type": "i64",
  92. "key_names": [
  93. "post_id"
  94. ],
  95. "key_types": [
  96. "uint64"
  97. ],
  98. "type": "da"
  99. }
  100. ],
  101. "ricardian_clauses": []
  102. }