Hibernate bizim Java nesnelerimizi veritabanına kaydetmede,silme gibi süreçlerini yöneten bir framewoktür ve bütün low-level SQL sorgularını bizim yazmamıza gerek kalmadan bütün her şeyi kendisi halleder biz sadece Java kodumuzu yazarız.
Hibernate, JDBC (Java Database Connectivity) kullanarak yazdığımız kodları azaltır ve bizim için ORM (Object-Relational Mapping) sağlar.
ORM (Object-Relational Mapping) : Java sınıflarımız (class) ve veritabanı tablosu (Table) arasındaki eşleştirmeyi yapan tekniktir bu sayede biz INSERT,UPDATE gibi sorgular yazmayız user.setName() gibi Java nesneleri üzerinden veritabanı işlemleri yaparız ORM'de bu değişikleri bizim için SQL sorgularına çevirir.
JPA (Jakarta Persistence API) : Önceden biz buna Java Persistence API diyorduk, şimdi ismi değişti Jakarta oldu. Bu bizim ORM ilişkilerimizi tanımlamak için bir Standart API'dir. Sadece bir specificationdur ve birkaç interface tanımlar tabi interface (arayüz) tanımladığı için bunu kullanabilmek için ise bu implementationu sağlayan kütüphanelere ihtiyaç vardır bunlara da JPA Provider denir. En popüler sağlayıcılar ise Hibernate ve EclipseLink'tir.
Biz JPA Specificationunu implemente eden Hibernate'yi kullanacağız ve piyasada zaten ismi en çok; JPA/Hibernate olarak bilinir. Tabi bu arkada planda ise JDBC'yi kullanır. Biraz daha genel çerçevede bakalım.
JPA Annotations
JPAda bir kaç tane yaygın annotationu vardır.
@Entity
Entity Class : Veritabanıyla ilişkili olan Java classıdır. Bazı şeylere ihtiyacı vardır, bir classın "Entity Class" olabilmesi için minimum:
@Entity annotationu yazılması gereklidir.
1 tane no-argument public veya proected constructor'a sahip olmalıdır.
Tabi birden fazla da constructora da sahip olabilir.
@Table
Bu annotationu kullanarak veritabanındaki tablo ismiyle class'ı eşleştirebiliriz.
@Id
Bu sayede belirttiğimiz field'ın bir primary key olduğunu veritabanında belirtiyoruz.
@GeneratedType
Primary key'in hangi strateji de oluşturulacağını belirtiyoruz.
@Column
Tablo'da bulunan sütunun özelliklerini de burda belirtebiliyoruz.
Bir class'ın veritabanıyla ilişkisini kuralım.
@Entity
@Table(name = "student")
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;
@Column(name = "first_name")
private String firstName;
@Column(name = "last_name")
private String lastName;
public Student() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}Biz bunu Hibernate kullanarak veritabanına ekleme yaptığımız böyle bir çıktı verir
create table student (id bigint not null auto_increment, first_name varchar(255), last_name varchar(255), primary key (id)) engine=InnoDB
ID Oluşturma Stratejileri
GeneratedType annotationuda görüldüğü üzere strategy var bizim 5 adet GenerationType'miz var şimdi bunlara değinelim.
GenerationType.AUTO : Bizim veritabanıza uygun olarak bir tane strategy'yi kendisinin seçmesini istiyoruz. Eğer ki biz AUTO seçersek böyle bir çıktı verir.
GenerationType.SEQUENCE : Veritabanının sırasını kullanarak primary key ataması yap. Eğer ki biz SEQUENCE seçersek böyle bir çıktı verir.
GenerationType.IDENTITY : ID columnua bakarak primary keylerin atamasını yap. Eğer ki biz IDENTITY seçersek böyle bir çıktı verir.
GenerationType.TABLE :
GenerationType.UUID : Global olarak kullanılan UUID (Unique Identifier) kulanarak primary keylerin atamasını yap. Önemli nokta şudur; Student classınıda bulunan Long kısmını değiştirip UUID yapmamız gereklidir.
Eğer ki biz UUID seçersek böyle bir çıktı verir.
JPA/Hibernate bizim için veritabanında tabloları oluşturma ve silmeyle ilgili güzel bir özellik sağlıyor tabi bu süreçleri yapabilmek için öncelikle
application.properties dosyasına eklememiz gereken bir özellik bulunmaktadır.
spring.datasource.url=jdbc:mysql://localhost:3306/mydb
spring.datasource.username=root
spring.datasource.password=password
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect
ddl-auto kısımlarında birkaç tane özelliği vardır:
- none : Hiçbir action yapma
- create : Database tablolarını drop edip baştan yapılır.
- create-drop : Database tablolarını drop edip baştan yapılır ve uygulama kapatıldığında bütün database tabloları drop edilir.
- validate : Database tablolarının schemasını doğrular.
- update : Database tablolarının schemasını günceller.
DAO (Data Access Object)
Veritabanıyla ilişkileri yönetmede sorumlu classtır ve çok yaygın bilinen bir design patterndir.
public interface StudentDAO {
void persist(Student student);
}
JPA Entity Manager
JPA entity manager bir tane Data source ihtiyaç duyar. Data Source demek bizim veritabanına bağlantı bilgisini içerir. Tabi bu Entity Manager ve Data Source bizim application.properties'de verdiğimiz otomatik bilgilerle oluşturulur ve biz de DAO classımıza inject edebiliriz.
@Transactional ve @Repository
Şimdi biz artık DAO interfacemizi oluşturduk ve ekstra bu DAO'yu implement eden bir classa ihtiyacımız var bunun için de
@Repository
public class StudentDAOImpl implements StudentDAO{
private EntityManager entityManager;
@Autowired
public StudentDAOImpl(EntityManager entityManager) {
this.entityManager = entityManager;
}
@Override
@Transactional
public void persist(Student student) {
this.entityManager.persist(student);
System.out.println("Öğrenci kaydedildi!");
}
}@Transactional annotation bizim JPA kodumuz için bir transaction başlatır ve bitir bu sayede bizim entityManager'i açıp kapatmayla uğraşmayacağız.
@Repository annotation bizim DAO implementationalrına uyguladığımız bir annotationdur ve bu sayede Spring DAO implementationunu otomatik olarak kaydedecek ve artık component scanning özelliğinde otomatik olarak StudentDAO çağrıldığında StudentDAOImpl inject edilecektir.
Uygulamamızda da çağıralım.
@SpringBootApplication
public class HibernateApplication {
public static void main(String[] args) {
SpringApplication.run(HibernateApplication.class, args);
}
@Bean
public CommandLineRunner commandLineRunner(StudentDAO studentDAO){
return runner -> {
createStudent(studentDAO);
};
}
private void createStudent(StudentDAO studentDAO) {
Student student = new Student("Minter","Coder");
studentDAO.persist(student);
}
}Querying Objects
FindById
StudentDAO.java interfacemize eklememiz gereken:
Student findById(Long id);
StudentDAOImpl.java eklememiz gereken:
@Override
public Student findById(Long id) {
return this.entityManager.find(Student.class, id);
}@Transactional'a gerek yok çünkü herhangi bir update,create,delete gibi işlemler yapılmamaktadır.
FindAll
StudentDAO.java interfacemize eklememiz gereken:
List<Student> findAll();
StudentDAOImpl.java eklememiz gereken:
@Override
public List<Student> findAll() {
TypedQuery<Student> query = this.entityManager.createQuery("SELECT student FROM Student as student",Student.class);
List<Student> students = query.getResultList();
return students;
}Update Objects
StudentDAO.java interfacemize eklememiz gereken:
void update(Student student);StudentDAOImpl.java eklememiz gereken:
@Override
@Transactional
public void update(Student student) {
Student s = entityManager.find(Student.class, 1L);
s.setFirstName(student.getFirstName());
s.setLastName(student.getLastName());
this.entityManager.merge(s);
}Delete Objects
StudentDAO.java interfacemize eklememiz gereken:
void delete(Long id);
StudentDAOImpl.java eklememiz gereken:
@Override
@Transactional
public void delete(Long id) {
Student s = this.entityManager.find(Student.class, id);
this.entityManager.remove(s);
System.out.println("Öğrenci "+s.getFirstName()+" silindi!");
}En güncel hali
package net.mintercoder.hibernate;
import java.util.List;
import net.mintercoder.hibernate.data.entity.Student;
import net.mintercoder.hibernate.data.repository.StudentDAO;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
public class HibernateApplication {
public static void main(String[] args) {
SpringApplication.run(HibernateApplication.class, args);
}
@Bean
public CommandLineRunner commandLineRunner(StudentDAO studentDAO) {
return runner -> {
// createStudent(studentDAO);
// findStudentById(studentDAO);
// findAll(studentDAO);
// updateStudent(studentDAO);
deleteStudent(studentDAO);
};
}
private void createStudent(StudentDAO studentDAO) {
Student student = new Student("Minter", "Coder");
studentDAO.persist(student);
}
private void findStudentById(StudentDAO studentDAO) {
Student foundStudent = studentDAO.findById(1L);
System.out.println("Bulunan öğrenci : " + foundStudent.getFirstName() + " " + foundStudent.getLastName());
}
private void findAll(StudentDAO studentDAO) {
List<Student> students = studentDAO.findAll();
for (Student s : students) {
System.out.println(s.getFirstName() + " " + s.getLastName());
}
}
private void updateStudent(StudentDAO studentDAO) {
Student student = new Student("Minter2", "Coder2");
studentDAO.update(student);
}
private void deleteStudent(StudentDAO studentDAO) {
studentDAO.delete(1L);
}
}