Bu Sayfayı Paylaş:

Bilgi/Açıklama

JPA

JPA (Java Persistence API - Java Kalıcılık Betikliği), bir ORM (Object Relation Mapping - Nesne İlişkisel Eşleşme) gerçekleştirimi, başka bir deyişle, ilişkisel veritabanı ile nesneler arasında eşlemeyi sağlayan teknoloji standardıdır.
JPA için en önemli kavram Entity (Varlık) kavramıdır. Entity, veritabanında nasıl saklanacağı tanımlanmış bir Java sınıfıdır. Örneğin bir sınıf, veritabanı üzerindeki bir tabloya karşılık gelebilir. Tablonun sütunları ile sınıfın değişkenleri veya yöntemleri eşleştirilebilir. Bir Entity sınıfı, @Entity ile tanımlanmalıdır. Sınıfın en az bir id (identity - kimlik) alanı olması ve @Id ile de işaretlenmesi gerekir.
Örneğin aşağıda bir entity sınıfı görülmektedir:
import javax.persistence.*;
@Entity
public class Product {
  @Id
  @GeneratedValue(strategy=GenerationType.AUTO)
  private int id;
  private String name;
  public int getId() {
    return id;
  }
  public void setId(int id) {
    this.id = id;
  }
  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }
}
Product (Ürün) sınıfı veritabanında product tablosu karşılığı olan bir sınıftır. Id alanı otomatik artan bir alandır ve bir de name (ad) sütunu bulunmaktadır.
@GeneratedValue (Üretilmiş Değer) ile id üretiminin nasıl olacağı verilmiştir. GenerationType (Üretme Türü), olarak AUTO (Kendinden), IDENTITY (Kimlik), SEQUENCE (Ardışım), TABLE (Tablo) değerleri verilebilir. IDENTITY, id alanının otomatik artmasını sağlar. SEQUENCE, veritabanında sequence'i kullanır. TABLE, id alanının, bir tablo kullanılarak artırılmasını sağlamak için kullanılır. Bu daha çok kurumsal projelerde, yüksek veritabanı bağımsızlığı sağlamak için tercih edilmektedir. AUTO ise id artırma sistemini veritabanına bırakmaktadır.
Eğer veritabanındaki tablo ile sınıf ismi farklı ise @Table (Tablo) ile isim verilebilir.
@Table(name="product", schema=”users”)
Benzer bir şekilde bir alan ile sütun adı aynı değilse @Column (Sütun) ile isim verilebilir. Sütun ile ilgili ek bilgiler (sütun tipi, boyutu, null olabilip olmaması vb..) @Column ile verilebilir. Örnek:
@Column(name=”ID”) 
JPA'da kullanılan önemli annotation'lar aşağıdaki gibi gösterilebilir :
  • Mapping-Eşleme
    • @Basic (Taban)
    • @Embedded (Gömülü)
    • @EmbeddedId (Gömülü Kim)
    • @Enumerated (Sayılandırılımış)
    • @Lob (Large Oject- İri Nesne)
    • @Temporal (Zamansal)
    • @OneToOne (Bire Bir)
    • @OneToMany (Bire Çok)
    • @ManyToOne (Çoka Bir)
    • @ManyToMany (Çoka Çok)
    • @Transient (Geçici)
  • Veritabanı İle İlgili Bilgi
    • @Table (Tablo)
    • @TableGenerator (Tablo Üretici)
    • @Column (Sütun)
    • @DiscriminatorColumn (Ayrıştırıcı Sütun)
    • @AttributeOverride(s) (Nitelik Ezme[ler])
    • @AssociationOverride(s) (Çağrışım[lar])
    • @JoinColumn (Katma Sütunu)
    • @JoinTable (Katma Tablosu)
    • @PrimaryKeyJoinColumn(s) (Birincil Açar Sütun[ları])
    • @SecondaryTable(s) (İkincil Tablo[lar])
    • @SequenceGenerator (Ardışım Üretici)
  • Davranış-Model
    • @Entity (Varlık)
    • @Id (Kimlik)
    • @IdClass (Kimlik Sınıfı)
    • @GeneratedValue (Üretilmiş Değer)
    • @MappedSuperclass (Eşleşmiş Üst Sınıf)
    • @Embeddable (Gömülebilir)
    • @Inheritance (Kalıtım)
    • @OrderBy (İle Sırala)
    • @DiscriminatorValue (Ayrıştırıcı Değer)
    • @Version (Sürüm)
    • @MapKey (Eşleşme Açarı)

JPA, bir standarttır. JPA sadece bir arayüz sağlar ve implementation (gerçekleştirim) içermez. JPA standardına uygun provider (sağlayıcı) sisteme eklemeniz gerekir. EclipseLink, TopLink, Hibernate gibi farklı provider'lar kullanılabilir. Provide'lar JPA standartlarına uygun geliştirmeyi yaparlar ve bu şekilde veritabanı ile ilgili işlemler yapılabilmektedir.

Bilgi/Açıklama

Persistence Unit ve persistence.xml

