Spring Boot使用Jpa Repository更新登录用户数据时新增记录问题
问题原因分析
- save操作对象不匹配:你修改了
currentuser对象的余额属性,但最终调用repo.save()时传入的是未做任何赋值的logindata对象,该对象没有携带已登录用户的主键标识,JPA的save方法识别到实体主键为空时,就会执行插入操作而非更新操作,因此会生成仅包含余额字段的新记录。 - 认证对象与数据库实体混淆:
CustomUserDetails是Spring Security的认证信息载体,不是和数据库映射的实体类对象,直接修改它的属性不会关联到数据库中的对应记录,即便直接保存currentuser也无法完成正确更新。
修复方案
1. 调整接口逻辑,先查询对应实体再更新
你需要先通过currentuser中存储的唯一标识(比如用户名、用户ID)查询出数据库中对应的用户实体,修改后再保存:
@PostMapping("/Balnce_add") public String GoesUp(@AuthenticationPrincipal CustomUserDetails currentuser) throws IOException { // 按用户名查询数据库中对应的用户实体,替换为你实际的查询方法 UserEntity loginUser = repo.findByUsername(currentuser.getUsername()); // 修改余额 int newBalance = loginUser.getBalance() + 10; loginUser.setBalance(newBalance); // 保存携带主键的实体,会执行更新操作 repo.save(loginUser); System.out.println("cool ==> "+ loginUser.getBalance()); return "user"; }
2. 补充Repository的查询方法
确认你的Repository接口中已经定义了对应的查询方法,示例如下:
public interface UserRepository extends JpaRepository<UserEntity, Long> { // 方法名要和实体类的用户名字段对应,如字段为userId就改成findByUserId UserEntity findByUsername(String username); }
优化建议
如果要避免并发场景下的余额覆盖问题,也可以直接写增量更新的JPQL语句,省略查询步骤:
// 在Repository中新增方法 @Modifying @Transactional @Query("update UserEntity u set u.balance = u.balance + 10 where u.username = :username") int incrementBalance(@Param("username") String username);
接口中直接调用该方法即可完成更新,性能更高且并发安全性更好。
内容的提问来源于stack exchange,提问作者LEGENDRYzZzZ
相关产品推荐
相关产品推荐

