İçeriğe geç

Enum Eşleme — Bloklu Kart Neden Bir Gün Dondurulmuş Göründü?

Orta 8 dk Sık karşılaşılır

Önce şunu oku: Flush ve SQL Sırası — save() Satırında Neden Hiçbir Şey Olmuyor?

30 saniyede özet

JPA varsayılan olarak enum'un sıra numarasını yazar. Araya bir değer eklenince eski satırlar sessizce başka bir durumla okunur. İsimle yazmak eklemeye, sabit kodlu bir AttributeConverter ise yeniden adlandırmaya da dayanır.

Bir dolabın çekmeceleri yalnızca numarayla biliniyor: “bloklu kartlar ikinci çekmecede.” Biri araya yeni bir çekmece takınca, ikinci çekmece artık başka bir şeyin çekmecesidir. İçindeki kartlar aynı, ama adresleri kaydı.

  1. Bayt: Kart durumuna yeni bir değer ekledim: FROZEN. Hepsi bu.

  2. Sen: Testler geçti, yayına aldık. Şimdi müşteri hizmetleri arıyor.

  3. Bayt: Bloklu kartlar dondurulmuş görünüyor, kapalı kart da bloklu! Veritabanına kimse dokunmadı.

  4. Bayt: Veri aynı. Değişen, o sayıların ne anlama geldiği.

Sütunda aslında ne yazıyor?

Bir enum alanına @Enumerated yazıp tür vermezsen, JPA sütuna değerin adını değil, ordinalBir enum sabitinin listedeki sıfırdan başlayan sırası. İlk sabitin ordinal değeri 0'dır.Liste değişince değişir; bu yüzden kalıcı bir kimlik olarak (veritabanında, dosyada) kullanılmaz. Kalıcı olan sabitin adıdır: name().Sözlükte gör → yazar. ACTIVE 0, BLOCKED 1, CLOSED 2 olur.

Sütunda yalnızca sayılar durur. O sayının hangi duruma karşılık geldiğini veritabanı değil, o anki Java kodun bilir.

Kafam karıştı, daha basit anlat

Varsayılan ayarda sütunda ad değil, sıra numarası durur. Anlamı kod belirler.

Hızlı kontrolBaşlangıç

Bir enum alanına @Enumerated yazılıp tür verilmezse veritabanına ne yazılır?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Enum'da ACTIVE, BLOCKED, CLOSED var ve ORDINAL kullanılıyor. BLOCKED bir kart için sütunda ne yazar?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Araya bir değer, ve sonra bir yeniden adlandırma

Sütunda sıra numaraları duruyor. Enum'da ACTIVE ile BLOCKED arasına FROZEN eklendi. Daha önce BLOCKED diye yazılmış kart şimdi nasıl okunur? Cevabı göster

FROZEN olarak, hiçbir hata vermeden. Sütunda 1 yazıyor ve yeni kodda 1, FROZEN’ın sırası. CLOSED kart da BLOCKED okunur; çünkü 2 artık BLOCKED.

Çekmeceye numara değil, sabit bir etiket.
Adım adım oku
  1. Çekmeceler sadece numarayla biliniyor.
  2. Biri araya yeni bir çekmece ekledi.
  3. İki numara artık başka bir çekmece.
  4. Çekmeceye numara değil, sabit bir etiket.

EnumType.STRING sütuna adı yazar; araya değer eklemek artık güvenlidir. Ama BLOCKED’ı SUSPENDED diye yeniden adlandırırsan, sütundaki “BLOCKED” yeni kodda yoktur ve okuma hata verir.

Bir AttributeConverterBir Java değerini sütuna nasıl yazılacağını ve geri nasıl okunacağını belirleyen JPA arayüzü. Enum'a sabit bir kod vermek için kullanılır.Sözlükte gör → her değere senin seçtiğin sabit bir kod verir: ACTIVE için ‘A’, BLOCKED için ‘B’. Ad da sıra da değişse sütundaki kod aynı kalır.

Kafam karıştı, daha basit anlat

