[英]Key problem: Which key strategy should I use in my database?
問題:當我在數據庫中使用自動遞增的主鍵時,這種情況一直發生:
我想存儲一個包含10個項目的訂單。 訂購的商品屬於訂單。 因此,我存儲了訂單,向數據庫詢問最后插入的ID(當涉及到並發時,這很危險,對嗎?),然后存儲帶有外鍵(order_id)的10個項目。
所以我總是要做:
插入 ...
last_inserted_id = db.lastInsertId();
插入...插入...插入...
而且我認為這使我無法在幾乎所有需要外鍵的INSERT情況下使用事務。
所以...這里有一些解決方案,我不知道它們是否真的很好:
A)不要使用auto_increment鍵! 使用密鑰表? 密鑰表將具有兩個字段: table_name, next_key
。 每當我需要一個用於表的鍵來插入新的數據集時,首先我要通過訪問特殊的靜態KeyGenerator類方法來請求next_key。 如果可能的話,這會在一個事務中執行SELECT和UPDATE (這行得通嗎?) 。 當然,我會要求為每個受影響的表提供該服務。 接下來,我可以在一次交易中插入我的整個對象圖,而無需與數據庫打乒乓球,然后我才預先知道鍵。
B)對密鑰使用GUUID / UUID算法嗎? 這些應該在全球范圍內確實是獨一無二的,而且很大。 我的意思是... L_A_R_G_E 。 因此,這些巨大的密鑰將占用大量內存。 索引會很難,對嗎? 數據檢索將是數據庫的痛苦-至少我猜是這樣-整數鍵處理起來要快得多。 另一方面,它們也提供了一定的安全性:訪問者僅通過增加id參數就無法遍歷所有訂單或所有用戶或所有圖片。
C)堅持使用自動增量鍵嗎? 好吧,如果可以的話,上例中所述的交易又如何呢? 我該如何解決? 也許是先插入Ghost行,然后使用一個UPDATE + n INSERT進行事務?
D)還有什么?
存儲訂單時,您需要進行交易以防止僅將一半產品添加到數據庫的情況。
根據您的數據庫和連接器,last-insert-id函數返回的值可能與事務無關。 例如,對於MySQL, mysql_insert_id
返回來自該特定客戶端的最后一個查詢的標識符(不受其他客戶端同時執行的操作的影響)。
您正在使用哪個數據庫?
是的,通常插入一條記錄然后嘗試再次選擇它以查找自動生成的鍵是不好的,特別是如果您使用的是從表查詢中選擇朴素的select max(id)的話。 這是因為一旦兩個線程創建了記錄,max(id)可能實際上不會返回當前線程使用的最后一個id。
避免這種情況的一種方法是在數據庫中創建一個序列。 從您的代碼中選擇sequence.NextValue然后使用該值執行插入(或者您可以編寫更復雜的SQL語句來一次進行選擇和插入)。 序列是原子/線程安全的。
在MySQL中,您可以從執行結果中請求最后插入的ID,我相信它將始終為您提供正確的答案。
Sql Server支持SCOPE_IDENTITY(Transact-SQL) ,它應該解決您的事務問題和並發問題。
我會說堅持auto_increment 。
(假設您正在使用MySQL)
“向數據庫詢問最后插入的ID(在進行並發時很危險,對吧?)”
如果使用MySQL的last_insert_id()函數,則只會看到會話中發生的情況。 所以這很安全。 您提到:
db.last_insert_id()
我不知道它是什么框架或語言,但是我會假設它在后台使用了MySQL的last_insert_id()(如果沒有,那是從工作中獲得的非常無用的數據庫抽象)
“我相信這使我無法在幾乎所有插入情況下使用事務”
我不明白為什么。 請解釋。
這個問題沒有最終和普遍的答案。
添加新記錄時,易於使用自動遞增列 。 要將它們用作同一事務中的外鍵,它們並不是那么簡單。 您需要特定於數據庫的命令來獲取新創建的密鑰。 對於某些數據庫(例如sql server),此技術很常見。
序列似乎更難使用,因為在插入行之前需要先獲得一個鍵,但最后它更易於用作外鍵。 該技術對於某些數據庫(例如oracle)是通用的。
當您使用Hibernate或NHibernate時 ,不建議使用自動遞增鍵,因為不再可能進行某些優化。 建議使用使用附加表的hi-lo算法。
指南很強大,例如,在不同數據庫,系統,斷開連接的方案,導入/導出等之間共享數據時。在許多數據庫中,大多數表僅包含幾百條記錄,因此內存和性能並不是問題。 使用NHibernate時,您會得到一個guid生成器,該生成器會生成順序的guid ,因為當鍵是順序的時,某些數據庫的性能會更好。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.