战魂小筑

讨论群:309800774 知乎关注:http://zhihu.com/people/sunicdavy 开源项目:https://github.com/davyxu

   :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  257 随笔 :: 0 文章 :: 506 评论 :: 0 Trackbacks

protobuf反射代码借鉴自陈硕的blog一种自动反射消息类型的 Google Protobuf 网络传输方案  在此表示感谢

这里是proto文件

message QueryAccount
{    
    // in
    required string SQL = 1;
    
    // out
    optional int64 id = 2;
}
 
C++实现
   1:  void ReflectionFill( google::protobuf::Message* Msg, const google::protobuf::Descriptor* MsgDescriptor, mysqlpp::Row& RowData )
   2:  {
   3:      using namespace google::protobuf;
   4:   
   5:      // 遍历所有消息成员
   6:      for ( size_t i = 0;i < MsgDescriptor->field_count();i++ )
   7:      {        
   8:          const FieldDescriptor* EachField = MsgDescriptor->field( i );
   9:   
  10:          // 这里假定optinal的是返回值
  11:          if ( !EachField->is_optional() )
  12:              continue;
  13:   
  14:          // sql的列
  15:          std::string FieldName = EachField->name();
  16:              
  17:          // 返回的CPP类型
  18:          switch ( EachField->cpp_type() )
  19:          {
  20:          case FieldDescriptor::CPPTYPE_STRING:
  21:              {
  22:                  std::string Result  = RowData[FieldName.c_str()];
  23:                  Msg->GetReflection()->SetString( Msg, EachField, Result );
  24:              }
  25:              break;
  26:          case FieldDescriptor::CPPTYPE_INT64:
  27:              {
  28:                  // 从列取值
  29:                  __int64 Result = RowData[FieldName.c_str()];
  30:   
  31:                  // 设置消息
  32:                  Msg->GetReflection()->SetInt64( Msg, EachField, Result );
  33:              }
  34:              break;
  35:          }
  36:   
  37:      }
  38:  }
  39:   
  40:   
  41:   
  42:  void ParseMessage( mysqlpp::Connection& SQLConnection, const char* ProtoType, void* Data, size_t Size )
  43:  {
  44:      // 转载请注明来自 战魂小筑http://www.cppblog.com/sunicdavy
  45:      using namespace google::protobuf;
  46:   
  47:      Message* Msg = NULL;
  48:   
  49:      // 通过类型字符串查出消息类型信息
  50:      const Descriptor* MsgDescriptor = DescriptorPool::generated_pool()->FindMessageTypeByName(ProtoType);
  51:      if (MsgDescriptor == NULL )
  52:          return;
  53:   
  54:      // 取消息原型
  55:      const Message* MsgPrototype = MessageFactory::generated_factory()->GetPrototype(MsgDescriptor);
  56:      if (MsgPrototype == NULL )
  57:          return;
  58:   
  59:      // 不能用原型消息哦,要新的
  60:      Msg = MsgPrototype->New();
  61:   
  62:      // 解析数据
  63:      Msg->ParseFromArray( Data, Size );
  64:   
  65:      // 查找SQL指令
  66:      const FieldDescriptor* SQLField = MsgDescriptor->FindFieldByName("SQL");
  67:      if ( SQLField == NULL )
  68:          return;
  69:   
  70:      // 使用反射查出值
  71:      std::string SQLCmd = Msg->GetReflection()->GetString( *Msg, SQLField );
  72:   
  73:      // 进行SQL查询
  74:      mysqlpp::Query query = SQLConnection.query( SQLCmd.c_str() );
  75:   
  76:      // 确认查询有效
  77:      mysqlpp::StoreQueryResult res = query.store();
  78:   
  79:      if (!res)
  80:          return;
  81:   
  82:      // 这里只取第一个消息
  83:      mysqlpp::Row RowData = *res.begin();
  84:   
  85:      // 反射填充消息
  86:      ReflectionFill( Msg, MsgDescriptor, RowData );
  87:   
  88:      // 测试返回数据
  89:      dbsvc::QueryAccount* qamsg = dynamic_cast<dbsvc::QueryAccount*>( Msg );
  90:      __int64 i = qamsg->id();
  91:   
  92:      delete Msg;
  93:  }
  94:   
  95:   
  96:  int main(int argc, char* argv[])
  97:  {    
  98:      mysqlpp::Connection con(false);
  99:   
 100:      con.set_option(new mysqlpp::SetCharsetNameOption("gbk"));
 101:   
 102:   
 103:      if (!con.connect("testdb", "localhost", "root", "123"))
 104:      {
 105:          return -1;
 106:      }
 107:      else
 108:      {
 109:   
 110:          dbsvc::QueryAccount Msg;
 111:          Msg.set_sql("select id from account where username = 'hello'");
 112:          std::string s;
 113:          Msg.SerializeToString( &s );
 114:   
 115:          ParseMessage( con, "dbsvc.QueryAccount", (void*)s.data(), s.size() );
 116:      }
 117:   
 118:      google::protobuf::ShutdownProtobufLibrary();
 119:  }
posted on 2011-12-14 17:48 战魂小筑 阅读(4856) 评论(3)  编辑 收藏 引用 所属分类: 网络 服务器技术

评论

# re: ProtocolBuffer + MySQL++实现消息反射查询返回数据 2012-03-15 21:56 aya
sql语句+protobuf入参的形式,还是不够通用啊。
存储过程+protobuf入参+protobuf出参封装成一个数据库逻辑层,底层用odbc,mysql之类的api, 上层用lua写逻辑,可以写个自动映射的数据库的服务器就好了。  回复  更多评论
  

# re: ProtocolBuffer + MySQL++实现消息反射查询返回数据 2012-04-27 17:50 YU_YU
这里也有一篇和你一样精神的文章 http://geek.renren.com/?p=71
其实,最好就是连proto文件都不需要,有好多数据库查询都是联合语句,很复杂,不可能把所有的proto都定义出来  回复  更多评论
  

# re: ProtocolBuffer + MySQL++实现消息反射查询返回数据 2012-05-12 10:24 战魂小筑
@YU_YU
感谢分享.
这套机制与我们项目使用的技术类似.   回复  更多评论
  


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理