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

时间:2015-12-21 10:26:39

标签: hibernate concurrency spring-data spring-data-jpa spring-transactions

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

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

我的问题是,保存一个有时在生产中没有按预期工作的答案,即它不满足业务规则,它为同一帖子的同一用户创建了两个答案。但在当地环境中,这个问题永远不会发生编辑方法适用于本地环境和生产环境。

以下是我的业务逻辑中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,在本地和生产环境中,默认隔离级别为REPEATABLE-READ。即。

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

注意:所有主键都是自动递增的,并且生产中有一个mysql服务器实例,它不是现在的集群。

对上述问题有所了解将受到高度赞赏。

1 个答案:

答案 0 :(得分:0)

可重复阅读:

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

因此,可能的解决方案之一可能是在Answers表上添加一个唯一键,以便匹配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)
}