24 Ağustos 2012 Cuma

Hibernate ve Foreign Key

Foreign Key Nedir
Foreign key kısaca Parent ve Child tabloların birbirlerine bağlanması amacını taşır.

Aşağıdaki şekilde grouptable bir Parent, story ise Child olarak kullanılmış. Her iki tabloyu birbirine bağlayan bir de foreign key var.




Bir başka benzer örneği de burada buldum.



Hibernate ve One-to-Many Kullanımı

Hibernate ile iki tablo arasındaki foreign key kullanılarak one-to-many ilişkisi kurulmak isteniyorsa önümüzde iki tane seçenek var.

  1. Çift yönlü (bidirectional) One-to-Many. 
  2. Tek yönlü (unidirectional) One-to-Many kullanımı.


One-To-Many İlişkisinin Çift Yönlü (Bidirectional) olması ve Foreign Key kullanması

Çift Yönlü Olması durumunu aşağıda açıklamaya çalıştım.


@Entity
public class Child{

private Long id;
private String childName;
private Parent parent;

     @ManyToOne
     public Parent getParent() {
         return parent;
     }
}
@Entity
public class Parent{

 private Long id;
 private String name;
 private String description;
 private List<Children> children;

 @Id @GeneratedValue
 public Long getId() {
  return id;
 }

 public void setId(Long id) {
  this.id = id;
 }

 @OneToMany(cascade=CascadeType.ALL, mappedBy="parent")
 public List<Children> getChildren() {
  return children;
 } 
}
One-To-Many ve Foreign Key Sütun İsmi
Bu kodda mappedBy kullanımı şu anlama geliyor. Parent ve Child sınıfları ilişkililer ve ilişki için Child sınıfındaki parent alanı için için üretilen foreign key kullanılacak.

Benim verdiğimden farklı örnek bir kodu burada bulabilirsiniz.

Yukarıda verilen örnek kodda @JoinColumn kullanılmamış. Bu gösterimin kullanılmadığı durumda üretilen foreign key sütununun isminin nasıl üretildiği şöyle açıklanmış.
If no @JoinColumn is declared on the owner side, the defaults apply. A join column(s) will be created in the owner table and its name will be the concatenation of the name of the relationship in the owner side, _ (underscore), and the name of the primary key column(s) in the owned side.
Bu açıklamada dikkat edilmesi gereken bir nokta şu. Object Oriented dünyada "owning side" Parent iken, SQL dünyasında foreign key'i içeren taraf "owning side" oluyor (yani Child) . Bu durum burada daha iyi açıklanmış.

Yukarıdaki açıklamaya göre Child nesnesi "owning side" olduğu için @JoinColumn kullanılmazsa bizim üretilecek foreign key sütununun ismi parent_id olacaktı.

Böyle bir konfigürasyon ilk defa yaratılıp save() metodu çağrılırsa üretilen SQL şuna benzer bir şey oluyor.

Hibernate: insert into PARENT (x, y, z) values (?)
Hibernate: insert into CHILD (x, y, z, parent_id) values (?, ?, ?, ?, ?)
Hibernate: insert into CHILD (x, y, z, parent_id) values (?, ?, ?, ?, ?)

Bu şekilde oluşturulan ilşkilerde N+1 select problemi de çok rastlanılan bir durum. Bu konuyla ilgili Hibernate ve N+1 Select problemi başlıklı yazıyı da okuyabilirsiniz.

One-To-Many ve CascadeType (Ard arda İşlemler Seçenekleri)

One-To-Many ilişkilerde yeni parent ve child nesneleri kaydederken foreign key kısıtından dolayı hata almamak için asgari CascadeType.PERSIST seçeneğinin tanımlı olması lazım. Böylece yukarıdaki üretilen SQL örneklerinde de görülebileceği gibi önce parent nesnesi kaydedilir ve onun birincil anahtarı child nesnelerde foreign key olarak kullanılır.

One-To-Many İlişkisinin Tek Yönlü (Unidirectional) olması ve Foreign Key kullanması

Bu durumu açıklayan güzel bir örneği burada buldum. Bir başka örnek ise burada.

Parent sınıfa normalde eklenmesi gereken
mappedBy özelliği yerine bu sefer sadece @JoinColumn gösterimi ekleniyor.

@Entity
public class Child{

private Long id;
private String childName;
}
 
@Entity
public class Parent{

 private Long id;
 private String name;
 private String description;
 private List<Children> children;

 @Id @GeneratedValue
 public Long getId() {
  return id;
 }

 public void setId(Long id) {
  this.id = id;
 }

