11 Eylül 2020 Cuma

JPA @SequenceGenerator Anotasyonu - Kendi Sequence Tanımımızı Yapmak İçindir

Giriş
Bu anotasyon üye alan üzerinde veya sınıf üzerinde tanımlanabilir. Sınıf üzerinde tanımlamak için şöyle yaparız
@SequenceGenerator(sequenceName = "MY_DB_SEQUENCE", name = "sequence")
public class MyClass {
  ...
}
PostgreSQL
PostgreSQL için açıklama şöyle. Yani Java kodunda kullanılan allocationSize alanı ile veri tabanındaki increment değeri aynı olmalı.
AllocationSize and Sequence Increment Size
One thing to note here is that the allocationSize property in Hibernate needs to be the same as the increment size for the underlying sequence in Postgres.

This is so that Hibernate and the underlying sequence don’t go “out of sync” in terms of the ids that they’re holding. This also prevents any issues with a distributed architecture where multiple servers are writing to the same table.

By default, the increment size for our Postgres sequences was 1. We wrote a very quick migration to change it to match our allocationSize:

ALTER SEQUENCE entity_id_seq INCREMENT 50;

Now, Hibernate will only need to make 1 call to get the list of ids per 50 inserts.

And it’ll only need 1 call to insert those 50 rows as well.

Here’s a summary of what we learned from this issue:

  • With Hibernate, start using database sequence-based identity value generation as soon as possible — especially if you foresee the number of writes increasing.

  • Keep the allocationSize and the underlying Postgres sequence increment size params the same to avoid id collisions and support a distributed system.
allocationSize Alanı
Sequence'tan her select işleminde kaç tane sayı çekeceğimizi belirtir.
Örnek
Şöyle yaparız.
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "school_generator")
@SequenceGenerator(name="school_generator", sequenceName = "school_seq",
 allocationSize=1)
@Column(name = "school_id")
private Long id;
initialValue Alanı - Veri tabanını Kendimiz Yaratırken Kullanılır
Örnek - Oracle
Önce veritabanında sequence yaratılır. Oracle Sequence her sorgulandığında yeni bir sayı verir.
create sequence sub_seq
       MINVALUE 1 
       MAXVALUE 999999999999999999999999999 
       START WITH 1
       INCREMENT BY 1 
       CACHE 100 
       NOCYCLE ;
Sınıfı kodlamak için şöyle yaparız.
@Id
@SequenceGenerator(name="sub_seq", initialValue=1, allocationSize=1,
sequenceName="sub_seq")
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="sub_seq")  
private Integer pid;
Burada SequenceGenerator aslında javax.persistence.SequenceGenerator. Hibernate bu sınıfı Hilo algoritmasını kullanarak gerçekleştiriyor. Bu da sayılarda boşluklara sebep oluyor. Boşluklardan kaçınmak için initialValue = 1, ve allocationSize = 1 vermek gerekiyor.

Eğer sequence mevcut değilse şöyle bir hata alırız.
ERROR: could not read a hi value - you need to populate the table: hibernate_sequence
name Alanı
@GeneratedValue anotasyonundaki generator alanı ile aynı olmalıdır.
Örnek
Şöyle yaparız.
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
@SequenceGenerator(name = "sequenceGenerator",  sequenceName = "product_id_seq")
private Long id;
sequenceName Alanı
Veritabanındaki sequence ismidir.

7 Eylül 2020 Pazartesi

final Anahtar Kelimesi

Final Değişkene Bir Kere Değer Atanabilir
Örnek
Şöyle yaparız
final int value;
if (condition) {
  value = 1; // Ok!
} else {
  value = 2; // Ok!
}
value = 3; // Compile error: value already assigned.

Final Değişken Immutable Olsa İyi Olur
Yoksa final olmasının bir önemi olmayabilir. Yani Java'daki final, C++'taki const gibi çalışmıyor.

Örnek
Şöyle yaparız. Burada Date sınıfı immutable olmadığı için, final istenilen sonucu vermez.
// Note that (obsolete) Date class is mutable in Java.
final Date myDate = new Date();

myDate = new Date(); // Compilation error: can't reassign a final reference!

myDate.setTime(4711); // Ok, mutating referenced object is allowed!

Local Değişken
Local değişkende final specifier olması davranışı değiştirir.

Örnek
Şöyle yaparız
final int a = 97;
System.out.println(true ? a : 'c'); // outputs a

// versus

int a = 97;
System.out.println(true ? a : 'c'); // outputs 97

6 Eylül 2020 Pazar

Autoboxing

Giriş
Referans tip beklenen kodda primitive kullanırsak, derleyici tarafından arka planda bir çevrim gerçekleşir. Bu çevrime Autoboxing denilir. Bu özellik Java 1.5 ile geliyor.  Yani çok eskiden beri var. Açıklaması şöyle
However, version 1.5 of the JDK introduced the autoboxing of Java primitive types. This means the wrapper class will get created automatically when a primitive type is used anywhere a reference type is expected.
Eski Kodlar
Java 5'ten önce şöyle yapılırdı.
int x = 10;
ArrayList<E> list = new ArrayList();
// list.add(10); Pre JDK 1.5 autoboxing would not work
Integer wrapper = Integer.valueOf(x);
list.add(wrapper);
Autoboxing Nasıl Çalışır?
Autoboxing işleminde derleyici bizim için Integer.valueOf() gibi bir metodu otomatik olarak çağırır. 

Üretilen kod şöyledir
// Example of auto-boxing, here c is a reference type
Integer c = 128; // Compiler converts this line to Integer c = Integer.valueOf(128); 
// Example of auto-unboxing, here e is a primitive type
int e = c; // Compiler converts this line to int e = c.intValue();

Auto-unboxing Nedir?
Autoboxing işleminin tersine, Auto-unboxing denilir.

Primitive Tipler
Java'da 8 tane primitive tip var. Bunlar şöyle
byte, short, int, long, float, double, char, ve boolean
int Tipi
Autoboxing işlemin tuhaf bir yan etkisi olabiliyor. Açıklaması şöyle. Bu da JVM'in alt tarafta bir Integer cache kullanmasından kaynaklanıyor. Bu cache integer tipi için -128 to 127 değerleri arasında
In an interview, one of my friends was asked: If we have two Integer objects, Integer a = 127; Integer b = 127; Why does a == b evaluate to true when both are holding two separate objects
Açıklaması şöyle
... direct assignment of an int literal to an Integer reference is an example of auto-boxing concept where the literal value to object conversion code is handled by the compiler, so during compilation phase compiler converts Integer a = 127; to Integer a = Integer.valueOf(127);.
Integer.valueOf()  metodunun içi şöyle
 public static Integer valueOf(int i) {
  if (i >= IntegerCache.low && i <= IntegerCache.high)
    return IntegerCache.cache[i + (-IntegerCache.low)];
  return new Integer(i);
 }
long Tipi
long primitive tipi nedense Byte referans tipine çevrilemiyor. Şu kod derlenmez.
final int i = 3;
Byte b = i; // no error

final short s = 3;
Byte b = s; // no error


final long l = 3;
Byte b = l; // error
Şu kod derlenmez.
// Both compiler errors.
byte primitive = 0L;
Byte wrapped = 0L;