Ответ
Процесс проектирования БД для интернет-магазина:
- Анализ требований: Выделение сущностей (Пользователь, Товар, Заказ, Категория) и их атрибутов.
- Концептуальное моделирование: Диаграмма сущность-связь (ERD).
- Нормализация: Приведение к 3NF для устранения аномалий вставки, обновления, удаления.
- Определение типов данных, ключей и индексов.
Логическая схема (основные таблицы):
-- 1. Пользователи
CREATE TABLE users (
id BIGSERIAL PRIMARY KEY,
email VARCHAR(255) UNIQUE NOT NULL,
password_hash VARCHAR(255) NOT NULL,
full_name VARCHAR(255),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 2. Категории товаров (иерархия может быть реализована через parent_id)
CREATE TABLE categories (
id BIGSERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
slug VARCHAR(100) UNIQUE NOT NULL,
parent_id BIGINT REFERENCES categories(id) ON DELETE SET NULL
);
-- 3. Товары
CREATE TABLE products (
id BIGSERIAL PRIMARY KEY,
sku VARCHAR(50) UNIQUE NOT NULL,
name VARCHAR(255) NOT NULL,
description TEXT,
price DECIMAL(10, 2) NOT NULL CHECK (price >= 0),
category_id BIGINT NOT NULL REFERENCES categories(id) ON DELETE RESTRICT,
stock_quantity INTEGER NOT NULL DEFAULT 0 CHECK (stock_quantity >= 0),
is_active BOOLEAN DEFAULT true
);
-- 4. Заказы (транзакционная сущность)
CREATE TABLE orders (
id BIGSERIAL PRIMARY KEY,
user_id BIGINT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
status VARCHAR(20) NOT NULL DEFAULT 'NEW', -- NEW, PROCESSING, SHIPPED, DELIVERED, CANCELLED
total_amount DECIMAL(10, 2) NOT NULL,
shipping_address JSONB, -- Гибкая структура для адреса
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 5. Позиции заказа (связь многие-ко-многим с атрибутами)
CREATE TABLE order_items (
id BIGSERIAL PRIMARY KEY,
order_id BIGINT NOT NULL REFERENCES orders(id) ON DELETE CASCADE,
product_id BIGINT NOT NULL REFERENCES products(id) ON DELETE RESTRICT,
quantity INTEGER NOT NULL CHECK (quantity > 0),
unit_price DECIMAL(10, 2) NOT NULL, -- Цена на момент заказа (историческая)
UNIQUE(order_id, product_id) -- Уникальность товара в заказе
);
Отображение в Java (JPA Entity):
@Entity
@Table(name = "orders")
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id", nullable = false)
private User user;
@Enumerated(EnumType.STRING)
private OrderStatus status;
@Column(name = "total_amount", precision = 10, scale = 2)
private BigDecimal totalAmount;
@Type(JsonType.class) // Использование Hibernate Type для JSONB (PostgreSQL)
@Column(columnDefinition = "jsonb")
private Address shippingAddress;
@OneToMany(mappedBy = "order", cascade = CascadeType.ALL, orphanRemoval = true)
private List<OrderItem> items = new ArrayList<>();
// Метод для расчета итога
public void calculateTotal() {
this.totalAmount = items.stream()
.map(OrderItem::getSubtotal)
.reduce(BigDecimal.ZERO, BigDecimal::add);
}
}
Ключевые решения:
- Нормализация: Отдельные таблицы для категорий и позиций заказа.
- Целостность: Использование
FOREIGN KEYиON DELETEправил. - Производительность: Индексы на
user_id,status,created_atв таблицеorders. - Гибкость: Поле
JSONBдля адреса,ENUM/VARCHARдля статуса. - Историчность: Сохранение
unit_priceвorder_itemsнезависимо от изменений вproducts.price.