[PB Generic Table][Go SDK] Get a Record

1. Interface Description

Get a record from a database table

2. Version Requirements

This interface is provided in all versions without special requirements.

3. Preparations

Refer to Preparation document to complete the preparation before using this interface and create the following PB Generic table. game_players table

syntax = "proto3";                      // Specify the version of the protocol buffers language

package tcaplusservice;

import "tcaplusservice.optionv1.proto"; // Use the public definitions of TcaplusDB by importing them.

message game_players {  // Define a TcaplusDB table with message

// Specify the primary keys with the option tcaplusservice.tcaplus_primary_key
// The primary key of a TcaplusDB table has a limit of 4 fields
option(tcaplusservice.tcaplus_primary_key) = "player_id, player_name, player_email";

// Specify the primary key indexes with the option tcaplusservice.tcaplus_index
option(tcaplusservice.tcaplus_index) = "index_1(player_id, player_name)";
option(tcaplusservice.tcaplus_index) = "index_2(player_id, player_email)";


// Value Types supported by TcaplusDB
// int32, int64, uint32, uint64, sint32, sint64, bool, fixed64, sfixed64, double, fixed32, sfixed32, float, string, bytes
// Nested Types Message

// primary key fields
int64 player_id = 1;
string player_name = 2;
string player_email = 3;


// Ordinary fields
int32 game_server_id = 4;
repeated string login_timestamp = 5;
repeated string logout_timestamp = 6;
bool is_online = 7;

payment pay = 8;
}


message payment {

int64 pay_id = 1;
uint64 amount = 2;
int64 method = 3;

}

Get the following information after the preparation. These details will be used by the SDK:

  1. Directory server address list
  2. App ID
  3. App access password
  4. Game zone ID
  5. Table name

4. Example Code

Basic execution process of example code:

  1. Define table configuration parameters
  2. Set log configuration;
  3. Create a client;
  4. Send a request and process the response;
  5. Destroy the client.

Example of client initialization:

package main

import (
    "fmt"
    "github.com/tencentyun/tcaplusdb-go-sdk/pb"
)

// Define table configuration parameters
const (
    AppId                = uint64(2)
    ZoneId               = uint32(3)
    DirUrl               = "tcp://x.x.x.x:xxxx"
    Signature            = "xxxxxxxxxxxxx"
    TableName            = "game_players"
)

var client *tcaplus.PBClient

func main() {
    // Create a client
    client = tcaplus.NewPBClient()
    // Set log configuration and the log level in the logconf.xml file
    if err := client.SetLogCfg("./logconf.xml"); err != nil {
      fmt.Println(err.Error())
      return
    }

    //Construct a Map object to store all tables under the corresponding table group
    zoneList := []uint32{ZoneId}
    zoneTable := make(map[uint32][]string)
    zoneTable[ZoneId] = []string{TableName}

    // Connect to the TcaplusDB backend
    err := client.Dial(AppId, zoneList, DirUrl, Signature, 30, zoneTable)
    if err != nil {
        fmt.Printf("init failed %v\n", err.Error())
        return
    }
    // Set the zone used by default
    client.SetDefaultZoneId(ZoneId)
    fmt.Printf("Dial finish\n")
    getExample()

    // Call Close to destroy the client when the program exits
    client.Close()
}

4.1 Synchronous Call Example

The synchronous call coding is the simplest, and it can be implemented through multiple concurrent processes. Example Directory

package main

import (
    "fmt"
    "git.woa.com/gcloud_storage_group/tcaplus-go-api/example/PB/table/tcaplusservice"
    "git.woa.com/gcloud_storage_group/tcaplus-go-api/example/PB/tools"
    "git.woa.com/gcloud_storage_group/tcaplus-go-api/logger"
    "git.woa.com/gcloud_storage_group/tcaplus-go-api/protocol/option"
)

func getExample() {
    // Set the key field of msg
    msg := &tcaplusservice.GamePlayers{
      PlayerId:    10805514,
      PlayerName:  "Calvin",
      PlayerEmail: "calvin@test.com",
    }
    // Send the Get request synchronously, and the response message will overwrite the msg
    opt := &option.PBOpt{}
    err := client.DoGet(msg, opt)
    if err != nil {
      logger.ERR("SendRequest error:%s", err)
      return
    }
    fmt.Println(tools.ConvertToJson(msg))
    fmt.Println(opt.Version) //Record version
}

4.2 Synchronous Call Example 2

