2010-05-25 65 views
1

我有一個名稱和一個name_count表。因此,當我插入新記錄時,我首先檢查該名稱的最大name_count是多少。然後我插入最大值爲+ 1的記錄。很好的作品...除了使用mysql 5.1和hibernate 3.5之外,默認情況下,讀取並不尊重事務邊界。其中2個相同名稱的插入可能會同時發生,並以相同的name_count結束,這完全是螺絲釘我的應用程序!如何鎖定事務以讀取行然後插入Hibernate?

不幸的是,有一些具體的情況,其中上述實際上是相當普遍的。那麼我該怎麼做?我想我可以做一個悲觀的鎖,我讀的任何行都被鎖定,以便進一步閱讀,直到我提交或回滾我的事務。或者我可以使用版本列進行樂觀鎖定,自動保持嘗試,直到沒有衝突?

對於我的情況,最好的方法是什麼?我如何在Hibernate 3.5和mysql 5.1中指定它?上表非常龐大,經常訪問。

回答

3

這就是爲什麼大多數人使用SEQUENCE來創建唯一的號碼。也就是說,你必須做的是鎖定整個表格(LOCK TABLES)。問題:您必須鎖定全部您需要的表格(即Hibernate可能會觸及的任何內容),否則您將收到錯誤信息。接下來,您必須解鎖表格,並將這兩項操作與其餘交易同步。

我希望這能給你一個想法,爲什麼人們使用序列:他們有一些小的缺陷,如差距,但其他一切都更糟糕。

[編輯]您可以定義一個序列,然後使用本機SQL查詢來獲取下一個值。您可以嘗試定義序列生成器(請參閱the docs),但可能僅在Id字段上允許映射。

重新「200萬個名字」:只要數據庫可以存儲數字,您也可以在其上定義一個序列。

「基於行的鎖定」:您打算鎖定哪一行?最大值的那個?我不確定如果您鎖定它,max()運營商將停止。你可以嘗試的是a trigger。由於觸發器是原子的,所以沒有人可以在運行時插入一行。但觸發器有點難以維護。

+0

我想幾個問題......我如何在休眠中使用序列?我真的可以爲我的情況使用序列嗎?可能會有2億個獨特的名字,我需要一個序列。關於鎖,我不能鎖定整個表,這是一個經常訪問的龐大表......不能在這種情況下使用hibernate/mysql進行基於行的鎖定嗎? – 2010-05-25 08:40:19

+0

你鏈接到的文檔只是自動增加ID ..這將工作,但我必須在我的情況下創建2億張表,不知道這是可行或可取的。 我把我的情況解釋爲調用max(),但實際上我並沒有這麼做,因爲max()對於大表而言速度太慢。相反,我讀取具有相同名稱和最大數量的行(按name_count限制1排序)。所以我想要鎖定那一行。 – 2010-05-25 17:33:29

0

MySQL不支持序列,所以應該模擬它們。這是一個有趣的配方:http://forums.mysql.com/read.php?61,143867,194058#msg-194058

請注意,表類型是MyISAM不尊重事務併發性並返回每個請求的下一個計數器值。

+0

這真的很安全嗎?你如何獲得價值回報? JDBC中是否有這樣的機制? – 2010-05-25 16:29:06

0

如果你想使數據庫無關(避免序列),而不必運行MAX()函數,然後插入嘗試使用GUID來代替:

/** 
* The unique id. This id is generated this object is persited. The id is a 32 character UUID. 
* This gives each entity a completely unqique identifier. This is completely unique across all 
* databases, jvms and entities. 
*/ 
@Id 
@GeneratedValue(generator = "system-uuid") 
@GenericGenerator(name = "system-uuid", strategy = "uuid") 
@Column(length = 32, name = EntityObject.Columns.ID) 
@DocumentId 
private String id; 

這還有一個好處,你的主密鑰在數據庫的每個表中都是唯一的,這對分佈式數據庫非常有利。

我們已經將它用於許多數據庫,我們可以輕鬆地在它們之間移動。

+0

我不需要生成Ids ...我需要增加計數器。 – 2010-05-28 22:52:13

+0

我想我需要仔細閱讀:) – 2010-06-01 09:37:20