Spring Boot购物车无法保存Item列表至数据库问题排查
问题:Spring Boot中Cart的Item列表无法保存到数据库
开发首个Spring Boot应用,需求是向购物车(Cart)添加Item列表,但Item列表无法保存到数据库。添加test字符串字段测试,该字段可正常更新,说明问题仅针对Item列表。控制台日志显示Item已添加到Cart对象,但数据库无对应记录。
相关代码
Account类
@Getter @Setter @NoArgsConstructor @AllArgsConstructor @Entity public class Account { @GeneratedValue @Id private Long id; @Column(nullable = false) private String name; @Column(unique = true, nullable = false) private String email; @Column(length = 1000, nullable = false) private String password; private LocalDateTime createdOn; { createdOn = LocalDateTime.now(); } private LocalDateTime lastUpdateOn; @JsonManagedReference @OneToOne(cascade = CascadeType.PERSIST) private Cart cart; // Constructor for Seeder public Account(String name, String email, String password) { this.cart = new Cart(); this.name = name; this.email = email; this.password = password; this.createdOn = LocalDateTime.now(); } }
Cart类
@Getter @Setter @AllArgsConstructor @NoArgsConstructor @Entity public class Cart { @GeneratedValue @Id private Long id; @JsonBackReference @OneToOne private Account account; private LocalDateTime createdOn; { createdOn = LocalDateTime.now(); } private LocalDateTime lastUpdateOn; @JsonManagedReference @OneToMany(mappedBy = "cart") private List<Item> items; private String test; }
Item类
@Getter @Setter @NoArgsConstructor @AllArgsConstructor @Entity public class Item { @GeneratedValue @Id private Long id; private LocalDateTime createdOn; { createdOn = LocalDateTime.now(); } private LocalDateTime lastUpdateOn; @JsonBackReference @ManyToOne @JoinColumn(name = "cart_id") private Cart cart; @ManyToOne @JoinColumn(name = "game_id") private Game game; private Integer quantity; public Item(Game game, Integer quantity) { this.game = game; this.quantity = quantity; } }
Cart控制器
@RequestMapping("/carts") @RestController public class CartController { @Autowired CartService cartService; @GetMapping public List<Cart> getAllCarts() { return cartService.getCarts(); } @GetMapping("/{id}") public Cart getCartById(@PathVariable Long id) { return cartService.getCartById(id); } @PutMapping("/add/{id}") public ResponseEntity<Cart> addItemsToCart(@PathVariable Long id, @RequestBody List<Item> items) { if (cartService.updateCartContents(id, items)) { return ResponseEntity.status(HttpStatus.OK).build(); } else { return ResponseEntity.status(HttpStatus.CONFLICT).build(); } } @DeleteMapping("/{id}") public ResponseEntity<Cart> deleteCart(@PathVariable Long id) { if (cartService.deleteCart(id)) { return ResponseEntity.status(HttpStatus.OK).build(); } else { return ResponseEntity.status(HttpStatus.CONFLICT).build(); } } @PutMapping("clearcart/{id}") public ResponseEntity<Cart> clearCart(@PathVariable Long id){ if (cartService.clearCart(id)){ return ResponseEntity.status(HttpStatus.OK).build(); } else { return ResponseEntity.status(HttpStatus.CONFLICT).build(); } } @PutMapping("removeitem/{id}") public ResponseEntity<Cart> removeCartItems(@PathVariable Long id, @RequestBody Item item){ if (cartService.removeCartItem(id,item)){ return ResponseEntity.status(HttpStatus.OK).build(); } else { return ResponseEntity.status(HttpStatus.CONFLICT).build(); } } // 结算:将购物车转为订单并清空购物车 @PutMapping("checkout/{id}") public ResponseEntity<Cart> checkout(@PathVariable Long id){ try{ cartService.checkout(id); return ResponseEntity.status(HttpStatus.OK).build(); } catch (IllegalArgumentException e) { return ResponseEntity.status(HttpStatus.CONFLICT).build(); } } }
Cart服务层
@Service public class CartService { @Autowired CartRepository cartRepository; @Autowired ItemRepository itemRepository; @Autowired PurchaseRepository purchaseRepository; public List<Cart> getCarts(){ return cartRepository.findAll(); } public Cart getCartById(Long id){ return cartRepository.findById(id).orElseThrow(); } public boolean updateCartContents(Long id, List<Item> items){ Optional<Cart> optionalCart = cartRepository.findById(id); if (optionalCart.isPresent()) { Cart cart = optionalCart.get(); cart.getItems().addAll(items); System.out.println("cart items before saving: " + cart.getItems()); cartRepository.save(cart); System.out.println("cart items after saving: " + cart.getItems()); return true; } else { return false; } } public boolean deleteCart(Long id){ if(cartRepository.findById(id).isPresent()){ cartRepository.deleteById(id); return true; }else{ return false; } } public boolean clearCart(Long id){ if(cartRepository.findById(id).isPresent()){ Cart cart = cartRepository.findById(id).orElseThrow(); cart.getItems().clear(); cartRepository.save(cart); return true; }else{ return false; } } public boolean removeCartItem(Long id, Item itemToRemove){ if(cartRepository.findById(id).isPresent()){ Cart cart = cartRepository.findById(id).orElseThrow(); cart.getItems().remove(itemRepository.findById(itemToRemove.getId()).orElseThrow()); cartRepository.save(cart); return true; }else{ return false; } } public void checkout(Long id) throws IllegalArgumentException{ Cart cart = cartRepository.findById(id).orElseThrow(IllegalArgumentException::new); //Purchase purchase = new Purchase(); //purchase.setPurchasedItems(cart.getItems()); //purchaseRepository.save(purchase); clearCart(id); } }
控制台日志
cart items before saving: [Item{id=1, createdOn=2024-05-05T12:49:57.343516400, lastUpdateOn=null, cart=null, game=null, quantity=null}, Item{id=2, createdOn=2024-05-05T12:49:57.344485400, lastUpdateOn=null, cart=null, game=null, quantity=null}, Item{id=3, createdOn=2024-05-05T12:49:57.344485400, lastUpdateOn=null, cart=null, game=null, quantity=null}] cart items after saving: [Item{id=1, createdOn=2024-05-05T12:49:53.806481, lastUpdateOn=null, cart=null, game=com.united.Gamestore.Game.Game@2f5cee8, quantity=1}, Item{id=2, createdOn=2024-05-05T12:49:53.809481, lastUpdateOn=null, cart=null, game=com.united.Gamestore.Game.Game@7cedf75c, quantity=1}, Item{id=3, createdOn=2024-05-05T12:49:53.811481, lastUpdateOn=null, cart=null, game=com.united.Gamestore.Game.Game@6f5d6a00, quantity=1}]
问题原因
- 关联维护端限制:Cart类中
@OneToMany(mappedBy = "cart")指定Item是双向关联的维护端,只有维护端(Item的cart属性)的变更才会同步到数据库,仅更新Cart的items列表不会触发数据库操作。 - 未建立Item与Cart的关联:从日志可见,添加的Item对象
cart属性为null,数据库无法建立外键关联,导致Item无法被持久化。 - 缺少级联配置:Cart保存时未配置级联操作,无法自动处理关联Item的持久化逻辑。
解决方案
1. 修改Cart类的关联注解
给items字段添加级联配置并初始化列表,避免空指针:
@JsonManagedReference @OneToMany(mappedBy = "cart", cascade = {CascadeType.PERSIST, CascadeType.MERGE}, orphanRemoval = true) private List<Item> items = new ArrayList<>();
cascade = {CascadeType.PERSIST, CascadeType.MERGE}:让Cart的保存/更新操作级联到关联的ItemorphanRemoval = true:当Item从Cart的items列表中移除时,自动删除数据库中对应记录- 初始化
items为new ArrayList<>():避免调用addAll时出现NullPointerException
2. 修改CartService的updateCartContents方法
添加Item到Cart时,手动设置每个Item的cart属性为当前Cart:
public boolean updateCartContents(Long id, List<Item> items){ Optional<Cart> optionalCart = cartRepository.findById(id); if (optionalCart.isPresent()) { Cart cart = optionalCart.get(); items.forEach(item -> { item.setCart(cart); // 建立Item与Cart的关联 cart.getItems().add(item); }); System.out.println("cart items before saving: " + cart.getItems()); cartRepository.save(cart); System.out.println("cart items after saving: " + cart.getItems()); return true; } else { return false; } }
3. 可选方案:直接保存Item
若不想使用级联,可直接通过ItemRepository保存Item并设置关联的Cart:
public boolean updateCartContents(Long id, List<Item> items){ Optional<Cart> optionalCart = cartRepository.findById(id); if (optionalCart.isPresent()) { Cart cart = optionalCart.get(); items.forEach(item -> { item.setCart(cart); itemRepository.save(item); // 直接保存Item }); return true; } else { return false; } }
内容的提问来源于stack exchange,提问作者jade
相关产品推荐
相关产品推荐