Sıra numarası eklemede kayar, ad yeniden adlandırmada kırılır. Sabit kod ikisine de dayanır.

Hızlı kontrolOrta

ORDINAL kullanılırken ACTIVE ile BLOCKED arasına FROZEN eklendi. Eski BLOCKED kartlar nasıl okunur?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

EnumType.STRING neyi çözer?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Kendin gör

Kart durumu, yeni sürümde

Tohum 96571
  1. Kart 1: ACTIVE yazıldı
  2. Kart 2: BLOCKED yazıldı
  3. Kart 3: CLOSED yazıldı
  4. Kart 4: BLOCKED yazıldı

✕ sessizce yanlış: 0 · ⚠ okunamadı: 0

Hız
Adım 0

Şu an ne oldu?

@Enumerated varsayılanı (ORDINAL, sıra numarası) · ACTIVE ile BLOCKED arasına FROZEN eklendi

Satırlar eski sürümle yazıldı; yeni sürüm onları tek tek okuyor.

Görevler0/3

  • Hiç hata olmadan kartlar yanlış durumla okunsunaçık

    İpucu

    Sıra numarası ve araya ekleme.

  • Okuma yüksek sesle hata versinaçık

    İpucu

    İsimle yaz, sonra yeniden adlandır.

  • Yeniden adlandırmadan sonra bile her kart doğru okunsunaçık

    İpucu

    Sabit kod.

Olay günlüğü (0)

Henüz olay yok. Oynat veya adımla.

  1. Varsayılanla oynat. Sıra numarası ve araya ekleme: dört karttan üçü, hiç hata olmadan yanlış durumla okundu.
  2. “İsim” ve “yeniden adlandırıldı” seç. İki bloklu kart okunamadı; hata yüksek sesli.
  3. “Sabit kod” ve “yeniden adlandırıldı” seç. Bütün kartlar doğru okundu.
Hızlı kontrolOrta

EnumType.STRING kullanılırken BLOCKED, SUSPENDED diye yeniden adlandırıldı. Eski satırlar okunurken ne olur?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

AttributeConverter ile enum'a sabit bir kod vermenin kazancı nedir?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Tuzaklar

Yalnızca kodu değiştirmek. Yıllardır sıra numarasıyla yazılmış bir tabloda türü STRING yapmak yetmez; eski 0, 1, 2 değerleri ad olarak okunamaz. Veriyi bir şema göçüVeritabanı yapısını ya da içindeki veriyi sürümlü bir betikle değiştirmek. Flyway ve Liquibase bunu her ortamda aynı sırayla çalıştırır.Sözlükte gör → ile taşı, kodu onunla birlikte değiştir.

Aynı kodu iki değere vermek. Converter’da iki değer aynı kodu alırsa biri diğeri gibi okunur. Kodların benzersiz olduğunu küçük bir testle doğrula.

Kullanılan bir değeri silmek. Tabloda o değerde satır varken enum’dan silmek, o satırları okunamaz yapar. Önce satırları taşı ya da değeri “kullanımdan kalktı” diye tut.

Kafam karıştı, daha basit anlat

Saklama biçimi değişirse veriyi de taşı, kodları benzersiz tut, kullanılan değeri silme.

Hızlı kontrolOrta

Converter kullanılıyor ve iki farklı enum değerine yanlışlıkla aynı kod verildi. Ne olur?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.
Derinleş · Kart durumu: sabit kodlu enum ve converter 5 dosya · ~93 satır · ilk okumada atlayabilirsin
Proje dosyaları

card/src/main/java/com/bank/card/ CardStatus.java Enum: her değerin koddan bağımsız, değişmeyen bir kodu var.

card/src/main/java/com/bank/card/CardStatus.java
public enum CardStatus {
ACTIVE("A"),
FROZEN("F"),
SUSPENDED("B"), // renamed from BLOCKED; the stored code did not change
CLOSED("C");
private final String code;
CardStatus(String code) {
this.code = code;
}
public String code() {
return code;
}
public static CardStatus fromCode(String code) {
for (CardStatus status : values()) {
if (status.code.equals(code)) {
return status;
}
}
throw new IllegalArgumentException("Unknown card status code: " + code);
}
}

