Spring Boot中删除含@Embedded复合主键的CartItem实体失败求助
你遇到的问题是调用删除接口返回"Success",但数据库中CartItem实体未被删除,核心原因可能有以下几点,对应解决方案如下:
1. 事务未提交(最可能原因)
Spring Data JPA的删除操作需要在事务上下文执行,否则操作只会停留在持久化上下文,不会同步到数据库。你的服务层方法没有添加@Transactional注解,导致删除动作未被提交到数据库。
修改方案:
给removeCartItem方法添加@Transactional注解:
import org.springframework.transaction.annotation.Transactional; @Transactional public String removeCartItem(RemoveCartItemRequest request) { // 原有代码逻辑保持不变 }
2. 未找到目标实体,删除逻辑未执行
cartItemRepository.findById(cartItemId).ifPresent(cartItemRepository::delete) 中,如果findById返回空Optional,删除逻辑根本不会执行,但你依然返回了"Success",造成删除成功的假象。
修改方案:
添加存在性判断,明确处理未找到实体的情况:
public String removeCartItem(RemoveCartItemRequest request) { int productDetailId = request.getProductDetailId(); var context = SecurityContextHolder.getContext(); int userId = Integer.parseInt(context.getAuthentication().getName()); User user = userRepository.findById(userId).orElseThrow(() -> new AppException(ErrorCode.NOT_EXISTED)); int cartId = user.getCart().getCartId(); CartItemId cartItemId = new CartItemId(productDetailId, cartId); if (cartItemRepository.existsById(cartItemId)) { cartItemRepository.deleteById(cartItemId); return "Success"; } else { // 可根据业务需求返回提示或抛出异常 return "CartItem not found"; // throw new AppException(ErrorCode.CART_ITEM_NOT_EXIST); } }
改用existsById判断后直接调用deleteById,比先查询再删除更高效,避免不必要的实体加载。
3. 复合主键的equals/hashCode逻辑异常
虽然你在CartItemId上用了@EqualsAndHashCode,但需确保Lombok正确生成了包含productDetailId和cartId的equals/hashCode方法。可手动验证:
// 测试代码 CartItemId id1 = new CartItemId(1, 1); CartItemId id2 = new CartItemId(1, 1); System.out.println(id1.equals(id2)); // 应输出true System.out.println(id1.hashCode() == id2.hashCode()); // 应输出true
如果结果不符合预期,可能是Lombok配置问题,手动实现equals和hashCode即可:
@Embeddable @Getter @Setter @NoArgsConstructor @AllArgsConstructor @FieldDefaults(level = AccessLevel.PRIVATE) public class CartItemId implements Serializable { private static final long serialVersionUID = 1L; @Column(name = "product_detail_id") int productDetailId; @Column(name = "cart_id") int cartId; @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; CartItemId that = (CartItemId) o; return productDetailId == that.productDetailId && cartId == that.cartId; } @Override public int hashCode() { return Objects.hash(productDetailId, cartId); } }
4. 数据库外键约束导致删除失败(隐性回滚)
如果CartItem关联的ProductDetail或Cart存在外键约束(比如设置了ON DELETE RESTRICT),删除时数据库会拒绝操作,但如果事务未配置异常回滚策略,可能不会抛出异常,导致事务静默回滚。
验证方法:
直接在数据库执行删除SQL,查看是否报错:
DELETE FROM cart_item WHERE product_detail_id = ? AND cart_id = ?;
如果报错,可根据业务需求调整外键约束规则(比如改为ON DELETE CASCADE或ON DELETE SET NULL),或者先删除关联依赖。
内容的提问来源于stack exchange,提问作者TunazZz

