在高负载期间 mysql 中创建了多条记录

Multiple records getting created in mysql during high load

我正在 spring 数据 jpa 应用程序中工作。正如我们所知,通过应用 spring @Transactional 注释,它遵守 ACID 属性。但是我有一个问题。以下是我的解释。

在我当前的应用程序中,给定 post 的业务规则允许用户只回答一个答案,如果他想修改他的答案,他可以编辑一个答案但不能创建另一个答案同样post。因此,对于创建和修改答案,我有两种方法。 1.保存方法和2.编辑方法

我的问题是 w.r.t 保存一个有时在生产中无法按预期工作的答案,即它不满足业务规则并且它为同一 [=30] 的同一用户创建了两个答案=].但是在本地环境中,这个问题永远不会发生。编辑方法对本地环境和生产环境都适用。

以下是我的业务逻辑中save方法的示例代码片段。

@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,本地和生产环境的默认隔离级别都是可重复读取。即

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

注意:所有主键都是自动递增的,生产中有一个 mysql 服务器实例,目前还不是集群。

非常感谢对上述问题有所了解。

重复table阅读:

T1 事务从 table 个答案和 returns 一定数量的行中读取数据。 T1 中的每个后续读取都将具有相同的行。如果另一个并发事务(T2)在 T1 启动后在 table Answers 上插入一行,它(T1)将不知道有一个新行。

因此,一种可能的解决方案是在 Answers table 上添加一个唯一键,使其匹配 findByPostIdAndCreatedByIdAndIsDeleted where 条件。

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

并用 try 包裹保存:

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