The synchronous call mode of this example is similar to that of the C++ interface, and the request needs to be created and the response needs to be parsed. Example Directory

package main

import (
    "fmt"
    "github.com/tencentyun/tcaplusdb-go-sdk/tdr/example/PB/table/tcaplusservice"
    "github.com/tencentyun/tcaplusdb-go-sdk/tdr/example/PB/tools"
    "github.com/tencentyun/tcaplusdb-go-sdk/tdr/logger"
    "github.com/tencentyun/tcaplusdb-go-sdk/tdr/protocol/cmd"
    "github.com/tencentyun/tcaplusdb-go-sdk/tdr/terror"
    "time"
)

func getExample() {
    // Generate a get request
    req, err := client.NewRequest(ZoneId, "game_players", cmd.TcaplusApiGetReq)
    if err != nil {
      logger.ERR("NewRequest error:%s", err)
      return
    }

    // Add a record to the request. The index of the generic table is meaningless, just fill in 0
    record, err := req.AddRecord(0)
    if err != nil {
      logger.ERR("AddRecord error:%s", err)
      return
    }

    // Fill in data to the record
    // The key field is required. Set the key through the proto file
    // In this sample, option(tcaplusservice.tcaplus_primary_key) = "player_id, player_name, player_email";
    msg := &tcaplusservice.GamePlayers{
      PlayerId:    10805514,
      PlayerName:  "Calvin",
      PlayerEmail: "calvin@test.com",
    }

    _, err = record.SetPBData(msg)
    if err != nil {
      logger.ERR("SetPBData error:%s", err)
      return
    }

    // Send a request and receive the response;
    resp, err := client.Do(req, 5*time.Second)
    if err != nil {
      logger.ERR("SendRequest error:%s", err)
      return
    }

    // Get the response result
    errCode := resp.GetResult()
    if errCode != terror.GEN_ERR_SUC {
      logger.ERR("insert error:%s", terror.GetErrMsg(errCode))
      return
    }

    // Use the following interfaces to fetch return records if any
    for i := 0; i < resp.GetRecordCount(); i++ {
      record, err := resp.FetchRecord()
      if err != nil {
        logger.ERR("FetchRecord failed %s", err.Error())
        return
      }

      newMsg := &tcaplusservice.GamePlayers{}
      err = record.GetPBData(newMsg)
      if err != nil {
        logger.ERR("GetPBData failed %s", err.Error())
        return
      }
      fmt.Println(tools.ConvertToJson(newMsg))
    }
}

Asynchronous sending can use fewer processes to achieve greater concurrency. The coding is relatively complex. Example Directory

package main

import (
    "fmt"
    "git.woa.com/gcloud_storage_group/tcaplus-go-api/example/PB/table/tcaplusservice"
    "git.woa.com/gcloud_storage_group/tcaplus-go-api/example/PB/tools"
    "git.woa.com/gcloud_storage_group/tcaplus-go-api/logger"
    "git.woa.com/gcloud_storage_group/tcaplus-go-api/protocol/cmd"
    "git.woa.com/gcloud_storage_group/tcaplus-go-api/terror"
    "sync"
    "time"
)

func getExample() {
    wg := sync.WaitGroup{}
    wg.Add(1)
    // Process the response message in another coroutine
    go func() {
        defer wg.Done()
        for {
            // If resp and err are both nil, there is no response in the response pool
            resp, err := client.RecvResponse()
            if err != nil {
                logger.ERR("RecvResponse error:%s", err)
                continue
            } else if resp == nil {
                time.Sleep(time.Microsecond * 5)
                continue
            }

            // Get the response result
            errCode := resp.GetResult()
            if errCode != terror.GEN_ERR_SUC {
                logger.ERR("insert error:%s", terror.GetErrMsg(errCode))
                return
            }

            // Use the following interfaces to fetch return records if any
            for i := 0; i < resp.GetRecordCount(); i++ {
                record, err := resp.FetchRecord()
                if err != nil {
                    logger.ERR("FetchRecord failed %s", err.Error())
                    return
                }

                newMsg := &tcaplusservice.GamePlayers{}
                err = record.GetPBData(newMsg)
                if err != nil {
                    logger.ERR("GetPBData failed %s", err.Error())
                    return
                }
                fmt.Println(tools.ConvertToJson(newMsg))
            }
        }
    }()

    // Generate a get request
    req, err := client.NewRequest(tools.ZoneId, "game_players", cmd.TcaplusApiGetReq)
    if err != nil {
        logger.ERR("NewRequest error:%s", err)
        return
    }

    // Add a record to the request. The index of the generic table is meaningless, just fill in 0
    record, err := req.AddRecord(0)
    if err != nil {
        logger.ERR("AddRecord error:%s", err)
        return
    }

    // Fill in data to the record
    // The key field is required. Set the key through the proto file
    // In this sample, option(tcaplusservice.tcaplus_primary_key) = "player_id, player_name, player_email";
    msg := &tcaplusservice.GamePlayers{
        PlayerId:    10805514,
        PlayerName:  "Calvin",
        PlayerEmail: "calvin@test.com",
    }

    _, err = record.SetPBData(msg)
    if err != nil {
        logger.ERR("SetPBData error:%s", err)
        return
    }

    // Send a request asynchronously
    if err := client.SendRequest(req); err != nil {
        fmt.Printf("SendRequest failed %v\n", err.Error())
        return
    }
    wg.Wait()
}

