代碼
出錯代碼段
bool CGameServer::getAccountInfoByUserId(int user_id, UserAccountData& data) {
if (connectToLocalDB()) {
log_error("connect to db failed");
return false;
}
TLIB_DB_LINK *pTempDBLink = &m_stLDBLink;
snprintf(pTempDBLink->sQuery[0], sizeof(pTempDBLink->sQuery[0]),
"select bind_mark, account, password, state, device_mark, country, tunnel, \
register_version, transfer_code, bind_equipment from account_data where \
user_id=%d", user_id);
//......
if (pTempDBLink->stRow[i]) {
data._transfer_code = pTempDBLink->stRow[i++];
}
if (pTempDBLink->stRow[i]) {
data._bind_equipment = atoi(pTempDBLink->stRow[i++]);
}
//......
問題代碼段
int CGameServer::setBindStatAndEquipment(int user_id, const std::string& equipment) {
if (connectToLocalDB()) {
log_error("connect to db failed");
return -1;
}
TLIB_DB_LINK *pTempDBLink = &m_stLDBLink;
unsigned int equipment_size = 2 * equipment.size() + 2;
char* equipment_object = (char*)malloc(equipment_size);
mysql_real_escape_string(&pTempDBLink->stMysqlConn.stMysql, (char*)equipment_object,
(char*)equipment.c_str(), equipment.size());
snprintf(m_stLDBLink.sQuery[0], sizeof(m_stLDBLink.sQuery[0]),
"UPDATE account_data SET device_mark='%s', bind_equipment=1, \
transfer_code=null WHERE user_id=%d", equipment_object, user_id);
//......
}
錯誤分析
由於設置了 transfer_code 爲 null,導致在獲取時,由於數據爲 null,導致 bind_equipment 也無法正常獲取到值。
細心的小夥子,想必你也看到了,SET 的時候 transf_code = null 和 bind_equipment 恰好是一組,所以後續獲取一定就出錯了。
爲什麼叫血案
- 我自測未發現;
- 測試也未發現;
最終這個問題被搞到線上環境了
爲什麼?
日本方需求如下:
用戶在 A 設備上獲取“遷移碼”,在 B 設備上使用該遷移碼,A 設備則不能再登錄遊戲,此後該賬號只能在 B 設備上使用。若想切換成其它設備,只需要在 B 設備上再獲取“遷移碼”在其它機器上使用即可
錯誤復現
- 用戶在初始獲取遷移碼時,getAccountInfoByUserId 會被調用,此時會創建新的遷移碼;
- 在另外的設備上使用遷移碼,setBindStatAndEquipment 會被調用;
- 此時邏輯是正確的;
- 但是在新的設備上獲取遷移碼時,getAccountInfoByUserId 會因爲 setBindStatAndEquipment 設置的數據,導致獲取的 bind_equipment 爲 0,導致設備綁定的邏輯失效。