該數據庫是否將眼光夠安全嗎?
不,這需要一點時間來解釋。
讓我們從所有這些限制開始。過度熱心地使用色譜柱限制是一個非常普遍的問題。
這些限制的工作方式常常被誤解,例如您詢問安全問題,或者您可能認爲您節省了空間。真正的問題是它難以編碼對軟件的其餘部分如何進入數據庫的不必要限制,並且您的限制非常吝嗇。
您問這是否使表更安全。列限制並不是關於安全性的,儘管我猜他們理論上不讓某人填滿磁盤,但這並不是你擁有的限制。
例如,您的密碼限制爲16個字符。這不是數據庫應該做的決定,而是安全考慮。當您稍後查看密碼安全性時,您會發現16個字符的密碼幾乎不夠用。你想要更像64或128的東西,這將需要昂貴的alter table
。
更重要的是,您將存儲密碼清晰。這是一個很大的安全問題。
那麼你有電子郵件(大概電子郵件地址)設置爲320個字符?!這是一個電子郵件地址!但用戶只能得到16個名字?
一個常見的誤解是,這些限制減少了磁盤使用量。他們不。 varchar
將只存儲該行所需的數量。 age INT(3)
不使用比age INT
更少的空間,它是固定大小。
好的,它可以確保你的約會網站上沒有任何12938歲的人
甚至沒有這樣做。這只是多少字段得到顯示,這是肯定不是應該在您的架構中的東西。 MySQL做了一些奇怪的事情。
你可以使用一個unsigned tinyint
存儲從0到255的1個字節......但一旦你擔心個別字節它會變得愚蠢。這一切都沒有實際意義,根本不存儲他們的年齡。儲存他們的生日。因爲人們變老了。
關於使用限制的錯誤方法,有什麼正確的方法?
限制是爲了執行數據完整性(和技術限制,請參閱評論)。就是這樣。您希望創建一個足夠靈活的模式來支持您的應用程序希望成爲的任何應用程序,同時還可以確保數據是它所說的數據,而無需不斷地再次猜測它。
一個更好的模式可能是這樣的:
create table members(
id primary key auto_increment,
username varchar(64) unique,
password_hash varchar(128),
email varchar(64) unique,
mobile varchar(32),
birthday datetime,
location integer references(locations),
index(birthday)
)
你的表是缺少一個主鍵,這是一個很大的問題。用戶名可以改變,並且你不希望引用該用戶的所有內容都會中斷。相反,使用一個簡單的自動遞增整數。 「但我不會讓用戶改變他們的名字!」是的,請記住我剛纔提到的關於軟件硬編碼限制的數據模型?多年來,您如何構建您的架構具有影響力。
本來我把所有的限制從領域中刪除,並將它們切換到無限制text
。他們都沒有一個令人信服的限制理由。除非你有很好的理由,否則只需使用text
或varchar
。限制在數據模型中處理,可由程序員和設計人員更改。 A text
或varchar
字段只會使用盡可能多的空間。
......但是@PaulSpiegel在評論中指出MySQL's has limitations on how big a field it will index。我習慣於沒有這種限制的Postgres。所以我將它們轉換爲varchar
,並挑選了大量限制。技術限制可能是使用限制的理由。
username
(不user
因爲這可以參考整個用戶,而不僅僅是他們的名字)和email
已標記unique
。這是關於數據完整性的,你不希望兩個人使用相同的用戶名,並且你想要確保每個帳戶都有一個單一的聯繫點(你可能會說這是把行爲放在數據庫中,你可能是對的,但刪除唯一索引比添加索引更容易)。
然後我們來看到明顯的安全問題。 從不存儲密碼!永遠。永遠永遠。相反,存儲密碼的散列。如果您不知道我在說什麼,請立即停止並閱讀Salted Password Hashing - Doing it Right。
代替存儲age
,我們將它們的birthday
作爲datetime
存儲。存儲用戶的年齡並不是展望未來,明年會發生什麼?隨着他們的生日,你可以計算他們的年齡,甚至給他們生日禮物!通過將其存儲爲datetime
,您可以使用MySQL's confusing date and time functions對其進行各種日期計算。
你問及如何處理位置。位置可能意味着很多事情,並且可能會變得非常複雜。這不是您現在需要做出的決定,因此最好做到這一點,以便稍後可以對其進行擴展和更改。把它放在自己的表中,並用外鍵引用它。我們稍後再回來,這是整個觀點。
最後,索引。您的磁盤空間不需要太過簡單,只需要存儲用戶名的前6個字符!通過用戶名查看用戶將非常非常常見,並給它一個完整的索引。但我們不需要一個,聲明一個列unique
給它一個索引。
索引可以提高查詢性能,但它們也可以佔用磁盤空間並降低插入速度。而不是事先對索引瘋狂,等到你看到你將要做什麼查詢以及表現如何。我輸入的唯一明確索引是birthday
,因爲我非常確定約會網站正在按年齡進行限制。
這裏缺少的是您的數據模型。這是數據之上的代碼,例如Member類。它將處理成員可以執行的所有事情,包括訪問數據庫以及限制應該是什麼。模型是觸及數據庫的唯一東西,其餘的代碼調用模型上的方法。這可以讓數據庫更改而不用擔心影響整個項目。
這就是所謂的模型 - 視圖 - 控制器或MVC,這是數據驅動應用程序編碼的基本方式。 Ruby On Rails就是一個很好的例子。看看MVC。
好的,位置。我們已經制作了location
自己的表格。這使得它成爲一個抽象的概念,而不是members
表中的某些硬編碼字段。
位置會變得非常複雜。所以我們會保持簡單。從其他用戶希望知道的一些基本信息開始:誰在附近。最低限度是郵政編碼和國家,你可以從中找出很多。你可能也想保持城市和州,因爲這是人們想要找到人的另一種方式。
create table locations (
id integer primary key,
city text,
province text,
country text,
postal_code text
);
製作位置模型來封裝和管理位置數據。
現在,您可以隨心所欲地管理位置數據,而不會搞亂成員表。你可以做什麼@PaulSpiegel建議,並建立一個所有國家及其名稱的表格,以便在其他代碼中引用並確保它們使用的是真實的國家(數據完整性)。您可以使用他們的郵政編碼來獲取他們的城市和省份。您可以存儲GPS數據,如果他們會給你的。
所以,唔......如果你剛開始這可能會似乎勢不可擋。數據建模很複雜。這不一定很難,只需要考慮很多移動部件和事物,以便您的應用程序不受您的架構限制。您可能必須使用過於簡單的模式來製作一些真正理解的應用程序。
讓我們看看我能不能熬下來。
- 有一個簡單的主鍵。
- 避免列限制。
- 永遠不要將密碼存儲在明文中。
- 將複雜性推送到自己的表中。
- 存儲您可以從(生日,郵政編碼)中派生更多的東西。
您錯過了提問:-) –
@PaulSpiegel謝謝!完全忘記:) – smithster
「位置」只是國家,還是更詳細的位置? –