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更严格。我对你解释的方式含糊不清。感谢它证实了我的理解。 –