← Назад к вопросам

Какая аннотация запрещает обновление поля сущности?

1.0 Junior🔥 201 комментариев
#ORM и Hibernate

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

# Аннотация для запрета обновления поля сущности

Для запрета обновления (update) поля в JPA сущности используется аннотация @Column(updatable = false). Это одна из важных аннотаций при работе с базой данных.

@Column(updatable = false)

Эта аннотация указывает JPA, что поле не должно быть обновляемо в SQL UPDATE запросах:

import javax.persistence.*;

@Entity
@Table(name = "users")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    // Поле можно вставить один раз (INSERT), но не обновить (UPDATE)
    @Column(updatable = false)
    private String email;
    
    // Обычное поле, которое можно обновлять
    @Column
    private String name;
    
    // Поле создания, часто используется с updatable = false
    @Column(updatable = false)
    @Temporal(TemporalType.TIMESTAMP)
    private Date createdAt;
    
    // Поле обновления, только для чтения при INSERT
    @Column(insertable = false)
    @Temporal(TemporalType.TIMESTAMP)
    private Date updatedAt;
}

Практический пример

@Entity
@Table(name = "users")
public class User {
    @Id
    private Long id;
    
    // Email не может быть изменён после создания
    @Column(updatable = false, nullable = false)
    private String email;
    
    // Имя можно менять
    private String name;
    
    // Дата создания устанавливается один раз
    @Column(updatable = false)
    @CreationTimestamp
    private LocalDateTime createdAt;
    
    // Дата последнего обновления автоматически обновляется
    @UpdateTimestamp
    private LocalDateTime updatedAt;
    
    // Версия для оптимистичной блокировки
    @Version
    private Long version;
}

Как это работает

Попытка обновления

// Сохранение нового пользователя
User user = new User();
user.setEmail("john@example.com");  // OK - INSERT
user.setName("John");
userRepository.save(user);

// Позже попытка обновить email
User existing = userRepository.findById(1L).orElseThrow();
existing.setEmail("newemail@example.com");  // Вызов работает
existing.setName("Johnny");                 // Работает нормально
userRepository.save(existing);  // SAVE работает, но email НЕ обновится в БД!

// Проверка
User reloaded = userRepository.findById(1L).orElseThrow();
System.out.println(reloaded.getEmail());  // Остался "john@example.com"
System.out.println(reloaded.getName());   // "Johnny" - обновился

Сгенерированный SQL

-- Первое сохранение (INSERT)
INSERT INTO users (email, name, created_at) 
VALUES ('john@example.com', 'John', NOW());

-- Попытка обновления
-- updatable = false означает, что email НЕ будет включён в UPDATE
UPDATE users SET name = 'Johnny', updated_at = NOW() 
WHERE id = 1;
-- Обратите внимание: email НЕ в SET части!

Паттерны использования

1. Immutable поля (ID, создание, версия)

@Entity
public class BlogPost {
    @Id
    @GeneratedValue
    private Long id;
    
    @Column(updatable = false)
    private String slug;  // URL-friendly identifier, не меняется
    
    @Column(updatable = false)
    private LocalDateTime publishedAt;  // Дата публикации
    
    private String title;   // Можно редактировать
    private String content; // Можно редактировать
}

2. Аудит полей

@Entity
public class Document {
    @Id
    private Long id;
    
    @Column(updatable = false)
    private String createdBy;  // Кто создал
    
    @Column(updatable = false)
    private LocalDateTime createdAt;  // Когда создал
    
    private String content;
    private String modifiedBy;  // Кто последний раз редактировал
    private LocalDateTime modifiedAt;  // Когда
}

3. Системные идентификаторы

@Entity
public class Account {
    @Id
    private String accountNumber;  // IBAN или номер счёта
    
    @Column(updatable = false)
    private String accountNumber;  // Уникальный идентификатор
    
    @Column(updatable = false)
    private String accountType;    // Тип счёта, не меняется
    
    private BigDecimal balance;    // Может меняться
}

Комбинация с insertable

@Entity
public class Entity {
    @Id
    private Long id;
    
    // Только для вставки, не обновляется
    @Column(insertable = true, updatable = false)
    private String createdBy;
    
    // Для вставки и обновления
    @Column(insertable = true, updatable = true)
    private String modifiedBy;
    
    // Ни для вставки, ни для обновления (вычисляемое поле)
    @Column(insertable = false, updatable = false)
    private String computedValue;
}

Важные замечания

Hibernate vs Spring Data JPA

Все JPA реализации (Hibernate, EclipseLink) поддерживают updatable = false.

Проверка на уровне БД

-- Лучше всего добавить ограничение на уровне БД
CREATE TABLE users (
    id BIGINT PRIMARY KEY,
    email VARCHAR(255) NOT NULL,
    name VARCHAR(255),
    created_at TIMESTAMP NOT NULL,
    CONSTRAINT chk_email_immutable CHECK (email IS NOT NULL)
);

Безопасность

// updatable = false это не замена валидации!
// Это просто указание ORM как генерировать SQL

// Плохо: только на уровне ORM
@Column(updatable = false)
private String email;

// Хорошо: валидация + ORM
@Column(updatable = false, nullable = false)
@Email
private String email;

Тестирование

@SpringBootTest
public class UserEntityTest {
    @Autowired
    private UserRepository repo;
    
    @Test
    public void emailShouldNotUpdate() {
        // Создание
        User user = new User();
        user.setEmail("original@example.com");
        user.setName("John");
        User saved = repo.save(user);
        
        // Обновление
        saved.setEmail("changed@example.com");
        saved.setName("Johnny");
        repo.save(saved);
        
        // Проверка
        User reloaded = repo.findById(saved.getId()).orElseThrow();
        assertEquals("original@example.com", reloaded.getEmail());  // Не изменился
        assertEquals("Johnny", reloaded.getName());  // Изменился
    }
}

Альтернативы

1. @Immutable (для целого класса)

import org.hibernate.annotations.Immutable;

@Entity
@Immutable
public class ReadOnlyEntity {
    // Всё поле не обновляется
}

2. @CreationTimestamp и @UpdateTimestamp (Hibernate)

import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.UpdateTimestamp;

@Entity
public class AuditedEntity {
    @CreationTimestamp
    @Column(updatable = false)
    private LocalDateTime createdAt;
    
    @UpdateTimestamp
    private LocalDateTime updatedAt;
}

Выводы

  • @Column(updatable = false) — запрещает обновление поля в UPDATE запросах
  • Используется для: ID, дат создания, неизменяемых идентификаторов
  • Это не замена безопасности: используй валидацию и ограничения БД
  • Работает со всеми JPA реализациями
  • На уровне приложения: ORM просто исключит поле из UPDATE SQL
Какая аннотация запрещает обновление поля сущности? | PrepBro