Bir JPA projesinde provider ayarları, veritabanı tanımları, entity sınıfları tanımları vb.. için persistence.xml dosyası kullanılır.
Birden fazla birbiriyle ilişkili entity sınıfı ve bu sınıflarla ilişkili ayarlardan oluşan gruba persistence unit (kalıcılık birimi) adı verilmektedir. Bir persistence unit tanım bilgileri persitence.xml dosyasında bildirilir.

Persistence XML

Aşağıdaki gibi bir persistence unit tanımlanabilir.
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0"
  xmlns="http://java.sun.com/xml/ns/persistence"  
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
      http://java.sun.com/xml/ns/persistence
        /persistence_2_0.xsd">
<persistence-unit name="JPATest" 
    transaction-type="RESOURCE_LOCAL">
  <provider>
      org.hibernate.jpa.
          HibernatePersistenceProvider  
  </provider>
  <class>com.test.jpa.Product</class>
  <properties>
    <property
      name="javax.persistence.jdbc.driver"
      value="com.mysql.jdbc.Driver" />
    <property 
      name="javax.persistence.jdbc.url"   
      value="jdbc:mysql://185.44.192.164/book" />
    <property 
      name="javax.persistence.jdbc.user"
      value="root" />
    <property
      name="javax.persistence.jdbc.password"
     value="xxx" />
  </properties> 
</persistence-unit>
</persistence>

EntityManager

Veritabanı ile ilgili işlemler yapmak için EntityManager (Varlık Yöneticisi) sınıfı kullanılır. EntityManager aşağıdaki gibi yaratılmaktadır :
EntityManagerFactory factory
  =Persistence
      .createEntityManagerFactory("JPATest");
EntityManager entityManager
   =factory.createEntityManager();
JPATest ifadesi persistence.xml de tanımlanmış persistence unit'in adıdır.
Eğer Maven kullanıyorsanız aşağıdaki gibi iki bağımlılığı ekleyebilirsiniz:
<dependency>
  <groupId>org.eclipse.persistence</groupId>
  <artifactId>
    javax.persistence
  </artifactId>
  <version>2.1.0</version>
</dependency>
<dependency>
  <groupId>org.hibernate</groupId>
  <artifactId>
     hibernate-entitymanager
  </artifactId>
  <version>4.3.6.Final</version>
</dependency>
Provider olarak Hibernate kullanılmıştır.

Test

Product tablosuna aşağıdaki gibi bir ürün ekleyebiliriz :
 
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
public class ProductAddTest {
  public static void main(String[] args) {
    EntityManagerFactory factory=Persistence
      .createEntityManagerFactory("JPATest");
    EntityManager entityManager=factory
      .createEntityManager();
    entityManager.getTransaction().begin();
    Product product=new Product();
    product.setName("Bilgisayar");
    entityManager.persist(product);
    entityManager.getTransaction().commit();
    entityManager.close();
    factory.close();
  }
}
EntityManager yarattıktan sonra transaction (işlembilgi) başlatılır. Yeni bir Product yaratılır ve persist (kalıcılandır) yöntemi ile veritabanına bilgilerin yazılması sağlanır. Sonra transaction için commit (işleme) yapılır ve Entity Manager kapatılır.
Aşağıdaki örnek ise 1 ID'li elemanı alır ve adını değiştirip veritabanına kaydeder:
import javax.persistence.*;
public class ProductAddTest {
  public static void main(String[] args) {
    EntityManagerFactory factory=Persistence
      .createEntityManagerFactory("JPATest");
    EntityManager entityManager=factory
      .createEntityManager();
    entityManager.getTransaction().begin();
    Product product=entityManager
      .find(Product.class, 1);
    product.setName("Buzdolabı");
    entityManager.merge(product);
    entityManager.getTransaction().commit();
    entityManager.close();
    factory.close();
  }
}

Sorgu

Yukardaki örnekte find() (bul) yöntemi verilen id'li elemanı bulmaktadır. İlk parametre Entity'in sınıfıdır. Örnekteki merge() (kaynaştır) yöntemi Entity'in son durumunu veritabanına geçerli hale getirir. Burada merge() yerine persist() yöntemi de kullanılabilirdi.
Bir entity, remove() (gider) yöntemiyle aşağıdaki gibi silinebilir :
  Product product=entityManager
    .find(Product.class, 1);
  entityManager.remove(product);