 @OneToMany(cascade=CascadeType.ALL)
@JoinColumn(name="parent_id", referencedColumnName="id")
 public List<Children> getChildren() {
  return children;
 } 
  
Bu kullanım şeklinde dikkat edilmesi gereken nokta mappedBy kullanılmadığı için Parent sınfı "owning side"
haline geliyor ve kendi id sütununu Child tablosuna foreign key olarak yazıyor.

Bir diğer nokta ise bu kullanım şekli sadece JPA 2.0 ile destekleniyor.

Bir dikkat edilmesi gereken nokta ise bu kullanım şekil tavsiye edilmiyor.

Kullanılan Collection Sınıfları

Hibernate ile "one-to-many" ilişkisinı kullanırken dikkatimi çeken bir şey oldu.

Kod içinde List, Set, Map gibi collection interface'leri kullanılırken Hibernate bu interfacelerden türeyen kendi sınıflarını kullanıyor. Örneğin org.hibernate.collection.PersistentSet gibi.

8 Ağustos 2012 Çarşamba

JExcel ve Apache POI

JExcel ve RowsExceededException
JExcel API'si eski olduğu için büyük excel dosyaları üretirken 65536 satırdan fazla satır yaratılmaya çalışılırsa RowsExceededException exception'ı atıyor. WritableSheetImpl.java dosyasındaki bu satır hatanın sebebi.

Büyük dosyalar üretmek için http://poi.apache.org/spreadsheet/how-to.html adresinde örnek verildiği gibi SXSSFWorkbook sınıfını kullanmak lazım. Zaten bu sınıfın açıklamasında da "Streaming version of XSSFWorkbook implementing the "BigGridDemo" strategy. " yazıyor.


JExcel ve Yuvarlama Hatası
JExcel kullanırken Number tipi alanların değerlerini getContents() metodu ile String olarak alırken dikkatli olmak lazım. Çünkü jxl.read.biff.NumberRecord sınıfı kendi içinde aşağıdaki gibi bir DecimalFormat nesnesi tutuyor. Ancak bu nesne sadece 3 hane hassasiyete kadar doğru değerleri döndürüyor. Eğer girilen değer daha fazla hassasiyete sahipse sonuç yuvarlanarak veriliyor ki bu da farkında olmadan hatalara sebep olabilir.

Aşağıda Jexcel'in kismi sınıf hiyerarşisi var.

Understanding the Excel .xls Binary File Format başlıklı yazıda da Excel'in veriyi nasıl sakladığı anlatılıyor.

XLSX Formatı
XLSX formatı aslında zip dosya formatı ile aynı.Eğer xlsx dosyasını bir zip programı ile açarsak karşımıza aşağıdaki görüntü çıkar.
XSSFSheetXMLHandler sınıfı ile  xml dosyasını parse etmek imkanı var. Bu sınıfın en önemli özelliği her hücreyi String olarak okuyabilmemizi sağlaması.

Excel Hücre Tipleri
Bir hücre aşağıdaki gibi Number olarak görünüyor olsak bile
hücrenin tipi SST_STRING olabiliyor. Bu durumda da string olarak okunabiliyor.

Eğer hücreye format verilmişse
hücrenin tipi NUMBER oluyor. XML içindeki veri 0.22556399999999999 olsa bile


double'a parse edilirken 0.225564 şekline dönüyor. Daha sonra formatlama stringi #,##0.000000 olduğu için java.text.DecimalFormat sınıfı sayesinde Türkçe 0,225564 haline geliyor.


POI ve Number hücrenin sağa/sola dayalı olması
Excel üzerinde 16,466166 görüyoruz ancak xml'de 16.466166000000001 de yazılı.
Eğer hücre sağa dayalı ise xml aşağıdaki gibi
<c r="A1"><v>16.466166000000001</v></c> --> çıktı 16.466166000000001





Eğer hücre sola dayalı ise xml aşağıdaki gibi
<c r="A2" s="1"><v>16.466166000000001</v></c> --> çıktı :  16,466166 çünkü s=1 ile style olarak "general format" kullanıyor

26 Temmuz 2012 Perşembe

Hibernate Birincil Önbellek

Birincil Önbellek
Birincil önbellek session ile ilişkilendirilir ve session kapatılınca yok olur. İkincil önbellek ise SessionFactory ile ilişkilendirilir ve SessionFactory kapatılınca yok olur.

Birincil önbelleğin Session ile ilişkili olduğunu gösteren şekli buradan aldım.

Bir diğer şekli ise buradan aldım.

Birincil önbellek bir nesneye arka arkaya birkaç güncelleme gelirse her seferinde veritabanına gitmeden SQL cümlelerini mümkün olduğunca geciktirebilmeye yarar. Eğer session kapatılırsa önbellek te beraberinde kapatılır. Birincil önbellek ile ilgili kurallar aşağıda.

Session.flush() –>  Flushes level one cache content to db software
Session.evict() –> Remove the content of level 1 cache
Session.close() –> closes level 1 cache, before that it calls session.flush()

Batch Processing
Birincil önbellek batch işlemlerde bazen OutOfMemoryException problemine sebep olabilyor. Bunun sebebi ve nasıl çözüleceği "Batch Processing" sayfasında anlatılmış. Ben de aşağıya bazı notlarımı ekliyorum.

Batch Update
Aşağıdaki kod parçasında da görüldüğü gibi openSession() metodu ile elde edilen Session nesnesi, birincil önbellek ile ilişkili ve bu nesne ile yapılan save(),update() vs. gibi işlemlerde parametre olarak geçilen nesne önbelleğe dahil ediliyor. Ancak çok fazla sayıda işlem yapılırsa önbellek şiştiği için OutofMemoryError hatası alabiliyoruz.


Bu durumdan kurtulmak için iki yol var. Birinci yöntemde önbellek ara sıra temizleniyor. Aşağıdaki kodda önbellek her 20 döngüde bir temizleniyor.
İkinci yöntemde ise önbellek hiç kullanılmıyor. Birinci koddan farklı olarak bu sefer openStatelessSession() metodunun çağırıldığına dikkat !
Batch Select
Batch select için örnek Managing the caches başlığı altında verilmiş.
Birincil Önbellek ve load
When does Hibernate Session.load() throw an exception sorusunda load() metodunun bir nesnenin veritabanında olup olmadığını kontrol etmek için kullanılmaması gerektiği açıklanmış.

6 Temmuz 2012 Cuma

PL/SQL String Metodları

Aşağıda kullandığım bazı String metodları örneklerini görebilirsiniz.

Trim
UPDATE Table1 A SET A.BKOD = TRIM (A.BKOD);

4 Temmuz 2012 Çarşamba

ls komutu

Not : Bu yazı ile ilgili olarak Linux Dosya Distemi başlıklı yazıya göz atabilirsiniz.
ls Komutu
ls komutu ile inode veriyapısında tutulan bir çok veriye erişmek mümkün. Aşağıdaki şekilde bu komut ile gösterilen bilgileri açıklayan bir şekil mevcut.
ls ve hardlink sayısı
What is the meaning of those numbers in the second column after typing “ls -l”? başlıklı soruda hardlinklerin ne olduğu açıklanmış. Dikkat edilmesi gereken nokta, dizinler için hardlink sayısı 2'den başlıyor. Örneğin aşağıdaki kırmızı çerveçe içine alınmış dizinde 1 tane alt dizin mevcut.

ls ve inode numarası

Linux üzerinde bir dosyanın inode numarasını görmek için burada da anlatıldığı gibi "ls -i" komutu kullanılabilir.
$ ls -i /etc/passwd komutu çıktı olarak
752010 /etc/passwd verir. 75200 inode numarasıdır.
ls -i komutu ile aynı görevi gören stat komutu da mevcut.

C dili ile inode numarasını almak için stat sistem çağrısı kullanılır.

How to: Linux / UNIX Delete or Remove Files With Inode Number başlıklı yazıda da anlatıldığı gibi inode numarası ile bir dosyayı silmek için find komutu kullanılabilir.


29 Mayıs 2012 Salı

Spring Security Filtereleri

Aşağıda Spring Security ve Http'yi beraber kullanırken aldığım notlarım var.

Spring Security Filtre zinciri aşağıdaki gibi.
 UsernamePasswordAuthenticationFilter

UserNamePasswordAuthenticationFilter  /j_spring_security_check adresi ile biten URL'lere cevap veriyor. Giriş için kullandığımız form  bilgileri kullanıcından aldıktan sonra "/j_spring_security_check?j_username=guest&j_password=guest" formatında POST ederse bu filtre devreye girer ve AuthenticationManager sınıfını kullanarak kimlik doğrulama yapar.

DefaultLoginPageGeneratingFilter

DefaultLoginPageGeneratingFilter eğer xml dosyasında <form-login login-page="/login.jsp" /> gibi bir satır yoksa default olarak bir login sayfası yaratn filtredir. Daha detaylı açıklamayı Announcing: Spring Security 3: The Book sayfasında bulmak mümkün.

SecurityContextHolderAwareRequestFilter

SecurityContextHolderAwareRequestFilter filtresi HttpServletRequest arayüzünün gerektirdiği isUserInRole() gibi bazı metodları Spring'in Authentication nesnesine yönlendirir.

10 Mayıs 2012 Perşembe

POSIX Sinyalleri

Bu konu çok karmaşık. İleride değinmek üzere bazı notlarımı ekliyorum.
Bu konu ile ilgili olarak Linux Sinyalleri başlıklı yazıya da göz atabilirsiniz.

sigtimedwait
Bu metod için man sayfası burada.
sigset_t _fSigMask; // beklenilen sinyaller

sigemptyset(&_fSigMask);
sigaddset(&_fSigMask, SIGUSR1);
sigaddset(&_fSigMask, SIGSEGV);

int nSig;
struct timespec tmTimeout = { nSec, nNanoSec }; // bekleme süresi
sigtimedwait(&fSigMask, &nSig, &tmTimeout);
sigwait
Bu metod için man sayfası burada. How to make thread synchronization without using mutex, semorphore, spinLock and futex? sorusunda threadler arasında klasik mekanizmaları kullanmadan senkronizasyon yapılmasına dair verilen cevaplarda hep sigwait metodu kullanılıyor.