Algorithm
139. 單詞拆分
func wordBreak(s string, wordDict []string) bool {
wordDictMap := make(map[string]bool)
for _, v := range wordDict {
wordDictMap[v] = true
}
results := make([]bool, len(s)+1)
results[0] = true
for i := 1; i <= len(s); i++ {
results[i] = false
for j := 0; j < i; j++ {
_, ok := wordDictMap[s[j:i]]
if results[j] && ok {
results[i] = true
break
}
}
}
return results[len(s)]
}
Review
Write a Web Service with Go Plug-Ins
文章介紹了go-plugin的入門使用方法,可用于即插即用的功能。
TIP
最近在項(xiàng)目開發(fā)中遇到一個(gè)需求:
- 前端頁面有多行操作記錄,這些記錄有先后順序的概念
- 可以對這些操作記錄進(jìn)行增刪改查功能。
- 對這些操作記錄,還需要支持拖拽改變先后順序的操作。
增刪改查都還好說,數(shù)據(jù)庫中對對應(yīng)的row進(jìn)行create、delete、update就可以了,難點(diǎn)在于如何實(shí)現(xiàn)“記錄有先后順序”這個(gè)需求。假設(shè)原來有2行操作記錄:
| 主鍵ID | 記錄內(nèi)容 | 是否刪除 |
|---|---|---|
| 1 | 內(nèi)容1 | false |
| 2 | 內(nèi)容2 | false |
現(xiàn)在如果要將記錄2拖動到記錄1的前面,代碼和sql要如何編寫呢?經(jīng)過查閱資料,想到一個(gè)鏈表的結(jié)局方案。
簡單來說就是在數(shù)據(jù)庫中增加一個(gè)next_record_id字段,用來標(biāo)識這個(gè)節(jié)點(diǎn)指向的下一個(gè)節(jié)點(diǎn),然后再在代碼中通過拼接鏈表的方式將所有record進(jìn)行排序再輸出給前端。修改后的數(shù)據(jù)庫設(shè)計(jì)如下:
| 主鍵ID | 記錄內(nèi)容 | 是否刪除 | next_record_id |
|---|---|---|---|
| 1 | 內(nèi)容1 | false | 2 |
| 2 | 內(nèi)容2 | false | -1 |
這里需要注意的是我們需要用-1來代表這一行數(shù)據(jù)為尾節(jié)點(diǎn)。
引入了next_record_id字段之后,對增刪改都增加了一定并發(fā)復(fù)雜度,原來增加一個(gè)節(jié)點(diǎn)只需要寫一個(gè)create sql就好了,但是現(xiàn)在需要如下操作:
- 前端調(diào)用后端add接口,傳入需要增加的信息,同時(shí)需要告訴后端pre_record_id,也就是目前前端上認(rèn)為的尾節(jié)點(diǎn)。
- 通過for update將原本的尾巴節(jié)點(diǎn)節(jié)點(diǎn)1鎖住,避免其他并發(fā)操作修改節(jié)點(diǎn)1。同時(shí)對節(jié)點(diǎn)1加鎖的for update語句需要在where 條件中加上 next_record_id=-1的樂觀鎖來避免節(jié)點(diǎn)1已經(jīng)被其他用戶update過了。完整sql應(yīng)該是:select ID from xxx where next_record_id=-1 for update.
- 執(zhí)行create sql增加一個(gè)新的尾巴節(jié)點(diǎn)節(jié)點(diǎn)2。
- update原本的尾部節(jié)點(diǎn)1的next_record_id字段指向新增的節(jié)點(diǎn)2。
- 需要特別注意的是以上所有操作需要在一個(gè)數(shù)據(jù)庫事務(wù)里面。
其他的刪改拖拽操作也是一樣的:老節(jié)點(diǎn)加鎖、對需要更新的節(jié)點(diǎn)進(jìn)行更新、修改相關(guān)record的next_record_id。
Share
學(xué)習(xí)mysql 45講
29 | 如何判斷一個(gè)數(shù)據(jù)庫是不是出問題了?
select 1判斷
定期執(zhí)行select 1并關(guān)注是否成功返回。本方法只能說明這個(gè)庫的進(jìn)程還在, 并不能說明主庫沒問題。
查表判斷
在系統(tǒng)庫(mysql庫) 里創(chuàng)建一個(gè)表, 比如命名為health_check, 里面只放一行數(shù)據(jù), 然后定期執(zhí)行,通過更新語句是否能夠成功來判斷數(shù)據(jù)庫是否有問題。
更新事務(wù)要寫binlog, 而一旦binlog所在磁盤的空間占用率達(dá)到100%, 那么所有的更新語句和事務(wù)提交的commit語句就都會被堵住。 但是, 系統(tǒng)這時(shí)候還是可以正常讀數(shù)據(jù)的。因此這個(gè)方案發(fā)現(xiàn)不了磁盤堵塞問題。
更新判斷
常見做法是放一個(gè)timestamp字段, 用來表示最后一次執(zhí)行檢測的時(shí)間。 這條更新語句類似于:update mysql.health_check set t_modified=now(); 通過判斷更新語句是否成功來判斷數(shù)據(jù)庫是否存在問題。
這個(gè)方案如果存在雙M架構(gòu)的話,主庫A和備庫B都用相同的更新命令, 就可能出現(xiàn)行沖突, 也就是可能會導(dǎo)致主備同步停止。為了讓主備之間的更新不產(chǎn)生沖突, 我們可以在mysql.health_check表上存入多行數(shù)據(jù), 并用A、 B的server_id做主鍵。
內(nèi)部統(tǒng)計(jì)
MySQL 5.6版本以后提供的performance_schema庫, 就在file_summary_by_event_name表里統(tǒng)計(jì)了每次IO請求的時(shí)間。我們可以通過打開對應(yīng)的檢測開關(guān)來記錄IO請求時(shí)間,從而及時(shí)發(fā)現(xiàn)暴露問題。