SpringBoot 事务并发更新数据丢失问题解决方案 - 乐观锁示例
在 Spring Boot 中,使用 @Transactional 注解来进行事务管理。然而,当多个线程并发更新同一行数据时,可能会发生更新丢失问题,导致数据不一致。
为了解决这个问题,可以使用乐观锁或悲观锁来保证数据的一致性。其中,乐观锁是通过版本号来实现的,而悲观锁是通过加锁来实现的。
下面是一个使用乐观锁来解决并发更新同一行数据导致更新丢失问题的示例代码:
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
@Transactional
public void updateUserName(Long userId, String userName) {
User user = userRepository.findById(userId).orElse(null);
if (user == null) {
throw new RuntimeException('User not found');
}
user.setUserName(userName);
userRepository.save(user);
}
@Transactional
public void updateUserNameWithOptimisticLock(Long userId, String userName) {
User user = userRepository.findById(userId).orElse(null);
if (user == null) {
throw new RuntimeException('User not found');
}
user.setUserName(userName);
userRepository.saveWithOptimisticLock(user);
}
}
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Version
private Long version;
private String userName;
// getters and setters
}
public interface UserRepository extends JpaRepository<User, Long> {
@Modifying
@Query('update User set userName = :#{#user.userName}, version = version + 1 where id = :#{#user.id} and version = :#{#user.version}')
int saveWithOptimisticLock(@Param('user') User user);
}
在上面的代码中,updateUserName 方法是普通的更新用户信息的方法,而 updateUserNameWithOptimisticLock 方法是使用乐观锁来更新用户信息的方法。
在 updateUserNameWithOptimisticLock 方法中,使用了 @Version 注解来指定版本号字段,然后在 UserRepository 中定义了一个 saveWithOptimisticLock 方法,使用了 @Modifying 和 @Query 注解来更新用户信息和版本号,同时判断版本号是否匹配。
这样,当多个线程并发更新同一行数据时,只有一个线程能够成功更新,其他线程会因为版本号不匹配而更新失败,从而保证了数据的一致性。
完整代码:https://github.com/zhaozhiming/springboot-transaction-demo
原文地址: https://www.cveoy.top/t/topic/nCOs 著作权归作者所有。请勿转载和采集!