card/src/main/java/com/bank/card/ CardStatusConverter.java Converter: sütuna kodu yazar, okurken koddan değeri bulur; bilinmeyen kodda açık bir hata verir.

card/src/main/java/com/bank/card/CardStatusConverter.java
@Converter
public class CardStatusConverter implements AttributeConverter<CardStatus, String> {
@Override
public String convertToDatabaseColumn(CardStatus status) {
return status == null ? null : status.code();
}
@Override
public CardStatus convertToEntityAttribute(String code) {
return code == null ? null : CardStatus.fromCode(code);
}
}

card/src/main/java/com/bank/card/ Card.java Entity: alan converter ile eşleniyor; @Enumerated yok.

card/src/main/java/com/bank/card/Card.java
@Entity
@Table(name = "cards")
public class Card {
@Id
private UUID id;
@Column(name = "masked_pan", nullable = false)
private String maskedPan;
// Not @Enumerated: the column holds a fixed code, independent of name and order.
@Convert(converter = CardStatusConverter.class)
@Column(name = "status", length = 1, nullable = false)
private CardStatus status;
protected Card() {
}
public void freeze() {
if (status != CardStatus.ACTIVE) {
throw new IllegalStateException("Only an active card can be frozen");
}
status = CardStatus.FROZEN;
}
}

card/src/main/resources/db/migration/ V12__card_status_codes.sql Göç: eski sıra numaralarını sabit kodlara çeviren Flyway betiği.

card/src/main/resources/db/migration/V12__card_status_codes.sql
-- The column used to hold ordinals: 0 ACTIVE, 1 BLOCKED, 2 CLOSED.
ALTER TABLE cards ADD COLUMN status_code CHAR(1);
UPDATE cards SET status_code = CASE status
WHEN 0 THEN 'A'
WHEN 1 THEN 'B'
WHEN 2 THEN 'C'
END;
ALTER TABLE cards ALTER COLUMN status_code SET NOT NULL;
ALTER TABLE cards DROP COLUMN status;
ALTER TABLE cards RENAME COLUMN status_code TO status;

card/src/test/java/com/bank/card/ CardStatusTest.java Test: kodların benzersiz olduğunu doğrular.

card/src/test/java/com/bank/card/CardStatusTest.java
class CardStatusTest {
@Test
void every_status_has_its_own_code() {
Set<String> codes = Arrays.stream(CardStatus.values())
.map(CardStatus::code)
.collect(Collectors.toSet());
assertThat(codes).hasSize(CardStatus.values().length);
}
@Test
void a_stored_code_reads_back_as_the_same_status() {
for (CardStatus status : CardStatus.values()) {
assertThat(CardStatus.fromCode(status.code())).isEqualTo(status);
}
}
}

Kendini sına

Şimşek turu1/4

Tür verilmeyen @Enumerated sütuna değerin adını yazar.

Soru 1/3İleri

Tablo yıllardır ORDINAL ile yazılmış. STRING'e geçmek için en güvenli yol hangisi?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Aklında kalacak üç şey

  1. 1 Tür verilmeyen @Enumerated, sütuna değerin sıra numarasını yazar. Enum'a araya bir değer eklemek eski satırların anlamını hatasız değiştirir.
  2. 2 EnumType.STRING araya eklemeye dayanıklıdır, ama bir değeri yeniden adlandırmak eski satırları okunamaz yapar.
  3. 3 Sabit kodlu bir AttributeConverter, sütundaki değeri koddaki addan ve sıradan bağımsız tutar.
Sonraki kapı A Bankası'nın müşterisi hareket aramasına bir harf yazdı. Sonuçta B Bankası'nın müşterilerinin havaleleri de vardı. Hangi satır unutuldu? Kiracı Ayrımı — A Bankasının Müşterisi B Bankasının Verisini Görmesin · 8 dk

4 kart sonraki derste seni bekliyor

0/4 kart bu dersten toplandı