場景
相信大家工作中應該都有遇到過表單內包含列表資料
的情況。如下圖,一個出差申請單裡同行人員是可以填寫多行的。
首次儲存是新增場景,直接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答,是的。