# How Shopping Cart Persistence Works in the macrozheng/mall E-Commerce System

> Discover how shopping cart persistence works in macrozheng/mall. Learn about MyBatis database operations, soft-delete logic, and duplicate detection in OmsCartItemServiceImpl.

- Repository: [macro/mall](https://github.com/macrozheng/mall)
- Tags: deep-dive
- Published: 2026-02-28

---

**The macrozheng/mall project persists shopping cart data in MySQL using MyBatis mappers, with the `OmsCartItemServiceImpl` class orchestrating all database operations through soft-delete logic and duplicate detection.**

The shopping cart persistence mechanism in the [macrozheng/mall](https://github.com/macrozheng/mall) open-source e-commerce platform stores user selections in a relational database to maintain state across sessions. This implementation leverages MyBatis for object-relational mapping and applies a soft-delete pattern via the `deleteStatus` column, ensuring data integrity while supporting efficient cart lifecycle management.

## Architecture Overview

All cart-related persistence logic resides in the **portal module** and follows a classic service-mapper pattern. The **`OmsCartItemServiceImpl`** class in [`mall-portal/src/main/java/com/macro/mall/portal/service/impl/OmsCartItemServiceImpl.java`](https://github.com/macrozheng/mall/blob/main/mall-portal/src/main/java/com/macro/mall/portal/service/impl/OmsCartItemServiceImpl.java) serves as the primary entry point, delegating SQL operations to the **`OmsCartItemMapper`** interface generated by MyBatis Generator.

The underlying table `oms_cart_item` stores individual cart rows with foreign keys to members and products, quantity counts, pricing snapshots, and temporal tracking fields. Every query filters against `deleteStatus = 0` to exclude logically deleted entries, enabling recovery capabilities and audit trails.

## Adding Items: Insert or Update Logic

When a user adds a product, the system must determine whether to create a new row or increment an existing quantity. The `add(OmsCartItem cartItem)` method executes this logic by first calling **`getCartItem`** to query for an existing entry matching `memberId`, `productId`, and `productSkuId` with `deleteStatus = 0`.

If no matching row exists, the service inserts a new record capturing the member information, product details, and current timestamp. If the SKU already exists in the cart, the implementation retrieves the existing `OmsCartItem`, increases its `quantity` by the new amount, and updates the `modifyDate` before persisting the change.

```java
// From OmsCartItemServiceImpl.add(...)
OmsCartItem existCartItem = getCartItem(cartItem);
if (existCartItem == null) {
    cartItem.setCreateDate(new Date());
    count = cartItemMapper.insert(cartItem);           // INSERT new row
} else {
    cartItem.setModifyDate(new Date());
    existCartItem.setQuantity(existCartItem.getQuantity() + cartItem.getQuantity());
    count = cartItemMapper.updateByPrimaryKey(existCartItem); // UPDATE quantity
}

```

This approach prevents duplicate rows for the same SKU while preserving the original `createDate` and capturing price snapshots at the time of addition.

## Retrieving the Cart with Soft-Delete Filtering

The `list(Long memberId)` method retrieves only active cart items by constructing a MyBatis Example object that explicitly filters for `deleteStatus = 0`. This ensures that logically deleted items—whether removed individually or cleared in bulk—never appear in the user's active cart view.

```java
// From OmsCartItemServiceImpl.list(...)
OmsCartItemExample example = new OmsCartItemExample();
example.createCriteria()
       .andDeleteStatusEqualTo(0)
       .andMemberIdEqualTo(memberId);
return cartItemMapper.selectByExample(example);

```

The returned `List<OmsCartItem>` contains fully populated entities including product references, quantities, and pricing data required for checkout calculations.

## Updating Item Quantities

Cart quantity modifications use selective updates to minimize database traffic. The `updateQuantity(Long id, Long memberId, Integer quantity)` method creates a target object containing only the new quantity, then applies it through **`updateByExampleSelective`** with a strict criteria match on `id`, `memberId`, and `deleteStatus = 0`.

```java
// From OmsCartItemServiceImpl.updateQuantity(...)
OmsCartItem cartItem = new OmsCartItem();
cartItem.setQuantity(quantity);
OmsCartItemExample example = new OmsCartItemExample();
example.createCriteria()
       .andDeleteStatusEqualTo(0)
       .andIdEqualTo(id)
       .andMemberIdEqualTo(memberId);
return cartItemMapper.updateByExampleSelective(cartItem, example);

```

This pattern ensures that only the specific column changes, the row belongs to the requesting member, and the item has not been previously soft-deleted.

## Deletion and Cart Clearing via Soft-Delete

Rather than executing physical `DELETE` statements, the implementation sets **`deleteStatus = 1`** to mark rows as removed. The `delete(Long memberId, List<Long> ids)` method updates multiple rows simultaneously by matching against the member ID and a list of cart item IDs.

```java
// From OmsCartItemServiceImpl.delete(...)
OmsCartItem record = new OmsCartItem();
record.setDeleteStatus(1);
OmsCartItemExample example = new OmsCartItemExample();
example.createCriteria().andIdIn(ids).andMemberIdEqualTo(memberId);
return cartItemMapper.updateByExampleSelective(record, example);

```

The `clear(Long memberId)` operation follows the same pattern but omits the ID list, effectively marking every cart row for that member as deleted:

```java
// From OmsCartItemServiceImpl.clear(...)
OmsCartItem record = new OmsCartItem();
record.setDeleteStatus(1);
OmsCartItemExample example = new OmsCartItemExample();
example.createCriteria().andMemberIdEqualTo(memberId);
return cartItemMapper.updateByExampleSelective(record, example);

```

## Database Schema and Entity Model

The **`OmsCartItem`** entity in [`mall-mbg/src/main/java/com/macro/mall/model/OmsCartItem.java`](https://github.com/macrozheng/mall/blob/main/mall-mbg/src/main/java/com/macro/mall/model/OmsCartItem.java) maps directly to the `oms_cart_item` table with the following critical persistence fields:

- **`id`**: Primary key for the cart row
- **`member_id`**: Foreign key linking the cart to the user account
- **`product_id`** and **`product_sku_id`**: References to the product catalog and specific SKU variants
- **`quantity`**: Integer count of units requested
- **`price`**: Decimal unit price captured at the time of addition to handle future price changes
- **`delete_status`**: Soft-delete flag where `0` indicates active and `1` indicates removed
- **`create_date`** and **`modify_date`**: Timestamps for audit tracking

The MyBatis mapper interface `OmsCartItemMapper` provides standard CRUD methods including `insert`, `selectByExample`, `updateByPrimaryKey`, and `updateByExampleSelective`, with SQL generated automatically by MyBatis Generator.

## Integration with Order Creation

During checkout, the **`OmsPortalOrderServiceImpl`** class interacts with the cart persistence layer through two critical phases. First, it calls `listPromotion` to retrieve cart items enriched with promotion calculations. After successful order persistence, it invokes **`deleteCartItemList`** to clear the cart, which internally executes the soft-delete logic described above, ensuring the cart reflects the post-purchase state without losing historical data.

## Summary

- **Shopping cart persistence** in macrozheng/mall uses MySQL with MyBatis mappers, centered on the `OmsCartItemServiceImpl` service class.
- **Duplicate detection** during item addition merges quantities for existing SKUs rather than creating redundant rows.
- **Soft-delete architecture** uses the `deleteStatus` column (`0` for active, `1` for deleted) to preserve data integrity and enable audit capabilities.
- **Security boundaries** ensure all queries filter by both `memberId` and `deleteStatus`, preventing cross-user data leakage and exposing only valid cart items.
- **Order workflow integration** automatically clears the cart via soft-delete after successful checkout through `OmsPortalOrderServiceImpl`.

## Frequently Asked Questions

### Where is the shopping cart data physically stored in the mall project?

The data persists in the `oms_cart_item` table within a MySQL database, accessed through the MyBatis mapper interface `OmsCartItemMapper` and managed by the service implementation `OmsCartItemServiceImpl` in the portal module.

### How does the system prevent duplicate product entries in the same cart?

Before inserting a new row, the `add` method queries for an existing item matching the `memberId`, `productId`, and `productSkuId` with `deleteStatus = 0`. If found, it increments the existing quantity via `updateByPrimaryKey`; otherwise, it inserts a new record via `cartItemMapper.insert`.

### What is the purpose of the deleteStatus field in the cart table?

The `deleteStatus` column implements a soft-delete pattern where `0` indicates an active cart item and `1` marks it as deleted. This approach preserves historical cart data for potential recovery or analytics while ensuring deleted items never appear in active cart queries through the `andDeleteStatusEqualTo(0)` criteria.

### How is the shopping cart cleared after a user places an order?

After order generation succeeds, `OmsPortalOrderServiceImpl` calls the cart service's deletion methods, which execute `updateByExampleSelective` to set `deleteStatus = 1` for all rows matching the member ID, effectively clearing the cart without removing the underlying database records.