欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Golang開發(fā)之字符串與切片問題踩坑記錄

 更新時(shí)間:2023年07月31日 09:12:20   作者:寫代碼的lorre  
字符串和切片,都是golang常用的兩種內(nèi)置數(shù)據(jù)類型,最近在日常工作中,遇到了一個(gè)字符串切片導(dǎo)致的問題,記錄一下排查問題的過程,避免后續(xù)在這種場景上踩坑

背景

在項(xiàng)目中,我們使用mysql來存儲數(shù)據(jù)信息,其中l(wèi)abel表記錄了標(biāo)簽相關(guān)的信息。表結(jié)構(gòu)如下:

CREATE TABLE `label` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
  `name` varchar(190) COLLATE utf8mb4_unicode_ci DEFAULT 'label name',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uniq_n` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=7050965 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='label'

其中name字段為varchar類型,190代表字符長度,并且是唯一索引

為什么name字段設(shè)置最大字符長度為190?

name是varchar類型,并且是唯一索引。mysql規(guī)定varchar類型為索引時(shí),最大長度為767字節(jié)

name字段的編碼格式為utf8mb4_unicode_ci,一個(gè)字符最多用4個(gè)字節(jié)來表示,767 / 4 = 191.75,所以只需限制最大字符長度小于191.75即可,項(xiàng)目里取190作為限制

業(yè)務(wù)代碼邏輯很簡單,主要有兩步:

  • 依據(jù)name查詢label表,如果查詢到了label信息,則直接返回
  • 如果沒有查詢到label信息,則嘗試創(chuàng)建label信息

偽代碼:

const (
   // 最大字符長度
   LabelNameLengthLimit = 190
)
func GetOrCreateLabel(ctx context.Context, name string) (label dao.Label, err error) {
   var err error
   // 依據(jù)name查詢label信息
   label, err = db_reader.GetLabel(name)
   // 沒有找到對應(yīng)的label信息,且字符串長度超過190,則切片后再次查詢
   if IsRecordNotFoundError(err) && len(name) > LabelNameLengthLimit {
      label, err = db_reader.GetLabel(name[:LabelNameLengthLimit])
   }
   // 還是報(bào)錯(cuò),則嘗試創(chuàng)建label信息
   if err != nil {
      label.Name = name
      err = db_writer.CreateLabel(ctx, &label)
      // 報(bào)唯一鍵沖突錯(cuò)誤,可能是由于并發(fā)創(chuàng)建導(dǎo)致的問題,再次兜底進(jìn)行查詢
      if IsKeyConflict(err) {
         label, err = db_reader.GetLabel(ctx, name)
         if err != nil {
            return label, err
         }
      }
      if err != nil {
         return label, err
      }
   }
   return label, nil
}

問題

部分case,首次執(zhí)行業(yè)務(wù)代碼成功,后續(xù)執(zhí)行業(yè)務(wù)代碼一直報(bào)錯(cuò)

case1:

labelName := "? 2015 Charanga Sí o Ké - Chema Mu?oz, Perfecto Artola, Pablo Guerrero, Antonio Flores, Los Gipsy King, Chambao, Adele, La Pegatina, El Chaval de la Peca, Los Manolos ? 2015 Charanga Sí o Ké - Sones de Rumba"

執(zhí)行:

  • 首次執(zhí)行業(yè)務(wù)代碼,執(zhí)行成功
  • 后續(xù)執(zhí)行業(yè)務(wù)代碼,22行穩(wěn)定復(fù)現(xiàn)報(bào)錯(cuò)

分析

后續(xù)執(zhí)行業(yè)務(wù)代碼時(shí)

  • 依據(jù)name,一直查詢不到對應(yīng)的label信息,err報(bào)錯(cuò)RecordNotFoundError
  • 依據(jù)name[:LabelNameLengthLimit],一直查詢不到對應(yīng)的label信息,err報(bào)錯(cuò)RecordNotFoundError
var err error
// 依據(jù)name查詢label信息
label, err = db_reader.GetLabel(name)
// 沒有找到對應(yīng)的label信息,且字符串長度超過190,則切片后再次查詢
if IsRecordNotFoundError(err) && len(name) > LabelNameLengthLimit {
   label, err = db_reader.GetLabel(name[:LabelNameLengthLimit])
}

err != nil時(shí),嘗試創(chuàng)建label信息,此時(shí)報(bào)唯一鍵沖突錯(cuò)誤

線上可能是并發(fā)創(chuàng)建導(dǎo)致的唯一鍵沖突,兜底查詢一次,此時(shí)查詢還是報(bào)錯(cuò)RecordNotFoundError

err = db_writer.CreateLabel(ctx, &label)
// 報(bào)唯一鍵沖突錯(cuò)誤,可能是由于并發(fā)創(chuàng)建導(dǎo)致的問題,再次兜底進(jìn)行查詢
if IsKeyConflict(err) {
   label, err = db_reader.GetLabel(ctx, name)
   if err != nil {
      return label, err
   }
}

由于字符長度超過了190,定位到主要的問題是:依據(jù)切片后name[:LabelNameLengthLimit]查詢時(shí),沒有查詢到結(jié)果,但是依據(jù)name去創(chuàng)建label信息時(shí),報(bào)唯一鍵沖突,說明查詢的值和實(shí)際存儲的值不一致

golang string底層實(shí)現(xiàn)go/src/reflect/value.go

// StringHeader is the runtime representation of a string.
// It cannot be used safely or portably and its representation may
// change in a later release.
// Moreover, the Data field is not sufficient to guarantee the data
// it references will not be garbage collected, so programs must keep
// a separate, correctly typed pointer to the underlying data.
type StringHeader struct {
   Data uintptr
   Len  int
}

其中:

  • Data 指向底層的[]byte的首地址,string底層其實(shí)是[]byte
  • Len 代表字節(jié)切片的長度,避免多次獲取字符串長度時(shí),重復(fù)計(jì)算
  • 內(nèi)置函數(shù)len(string),獲取的是字符串字節(jié)長度
  • 對字符串進(jìn)行切片labelName[:LabelNameLengthLimit],是按照字節(jié)數(shù)進(jìn)行切片

所以問題就是:查詢和存儲時(shí),截取字符串的標(biāo)準(zhǔn)不一樣

  • 當(dāng)字符串字符長度超過190時(shí),查詢時(shí)是按照字節(jié)進(jìn)行截取
  • 當(dāng)字符串字符長度超過190時(shí),存儲時(shí)是按照字符進(jìn)行截取

測試代碼:

labelName := "? 2015 Charanga Sí o Ké - Chema Mu?oz, Perfecto Artola, Pablo Guerrero, Antonio Flores, Los Gipsy King, Chambao, Adele, La Pegatina, El Chaval de la Peca, Los Manolos ? 2015 Charanga Sí o Ké - Sones de Rumba"
fmt.Println("原字符串內(nèi)容:", labelName)
fmt.Println("字節(jié)長度:", len(labelName))
fmt.Println("按照字節(jié)截取內(nèi)容:", labelName[:LabelNameLengthLimit])
fmt.Println("字符長度:", len([]rune(labelName)))
fmt.Println("按照字符截取內(nèi)容:", string([]rune(labelName)[:LabelNameLengthLimit]))

輸出:

原字符串內(nèi)容: © 2015 Charanga Sí o Ké - Chema Muñoz, Perfecto Artola, Pablo Guerrero, Antonio Flores, Los Gipsy King, Chambao, Adele, La Pegatina, El Chaval de la Peca, Los Manolos © 2015 Charanga Sí o Ké - Sones de Rumba
字節(jié)長度: 214
按照字節(jié)截取內(nèi)容: © 2015 Charanga Sí o Ké - Chema Muñoz, Perfecto Artola, Pablo Guerrero, Antonio Flores, Los Gipsy King, Chambao, Adele, La Pegatina, El Chaval de la Peca, Los Manolos © 2015 Charanga S?
字符長度: 207
按照字符截取內(nèi)容: © 2015 Charanga Sí o Ké - Chema Muñoz, Perfecto Artola, Pablo Guerrero, Antonio Flores, Los Gipsy King, Chambao, Adele, La Pegatina, El Chaval de la Peca, Los Manolos © 2015 Charanga Sí o Ké

解決

解決方案:

  • 先把string轉(zhuǎn)rune切片,使用字符切片來表示字符串
  • 判斷rune切片長度是否超過限制,超過則依據(jù)字符長度進(jìn)行切片
const (
   // 最大字符長度
   LabelNameLengthLimit = 190
)
func GetOrCreateLabel(ctx context.Context, name string) (label dao.Label, err error) {
   if rs := []rune(name); len(rs) > LabelNameLengthLimit {
      name = string(rs[:LabelNameLengthLimit])
   }
   var err error
   // 依據(jù)name查詢label信息
   label, err = db_reader.GetLabel(name)
   // 還是報(bào)錯(cuò),則嘗試創(chuàng)建label信息
   if err != nil {
      label.Name = name
      err = db_writer.CreateLabel(ctx, &label)
      // 報(bào)唯一鍵沖突錯(cuò)誤,可能是由于并發(fā)創(chuàng)建導(dǎo)致的問題,再次兜底進(jìn)行查詢
      if IsKeyConflict(err) {
         label, err = db_reader.GetLabel(ctx, name)
         if err != nil {
            return label, err
         }
      }
      if err != nil {
         return label, err
      }
   }
   return label, nil
}

到此這篇關(guān)于Golang開發(fā)之字符串與切片問題踩坑記錄的文章就介紹到這了,更多相關(guān)Go字符串切片內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Go語言中JWT的創(chuàng)建和解析操作詳解

    Go語言中JWT的創(chuàng)建和解析操作詳解

    JWT的全名是Json web token,是為了在網(wǎng)絡(luò)應(yīng)用環(huán)境間傳遞聲明而執(zhí)行的一種基于JSON的開放標(biāo)準(zhǔn),這篇文章主要介紹了在Go語言中JWT的創(chuàng)建和解析操作,感興趣的同學(xué)可以參考下文
    2023-05-05
  • Go語言連接Oracle數(shù)據(jù)庫的方法

    Go語言連接Oracle數(shù)據(jù)庫的方法

    這篇文章主要介紹了Go語言連接Oracle數(shù)據(jù)庫的方法,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-02-02
  • Go語言七篇入門教程三函數(shù)方法及接口

    Go語言七篇入門教程三函數(shù)方法及接口

    這篇文章主要為大家介紹了Go語言的函數(shù)方法及接口的示例詳解,本文是Go語言七篇入門系列文章,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步
    2021-11-11
  • 一文探索Go語言中的內(nèi)存對齊

    一文探索Go語言中的內(nèi)存對齊

    在 Go 語言中,內(nèi)存對齊是一個(gè)經(jīng)常被忽略但非常重要的概念,本文將通過一個(gè)簡單的例子來探討 Go 語言中的內(nèi)存對齊機(jī)制,感興趣的可以了解下
    2024-11-11
  • golang中sync.Once只執(zhí)行一次的原理解析

    golang中sync.Once只執(zhí)行一次的原理解析

    在某些場景下,我們希望某個(gè)操作或者函數(shù)僅被執(zhí)行一次,比如單例模式的初始化,一些資源配置的加載等,golang中的sync.Once就實(shí)現(xiàn)了這個(gè)功能,本文就和大家一起解析sync.Once只執(zhí)行一次的原理,需要的朋友可以參考下
    2023-09-09
  • Go語言利用time.After實(shí)現(xiàn)超時(shí)控制的方法詳解

    Go語言利用time.After實(shí)現(xiàn)超時(shí)控制的方法詳解

    最近在學(xué)習(xí)golang,所以下面這篇文章主要給大家介紹了關(guān)于Go語言利用time.After實(shí)現(xiàn)超時(shí)控制的相關(guān)資料,文中通過示例介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-08-08
  • go-cqhttp權(quán)限管理系統(tǒng)的實(shí)現(xiàn)代碼

    go-cqhttp權(quán)限管理系統(tǒng)的實(shí)現(xiàn)代碼

    這篇文章主要介紹了go-cqhttp權(quán)限管理,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-09-09
  • 在Go中創(chuàng)建隨機(jī)的安全密碼

    在Go中創(chuàng)建隨機(jī)的安全密碼

    今天小編就為大家分享一篇關(guān)于在Go中創(chuàng)建隨機(jī)的安全密碼,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧
    2018-10-10
  • GO語言中embed簡介

    GO語言中embed簡介

    這篇文章主要介紹了GO語言中embed簡介的相關(guān)資料,需要的朋友可以參考下
    2023-08-08
  • 如何在golang中使用shopspring/decimal來處理精度問題

    如何在golang中使用shopspring/decimal來處理精度問題

    本文主要介紹了如何在golang中使用shopspring/decimal來處理精度問題,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-04-04

最新評論