spring-boot - Spring Boot JPA save() 方法尝试插入现有行
问题描述
我有一个简单的 kafka 消费者,它收集事件并根据其中的数据插入或更新数据库中的记录 - 表在 ID 列和实体字段中都有唯一的 ID 约束。
当表格预先填充并且不时发生插入时,一切正常。但是,当我截断表并发送具有有限 ID 数量的几千个事件(我在 3k 个事件中执行 50 个唯一 ID)时,会同时处理事件,并且 save() 方法随机失败,并出现唯一约束违规异常。我调试了它,结果很简单。
event1={id = 1 ... //somedata}被拾取,服务方法 saveOrUpdateRecord() 查找 ID=1 的记录,没有找到,插入一条新记录。
event2={id = 1 ... //somedata}几乎同时被拾取,服务方法 saveOrUpdateRecord() 查找 ID=1 的记录,没有找到(前一个是中间插入),尝试插入并因违反约束异常而失败-应该找到此记录并将其与基于我的条件的事件输入合并。
我怎样才能让 saveOrUpdateRecord() 仅在前一个完全执行以防止此类行为时运行?我真的不想用投票大小等来减慢 kafka 消费者的速度,我只想让我的服务一次执行一个事务。
服务方式:
public void saveOrUpdateRecord(Object input) {
Object output = repository.findById(input.getId));
if (output == null) {
repository.save(input);
} else {
mergeRecord(input, output);
repository.save(output);
}
}
方法上的@Transactional注释可以完成这项工作吗?
解决方案
使您的服务线程安全。用这个:
public synchronized void saveOrUpdateRecord(Object input) {
Object output = repository.findById(input.getId));
if (output == null) {
repository.save(input);
} else {
mergeRecord(input, output);
repository.save(output);
}
}
推荐阅读
- python - 将所有列从 int64 转换为 int32
- unix - Unix 有没有办法用单个命令在两台服务器之间发送文件?
- ios - NavigationController 在 push 和 pop 后会切掉阴影吗?
- spring - 如何从 Open API 3 规范全局忽略 Spring Boot 的 API?
- ios - 如何预加载 SCNAudioSource 以防止第一次播放声音时出现延迟?
- angular - AngularFontAwesome 不会显示在通过管道注入 Html 的表格中
- javascript - Firebase 托管:如何生成可在所有页面上使用的全局“地图/数组”,而不是在每个页面加载时解析数据库
- ios - 用排序的图像填充表格
- firebase - 当我使用 Firebase CLI 将数据发送到 Arduino UNO 到 Cloud Firestore 数据库时,我收到 404 错误
- sql - 对数据库表名使用 CONCAT