5. Method Description in Request Object

Note: Other methods of the request object are not listed here, which means that this method is not required in the scenario of querying data. Misuse may result in errors.

/**
  @brief: add a record to the request.
  @param [IN] index: used for List operations, and it is usually >=0, indicating the Index of the Record in the List.
                            For Generic operations, the index is meaningless, just set 0
  @retval record.Record: return the record pointer
  @retval error: error code
**/
AddRecord(index int32) (*record.Record, error)

/**
@brief: set the asynchronous transaction ID of the request, and the API will bring its value back through the response message unchanged
@param  [IN] asyncId: asynchronous transaction ID of the request
**/
SetAsyncId(id uint64)

/**
@brief: set the general flag bit of the request. Multiple values can be set at the same time through the "bit or" operation
@param  [IN]  flag: value of the request flag bit
@retval 0: setting successful
@retval < 0 failed and returned the corresponding error code. Usually because it is not initialized.
@note: valid flag bits include:
*  TCAPLUS_FLAG_FETCH_ONLY_IF_MODIFIED:
*      "Fetch only if modified" flag bit: Before starting a read operation, the user code carries the version number of the locally buffered data through TcaplusServiceRecord::SetVersion()
*      and sets this flag. When the storage end detects that the current data is consistent with the API buffered data version,
*      it indicates that the record has not been modified and that the API buffered data is the latest. As a result, it will not return the actual data,
*      but only the error code of TcapErrCode::COMMON_INFO_DATA_NOT_MODIFIED
*
*      After this flag bit is set in the request, the response should first be received through TcaplusServiceResponse::GetFlags() to find out
*      whether the TCAPLUS_FLAG_FETCH_ONLY_IF_MODIFIED flag was set when sending the request.
*
*      Only the following requests support setting this flag:
*           TCAPLUS_API_GET_REQ,
*           TCAPLUS_API_LIST_GET_REQ,
*           TCAPLUS_API_LIST_GETALL_REQ
*
*  TCAPLUS_FLAG_FETCH_ONLY_IF_EXPIRED:
*      "Fetch only if expired" flag bit: Before starting a read operation, the user code sets the data expiration time through SetExpireTime(),
*      and set this flag. When the storage end detects that the record has been updated within the specified time, it will return the data.
*      Otherwise, it will not return the actual data, but only the error code of TcapErrCode::COMMON_INFO_DATA_NOT_MODIFIED.
*
*      After this flag bit is set in the request, the response should first be received through TcaplusServiceResponse::GetFlags() to find out
*      whether the TCAPLUS_FLAG_FETCH_ONLY_IF_EXPIRED flag was set when sending the request.
*
*      Only the following requests support setting this flag:
*           TCAPLUS_API_BATCH_GET_REQ
*
*  TCAPLUS_FLAG_ONLY_READ_FROM_SLAVE
*      After setting this flag, the read request will be directly sent to the Tcapsvr Slave node.
*      Tcapsvr Slave is usually relatively idle. Setting this flag helps to fully utilize Tcapsvr Slave resources.
*
*      Applicable scenarios:
*                              read requests that do not require high data timeliness,
*                              including all read requests for the generic table and list table, as well as batch get and traversal requests
*
*  TCAPLUS_FLAG_LIST_RESERVE_INDEX_HAVING_NO_ELEMENTS
*       After setting this flag, the index and version need to be retained when deleting the last element in the List table.
*       The ListDelete, ListDeleteBatch and ListDeleteAll operations set this flag when deleting the last element of the list table.
*       When writing a new List record, the version number will increase and not be reset to 1.
*
*      Applicable scenarios:
*                              app that needs to determine whether a table needs to retain index and version when deleting the last element.
*                              Mainly involves the use experience of the List table
*
*/
SetFlags(flag int32) int

