thảo luận [sql] nên dùng constraint hay manual check

hi các thím, em đang có bảng user với column email có constraint là unique và 1 column is enabled để check xem user này đã verify hay chưa
khi insert vào bảng này đầu tiên e sẽ check xem is enabled là true hay false, nếu false thì cho dù email có trùng vẫn cho insert, chỉ khi là true em mới throw exc ra
nhưng cái jpa (em dùng spring boot) under the hood nó đang chạy thì là nó check nếu chưa verify thì nó vẫn chạy câu insert thành ra bị sql nó chửi do dính constraint
vậy em nên dùng giải pháp là bỏ cái unique đó và check bằng tay (tức là nếu trùng email và đã verify rồi thì em mới quăng câu chửi lên, còn k thì vẫn chạy sql)
có bác nào đã từng thiết kế db kiểu này chưa ạ? em xin hướng giải quyết conflict ạ
 

khacau_nguyendinh

Junior Member
Cái ý tưởng ban đầu của bác là bi conflict rồi, nếu là unique thì sao lại cho trùng email. Một khi đã trùng email thì bác ko thể enable unique được nữa. Trường hợp này bác bỏ cái unique rồi check trong code thôi, còn không nếu bác có thể chuyển máy cái user deactivate sang table khác :cautious:
 

vothevinh

Member
Cái này chắc thuộc dạng disable 1 user nhưng vẫn muốn cho user register với email cũ.

Có thể giải quyết bằng cách lúc disable user thì set email thành 1 dạng khác.
vd email đang là john.doe@example.com, lúc delete thì set is_enabled = false đồng thời set email lại thành john.doe@example.com__DELETED_{{TIMESTAMP}}. Bài toán sẽ được giải quyết mà không cần constraint gì nữa.
 

22mario9x

Đã tốn tiền
Cái này chắc thuộc dạng disable 1 user nhưng vẫn muốn cho user register với email cũ.

Có thể giải quyết bằng cách lúc disable user thì set email thành 1 dạng khác.
vd email đang là john.doe@example.com, lúc delete thì set is_enabled = false đồng thời set email lại thành john.doe@example.com__DELETED_{{TIMESTAMP}}. Bài toán sẽ được giải quyết mà không cần constraint gì nữa.
Lúc disable, tại sao không xóa record mà lại set 1 tên khác bác?
 

vothevinh

Member
Vậy tại sao không chuyển sang 1 table khác mà phải để lại trong table cũ? :shame:
Chi tốn công vậy bạn, phải tạo thêm 1 cái table, rồi set trigger (hoặc làm trong app) các kiểu, kết quả cuối cùng cũng như nhau. Nếu sợ user table nhiều row quá thì nói thẳng luôn là nếu bạn có performance issue chỗ table user thì lúc đó app thành công cmnr :))
 

Nipin

Member
dùng partial (unique) index nhé.

không ai tách table trong trường hợp này, phức tạp hơn nhiều.
 

Nipin

Member
:nosebleed: Contraint có vẻ vẫn chưa đủ có case ví dụ email tuideptrai@gmail.comtui+deptrai@gmail.com vẫn gửi chung vào 1 mail
tui+deptrai nó gửi vào tui@gmail.com với label là deptrai chứ có chung với tuideptrai đâu.
chỉ có tui.deptrai thì chung thôi.

p/s: bài toán của bạn chủ thớt trùng hợp vkl, đúng tầm ngày hôm đó tôi thấy có thằng hỏi một câu gần tương tự, nhưng là về soft delete chứ không phải là active mail, cơ mà giải pháp tương tự là dùng partial unique index, ví dụ trong trường hợp của bạn thì thêm cái index dạng thế này

Code:
create unique index users_unique_email_idx on users(email) where is_active is true;
 
Last edited:

tthixk

Member
xét về business logic thì case này hơi lạ. Ko có lí do gì để deactivate user cả, người ta muốn thêm còn ko đc mình lại thấy nó lâu ko vào cho nó cút luôn.

xét về tech thì có nhiều cách làm nhưng tôi toàn làm cả constraint db cả code để check luôn là cách an toàn nhất. Cách thím Nipin chỉ ko áp dụng đc cho MySQL, nếu làm MySQL thì add unique trên 2 cột email và active luôn, khi nó inactive = null và active = true. Ko có giá trị false.
 

Nipin

Member
xét về business logic thì case này hơi lạ. Ko có lí do gì để deactivate user cả, người ta muốn thêm còn ko đc mình lại thấy nó lâu ko vào cho nó cút luôn.

xét về tech thì có nhiều cách làm nhưng tôi toàn làm cả constraint db cả code để check luôn là cách an toàn nhất. Cách thím Nipin chỉ ko áp dụng đc cho MySQL, nếu làm MySQL thì add unique trên 2 cột email và active luôn, khi nó inactive = null và active = true. Ko có giá trị false.
mấy năm gần đây nói thật là không có lý do gì để dùng mysql nữa rồi :/
 

XH-CT

Member
chỉnh lại cái column enabled kia cho nullable,
set lại state cho nó vd như enabled = 1 là active, enabled = null là inactive
rồi set unique(email, enabled), vậy trong trường hợp enabled = null nó vẫn ko tính là unique, vẫn insert tiếp 1 row vào nữa

P/s: mysql nhé, còn các db khác thì ko chắc
 
Top