2012-05-08 107 views
1

我最近爲我的Java應用程序編寫了一個會計模塊。MYSQL自動遞增主鍵的實際問題

該模塊是基於MySQL表和InnoDB引擎。 其中一項要求當然是每個發票的「正在運行」ID。 我嘗試使用auto_increment方法來生成ID,並通過使用序列表中,但在兩個I有同樣的問題:當我堅持發票實體如果持久性實體的沖洗到過程中發生錯誤,因爲產生的ID,數據庫中,auto_id增加,導致我的系列發票中出現「漏洞」。 我當然可以放棄這種方法,並指定新發票的最大ID爲先前的發票+ 1,但我認爲這是一個不好的做法。我還可以使用其他什麼方法來確保我的發票系列中沒有漏洞,假設由於某些驗證問題偶爾發票可能無法保存。

+2

一次又一次,人們嘗試用AUTO_INCREMENT東西它並不適合。使用另一個爲您編號的查詢,不要依賴auto_increment。依賴任何類型的順序編號的auto_increment是不好的做法,並且完全錯誤地使用該類型的列。 –

回答

1

春天框架有類似

@Transactional(rollbackFor=RuntimeException.class) 

所以一切都應該被回滾應該有與服務器調用問題。我相信其他框架也有類似的方法。

+0

我真的很喜歡你的方法。我試圖找到我的toplink持久性提供這個電話,但我似乎沒有找到任何...也許你可以幫我找到toplink等價的東西? – Vova

+0

我認爲Toplink是一個持久層,如果我沒有弄錯的話,它相當於hibernate,@Transactional是通過練習放在服務層,這樣如果有多個數據庫調用,比如在你的情況下產生一個序列號然後在表上更新/插入,如果其中一個失敗,則兩個調用都回滾。你的服務層是什麼? –

+0

你是對的,Toplink對我來說和冬眠一樣... – Vova

0

,如果你的MySQL版本> 5.0.2,那麼你可以嘗試使用觸發器將適當增加表列的值。 但是你應該記住,委託給數據庫發票號,這是更相關的業務邏輯的產生,我想,是不是一個非常好的主意,因爲在故障情況下,你可能有一些問題。所以我寧願建議你在代碼中以編程方式生成它。

0

它本身並不是不好的做法,但它可能是值得擁有的不同的「傳統」數字主鍵字段,以保證表的結構完整性,並有另一場發票號碼。

然後,您可以使用不同的邏輯來填充該發票號碼,或者只是簡單的MAX + 1或者通過從密鑰表中查找,以允許針對不同類型的發票使用不同的編號順序。

例如:

CREATE TABLE `keys` (
    `id` INT NOT NULL auto_increment, 
    `type` VARCHAR(10) NOT NULL, 
    `prefix` VARCHAR(10) NOT NULL, 
    `value` INT(10) NOT NULL DEFAULT 0, 
    PRIMARY KEY (`id`) 
); 

INSERT INTO `keys` (`type`, `prefix`) VALUES 
('Sales Receipt', 'SRI'), 
('Sales Invoice', 'SIN'), 
('Sales Refund', 'SRF'); 

然後在你的(僞)碼,你可以做

Database.BeginTransaction; 
NewInvNum = Database.Query("SELECT `value` FROM `keys` WHERE `type` = 'SIN'"); 
MyInvoice.InvoiceNumber = NewInvNum; 
Database.SaveInvoice(MyInvoice); 
Database.Query("UPDATE `keys` SET `value` = {0} WHERE `type` = 'SIN'", NewInvNum+1); 
Database.CommitTransaction; 

交易(或其他一些併發保護反正)是很重要的,所以,當越來越比一張發票正在創建的過程中,他們沒有得到相同的號碼。

+0

你會什麼NetBeans提供的模板**在創建發票的*整個*交易期間有**鎖定密鑰表(或至少該行的那個密鑰)。否則這將不會生成唯一的數字 –

+0

我其實已經有了這樣的表格 - 序列表。它只是我沒有明確地使用它,而是通過將我的生成類型設置爲@TableGeneration。我寧可不使用一個單獨的表鍵,因爲它可以(在還原備份後爲例)使兩個表之間存在一些差異 – Vova

+0

如果你從備份恢復的數據庫位,我想你會比只是一個更大的問題不同步密鑰表。 – Cylindric