К какой категории сущности относится Primary Key
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
К какой категории сущности относится Primary Key
Primary Key (первичный ключ) относится к категории ИДЕНТИФИКАТОРОВ сущности. Это ключевая характеристика, которая уникально определяет каждую запись в таблице.
Классификация атрибутов сущности
Все атрибуты сущности в базе данных можно разделить на несколько категорий:
┌─────────────────────────────────────────────────────────┐
│ АТРИБУТЫ СУЩНОСТИ │
├─────────────────────────────────────────────────────────┤
│ 1. ИДЕНТИФИКАТОРЫ (Identifiers) │
│ ├─ Primary Key (Первичный ключ) │
│ ├─ Composite Key (Составной ключ) │
│ └─ Surrogate Key (Суррогатный ключ) │
├─────────────────────────────────────────────────────────┤
│ 2. ДЕСКРИПТОРЫ (Descriptors) — описывают сущность │
│ ├─ Обычные атрибуты (name, email, etc) │
│ └─ Производные атрибуты (calculated age) │
├─────────────────────────────────────────────────────────┤
│ 3. ССЫЛКИ (References) — внешние ключи │
│ └─ Foreign Key (Внешний ключ) │
├─────────────────────────────────────────────────────────┤
│ 4. СЛУЖЕБНЫЕ (Service) — для синхронизации │
│ ├─ created_at (timestamp) │
│ ├─ updated_at (timestamp) │
│ └─ version (for optimistic locking) │
└─────────────────────────────────────────────────────────┘
Primary Key как идентификатор
Primary Key — это уникальный идентификатор, обладающий свойствами:
// Пример: таблица User
@Entity
@Table(name = "users")
public class User {
@Id // ← Primary Key
@GeneratedValue(strategy = GenerationType.UUID)
private UUID id; // Идентификатор
// Дескрипторы (описывающие сущность)
@Column(nullable = false)
private String email;
private String name;
private int age;
// Внешний ключ (ссылка на другую сущность)
@ManyToOne
@JoinColumn(name = "company_id")
private Company company;
// Служебные поля
@Column(updatable = false)
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
}
Характеристики Primary Key
1. Уникальность (Uniqueness)
- Каждое значение первичного ключа должно быть уникальным
- Не может быть двух записей с одинаковым PK
CREATE TABLE users (
id UUID PRIMARY KEY, -- Уникальный
email VARCHAR(255), -- Может быть не уникальным
name VARCHAR(255)
);
-- Попытка вставить дублирующийся id приведёт к ошибке
INSERT INTO users VALUES (123e4567-e89b-12d3-a456-426614174000, alice@example.com);
INSERT INTO users VALUES (123e4567-e89b-12d3-a456-426614174000, bob@example.com);
-- ERROR: duplicate key value violates unique constraint
2. Невозможность быть NULL (NOT NULL)
- Primary Key не может быть пустым
- Это гарантирует существование идентификатора
INSERT INTO users VALUES (NULL, alice@example.com, Alice);
-- ERROR: null value in column "id" violates not-null constraint
3. Неизменяемость (Immutability)
- Первичный ключ должен быть неизменяемым
- Нельзя менять идентификатор существующей записи
User user = userRepository.findById(userId).orElseThrow();
user.setId(newId); // ❌ Плохая практика!
// Это нарушит логику приложения
user.setName("New Name"); // ✅ Хорошо
user.setEmail("new@example.com"); // ✅ Хорошо
Типы Primary Keys
1. Simple (Простой) Primary Key
@Entity
public class Product {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id; // Один атрибут как PK
private String name;
private BigDecimal price;
}
2. Composite (Составной) Primary Key
@Embeddable
public class OrderItemId {
@Column(name = "order_id")
private Long orderId;
@Column(name = "product_id")
private Long productId;
// Equals и hashCode обязательны
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof OrderItemId)) return false;
OrderItemId that = (OrderItemId) o;
return Objects.equals(orderId, that.orderId) &&
Objects.equals(productId, that.productId);
}
@Override
public int hashCode() {
return Objects.hash(orderId, productId);
}
}
@Entity
public class OrderItem {
@EmbeddedId
private OrderItemId id; // Составной PK
private int quantity;
private BigDecimal price;
}
3. Natural Primary Key (использует бизнес-данные)
@Entity
public class Country {
@Id
@Column(length = 2)
private String countryCode; // ISO-2 код
private String name;
// Пример: countryCode="US", "RU", "CN"
}
4. Surrogate Primary Key (искусственный, технический)
@Entity
public class Book {
@Id
@GeneratedValue(strategy = GenerationType.UUID)
private UUID id; // Суррогатный ключ
private String isbn; // Natural key (может быть unique)
private String title;
}
Primary Key vs Unique Key
@Entity
public class User {
@Id
private UUID id; // PRIMARY KEY
@Column(unique = true, nullable = false)
private String email; // UNIQUE KEY
@Column(unique = true)
private String phoneNumber; // UNIQUE KEY (может быть NULL)
}
-- В SQL эквивалент
CREATE TABLE users (
id UUID PRIMARY KEY, -- Primary Key
email VARCHAR(255) NOT NULL UNIQUE, -- Unique Key
phone VARCHAR(20) UNIQUE -- Может быть NULL
);
Отличия:
- PRIMARY KEY: ровно один на таблицу, NOT NULL обязателен
- UNIQUE KEY: может быть несколько, может содержать NULL
Primary Key в отношениях
@Entity
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id; // Primary Key
@ManyToOne
@JoinColumn(name = "user_id", nullable = false)
private User user; // Foreign Key (ссылка на Primary Key)
private LocalDateTime orderDate;
}
-- Связь через Primary Key
CREATE TABLE orders (
id BIGSERIAL PRIMARY KEY,
user_id UUID NOT NULL REFERENCES users(id),
order_date TIMESTAMP
);
Best Practices
// ✅ ХОРОШО
@Entity
public class GoodEntity {
@Id
@GeneratedValue(strategy = GenerationType.UUID)
private UUID id; // Surrogate key — лучше всего
@Column(unique = true)
private String uniqueBusinessKey; // Для natural lookups
}
// ❌ ПЛОХО
@Entity
public class BadEntity {
@Id
private String email; // Не нужно менять, может быть NULL (нарушение)
@Id
@Column(name = "user_id")
private Long userId; // Несколько @Id?
}
Производительность Primary Key
// Индексирование
// Primary Key автоматически индексируется
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id; // Автоматический индекс
@Column(unique = true) // Также индексируется
private String email;
}
// Быстрый поиск по PK
User user = userRepository.findById(123L); // O(log n)
// Поиск по другому полю может быть медленнее без индекса
User user = userRepository.findByEmail("alice@example.com"); // Нужен свой индекс
Заключение
Primary Key — это идентификатор сущности, который:
- Уникально определяет каждую запись
- Не может быть NULL
- Должен быть неизменяемым
- Автоматически индексируется для быстрого поиска
- Используется для связей между таблицами
Это основной столп реляционных баз данных, обеспечивающий целостность и эффективность доступа к данным.