/**
  @brief: clear the general flag bit of the request. Multiple values can be set at the same time through the "bit or" operation
  @param  [IN]  flag: value of the request flag bit
  @retval 0: setting successful
  @retval < 0 failed and returned the corresponding error code. Usually because it is not initialized.
  @note: for a list of valid flag bits and a detailed explanation, please refer to SetFlags()
*/
ClearFlags(flag int32) int

/**
  @brief: get the general flag bit of the request
  @return: return the general flag bit of the request
  @note: for a list of valid flag bits and a detailed explanation, please refer to SetFlags()
*/
GetFlags() int32

/**
  @brief: set the name list of the Value fields for getting or updating, that is, getting and updating part Value fields, which can be used for get, replace, and update operations.
  @param [IN] valueNameList: list of field names that need to be queried or updated
  @retval error: error code
  @note: when using this function to set a field name, the field name can only contain the value field name the key field name, not
              The refer field and array field should be set at the same time or not at the same time, otherwise there may be data confusion
**/
SetFieldNames(valueNameList []string) error

/**
@brief: set the user buffer, which is carried back by the response
@param [IN] userBuffer: user buffer
@retval error: error code
**/
SetUserBuff(userBuffer []byte) error

6. Method Description in Response Object

Note: Other methods of response object are not listed here, which means that this method is not required in the scenario of querying data. Misuse may result in errors.

/*
    @brief: get the result
    @retval int tcaplus api: user-defined error code 0 means the request was successful; non-0 means error codes, which can be got from terror.GetErrMsg(int)
*/
GetResult() int

/*
    @brief: get the result table Name
    @retval string: table name of the result message
*/
GetTableName() string

/*
    @brief: get the result appId
    @retval uint64: appId of the result message
*/
GetAppId() uint64

/*
    @brief: get the result zoneId
    @retval uint32: zoneId of the result message
*/
GetZoneId() uint32

/*
    @brief: get the result command word
    @retval int: result message command word, the response command word in the cmd package
*/
GetCmd() int

/*
    @brief: get the result asynchronous ID corresponding to the request
    @retval uint64: asynchronous ID of the result message, corresponding to the request
*/
GetAsyncId() uint64

/*
    @brief: get the number of result records in this response
    @retval int: the number of result records in this response
*/
GetRecordCount() int

/*
    @brief: get a record from the result
    @retval * record.Record: record pointer
    @retval error: error code
*/
FetchRecord() (*record.Record, error)

/*
    @brief: get the user buffer information in the response
    @retval []byte: user buffer binary, consistent with the buffer value in the request message
*/
GetUserBuffer() []byte

7. Method Description in Record Object

Note: Other methods of response object are not listed here, which means that this method is not required in the scenario of querying data. Misuse may result in errors.

  • Common method of record:
/**
    @brief: get the record version number
    @retval: record version number
    @note: For the Generic operation, it means getting the version of the Record; whereas for the List operation, it means getting the version of the List in which the Record is located.
**/
func (r *Record) GetVersion() int32   

/**
  @brief: set the record data based on the PB Message
  @param [IN] data  PB Message
  @retval []byte: record's keybuf, which is used to uniquely identify a record and is often used to request and respond to records
  @retval error: error code
*/
func (r *Record) SetPBData(message proto.Message) ([]byte, error)

/**
    @brief: get the record data based on the PB Message
    @param [IN] data   PB Message
    @retval []byte: record's keybuf, which is used to uniquely identify a record and is often used to request and respond to records
    @retval error: error code
**/
func (r *Record) GetPBData(message proto.Message) error

8. FAQ

For details, see Meaning and Handling of Error Codes.

8. Other Reference Documents

[[PB Generic Table] [C++ SDK] Interface Description for Getting a Record](../../01C++_SDK/02Interface_Documents/01[Generic_Table]Get_a_Record.md

[[PB Generic Table] [RESTFul API] Interface Description for Getting a Record](../../03RESTFul_API/02Interface_Documents/01[Generic_Table]Get_a_Record.md

results matching ""

    No results matching ""