不好的程式設計習慣之列表儲存

JinCeon發表於2023-03-05

場景

相信大家工作中應該都有遇到過表單內包含列表資料的情況。如下圖,一個出差申請單裡同行人員是可以填寫多行的。
d6139fc56e415b11bd72b0e73b436f1.png
首次儲存是新增場景,直接insert即可。
如果允許對錶單進行編輯修改,不少程式設計師的做法是先將資料庫裡的資料全部刪除後,再重新insert。
例如,首次儲存後資料庫的資料是

id姓名
1張三
2李四

再次編輯時,即使什麼都沒修改,直接點選儲存。由於程式碼裡是先刪除再插入,那麼id會重新生成。資料庫裡的資料最終會變成

id姓名
3張三
4李四

明白我意思了嗎?雖然介面上使用者看到的還是張三李四,但是資料庫裡的id已經變了。

問題

小夥伴反問我,雖然id是變了,但是使用者看到的資料沒變呀,業務含義也沒有變呀,業務上又不關注它的id,有什麼問題呢?
真的沒有問題嗎?
考慮下這個場景。假設這張單有2個人在同時操作,
小A把張三刪除了,同時新增了王五
小B把李四刪除了,同時新增了趙六
刪除再插入的實現,那麼最終的結果受小A和小B的處理順序影響,後者會把前者的操作給覆蓋掉,資料庫裡的資料最終要麼是小A提交的李四+王五,要麼是小B提交的張三+趙六
但是在業務含義上,在小A和小B的視角里,他們會很困惑。
小A會想,我明明新增了王五,是沒有儲存成功呢?還是誰把我的資料刪了?
小B也會覺得冤枉,我可從來沒有看見過王五,更別說刪除王五了。

解決

正確的方式是什麼呢?
新增、編輯、刪除分開處理。
我剛提出的時候,小夥伴大叫,那要從資料庫裡取出來逐個對比,好麻煩呀。
我提了2個點。
首先,業務需要的是正確的答案。你一秒就計算出了338483893 * 95858328 = 3 ,確實很快,但結果是錯的呀。你寫了個簡單的方案,卻得不到業務想要的結果,簡單又有什麼意義呢?
其次,誰說沒有簡單的方案?

參考實現

還以小A的操作為例,假設初始資料是

id姓名
1張三
2李四

小A刪除了張三,新增了王五。那麼在介面傳遞的時候,客戶端向伺服器段傳送的資料可以是

[
  {id: 1, name: '張三', deleted: true},
  {id: 2, name: '李四', deleted: false},
  {id: null, name: '王五', deleted: false},
]

那麼伺服器在收到請求後,分別處理刪除、新增、刪除

for(UserDto userDto: users){
    if(Boolean.True.equals(userDto.deleted)){
       // 刪除
       delete(userDto);
    }else if(userDto.getId() == null){
       // 新增
       insert(userDto);
    }else{
       // 更新
       update(userDto);
    }
}

別糾結我在for迴圈裡運算元據庫,也別糾結我直接把dto傳給delete、insert等,本文的重點不在這。

結果

回到本文開頭的例子,小A和小B在各自點選儲存後,看到介面上的資料從張三+李四變成了王五+趙六,但是卻不會對他們造成困惑。
比如對小A來說,張三刪除成功了,王五新增成功了。
至於消失的李四和突然出現的趙六,小A一問,是你刪掉李四和新增趙六了?小B答,是的。

相關文章