JPA, JPQL (Java Persistence Query Language - Java Kalıcılık Sorgulama Dili) adında SQL benzeri bir sorgu dilini desteklemektedir. JPA, doğrudan SQL dilini de desteklemektedir. Eğer veritabanına bağımlı bazı özellikler kullanmak istiyorsanız doğrudan SQL diliyle native query (yerli sorgu) kullanabilirsiniz.
Product tablosundaki tüm kayıtları JPQL kullanarak alabiliriz.
import java.util.*;
import javax.persistence.*;
public class ProductListTest {
  public static void main(String[] args) {
    EntityManagerFactory factory=Persistence
      .createEntityManagerFactory("JPATest");
    EntityManager entityManager=factory
      .createEntityManager();
    Query query=entityManager
      .createQuery(
        "select p from Product p");
    List<Product> list = query.getResultList();
    for (Product product : list) {
      System.out.println(
        product.getId()+":"+
          product.getName());
    }
    entityManager.close();
    factory.close();
  }
} 
Görüldüğü gibi
select p from Product p
şeklinde tüm product tablosunu alacak sorgu yazılmıştır. SQL dilinden farklılıklar bulunmaktadır.
Parametre ile where (orada) koşulu kullanılabilir:
Query query=entityManager
  .createQuery(
     "select p from Product p 
        where p.name=:name");
query.setParameter("name", "Bilgisayar");
List<Product> list = query.getResultList();
for (Product product : list) {
  System.out.println(
    product.getId()+":"+
      product.getName());
}
Parametreler :name şeklinde : ile belirtilirler.
Bir JPQL ile query çalıştırmak için createQuery() (sorgu yarat) yöntemi, normal SQL yazmak için ise createNativeQuery() (yerli sorgu yarat) yöntemi kullanılır.
Aynı örneği createNativeQuery ile yaparsak :
import java.util.*;
import javax.persistence.*;
public class ProductListNativeTest {
  public static void main(String[] args) {
    EntityManagerFactory factory=Persistence
        .createEntityManagerFactory("JPATest");
    EntityManager entityManager=factory
        .createEntityManager();
    Query query=entityManager
      .createNativeQuery(
         "select * from product",
           Product.class);
    List<Product> list = query.getResultList();
    for (Product product : list) {
      System.out.println(
        product.getId()+":"+
        product.getName());
    }
    entityManager.close();
    factory.close();
  }
}

Örnekte createNativeQuery() yöntemine ek olarak geri dönecek sınıfın adı verilmiştir. Sorgu normal bir SQL sorgusudur. JPA, select sonucu dönen değerlerden Product nesnelerini oluşturacaktır.
EntityManager sınıfında bulunan persist() (kalıcılandır) , merge() (kaynaştır), refresh() (yenile), clear() (temizle), remove() (gider), flush() (akıt) gibi yöntemleri anlayabilmek için transient (geçici), managed (yönetilen), attached (iliştirilmiş), detached (koparılmış), removed (giderilmiş) kavramlarının anlaşılması gerekir.
Durumlardan transient, new ile yaratılan bir nesnedir ve henüz veritabanı ile ilişkilendirilmemiştir. EntityManager tarafından veritabanı ile ilişkisi kurulmuş entity ise managed durumundadır. Veritabanından find ve query ile çekilen nesnelerde managed durumundadır. Eğer managed durumundaki bir nesne normal bir nesne durumuna geçerse yani veritabanı ile ilişkisi EntityManager tarafından yönetilecek durumda değil ise detached durumundadır. Buna karşın, remove() ile veritabanından kaldırılan bir nesne ise removed durumundadır. Eğer managed bir nesnenin son durumu veritabanına kaydedilmiş ise persistent haline geçmiştir.
EntityManager sınıfındaki persist() yöntemi new ile yaratılan bir nesneyi veritabanına kaydeder (persistent durumuna getirir) ve onu managed durumuna sokar (attach eder). Eğer zaten managed bir nesne ise onu doğrudan veritabanına kayıt eder.
EntityManager sınıfındaki merge() ise aynı id ile managed bir nesne detached durumundaysa managed hale getirir. Eğer managed bir nesne var ise nesne veritabanında doğrudan güncellenir. Eğer veritabanında yok ise yeni bir kayıt eklenir. Öte yandan persist() işleminde eğer veritabanında aynı nesne var ise exception oluşurken merge() yönteminde update işlemi gerçekleştirir. Bunun yanında merge() yöntemi detached nesneyi alabilir ve cevap olarak her zaman managed bir nesne verir.
EntityManager sınıfındaki remove() managed yöntemi bir nesneyi veritabanından kaldırmak için kullanılır. Entity, removed durumuna geçer. Tekrar persist() ile kayıt edilerek managed durumuna getirilebilir.
EntityManager sınıfındaki flush() yöntemi managed nesneler üzerinde yapılan tüm değişikliklerle veritabanını senkron durumuna getirir. Buradaki flush() yöntemi detached edilmiş veya transient durumundaki nesneler üzerinde herhangi bir işlem yapmaz
EntityManager sınıfındaki refresh() yöntemi managed nesneler üzerinde değişiklikler veritabanındaki duruma geri dönecek şekilde geri alınır.
EntityManager sınıfındaki clear() yöntemi managed bir nesneyi detached durumuna getirir.



Bu Sayfayı Paylaş:

İletişim/Bize Yazın   mh@fibiler.com   Google+   Facebook   Twitter   fibiler@googlegroups.com
Her Hakkı Saklıdır
Bu sitede yayınlanan tüm bilgi ve fikirlerin kullanımından fibiler.com sorumlu değildir.
Bu sitede üretilmiş , derlenmiş içerikleri, fibiler.com'u kaynak göstermek koşuluyla kendi sitenizde kullanılabilirsiniz. Ancak telif hakkı olan içeriklerin hakları sahiplerine aittir