1

我正在spring數據jpa應用程序中工作。正如我們所知,通過使用spring @Transactional註解它遵守ACID屬性。但是我有一個問題。以下是我的解釋。在高負載下在mysql中創建多條記錄

在我目前的應用程序特定職位的業務規則的允許用戶回答只有一個答案,如果他想改變他的答案,他可以編輯一個答案,但不能創建另一個答案爲同一職位。因此,爲了創建和修改答案,我有兩種方法。 1.保存方法和2.編輯方法

我的問題是保存一個答案,有時不按預期在生產中工作,即它不符合業務規則,它會爲同一個用戶創建兩個答案同一職位。但在當地環境中,這個問題從不會發生。編輯方法適用於本地環境和生產環境。

以下是保存方法,我的業務邏輯的示例代碼段。

@Transactional 
public void save(Answer answer) { 
    Integer postId = answer.getQuestionId(); 
    Answer answerFromDb = answerRepository.findByPostIdAndCreatedByIdAndIsDeleted(postId, answer.getCreatedById(), false); 
    if(null != answerFromDb) { 
     throw new InvalidException("You have already answer for the current post"); 
    } 
    answerRepository.save(answer); 
} 

我們正在使用mysql 5.6,默認隔離級別在本地和生產環境中都是REPEATABLE-READ。即

mysql> SHOW VARIABLES LIKE 'tx_isolation'; 
+---------------+-----------------+ 
| Variable_name | Value   | 
+---------------+-----------------+ 
| tx_isolation | REPEATABLE-READ | 
+---------------+-----------------+ 
1 row in set (0.00 sec) 

注:所有的主鍵是自動遞增並有MySQL服務器的一個實例的製作,它不是一個集羣的現在。

在上述問題上投入一些光將高度讚賞。

回答

1

隨着重複讀:

T1事務讀取從表答案數據,並返回一定的行數。並且T1中的每個後續讀取都將具有相同的行。如果在T1啓動後另一個併發事務(T2)在表Answers上插入一行,則它(T1)不會知道有一個新行。

所以可能的解決方案之一可能是對的答案表添加一個單獨密鑰,它匹配findByPostIdAndCreatedByIdAndIsDeleted WHERE條件。

ALTER TABLE `Answers` ADD UNIQUE `unique_index`(`post_id`, `createdBy_id`, `deleted`); 

,敷保存嘗試:

try { 
    answerRepository.save(answer); 
} catch (DataIntegrityViolationException e) { 
    // ignore (there is already an answer) 
} 
+0

嘿@NikolaB,原本以爲上「帖子ID」,「createdById」和「請將isDeleted」這將阻止從創建一個更記錄添加唯一的約束但有興趣知道爲什麼兩個記錄正在創建隔離級別可重複讀取比read_committed更嚴格。我對你解釋的方式含糊不清。感謝它證實了我的理解。 –