我正在使用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服务器实例,它不是现在的集群。
对上述问题有所了解将受到高度赞赏。
答案 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)
}