Spring Boot&Caching 1 – Spring Cache

Merhabalar.

Bu yazı ve gelecek iki yazı ile birlikte bir Spring Boot projesinde caching işlemlerini hangi yazılım ile nasıl yapabiliriz ona bakıyor olacağız. Bu yazıda Spring Framework’ün caching desteğine bakacağız. Gelecek iki yazıda da Redis ve MemCache’in Spring Boot projesinde nasıl kullanıldığını inceleyeğiz.

Başlayalım.

AMAÇ :

Bu yazı ile bir Spring Boot projesinde cache mekanizması kullanarak performans kazanmayı göstermek amaçlanmaktadır.

VERİ SETİ:

Veritabanımda driver tablosunda şu şekilde 10 kayıt bulunmakta. Şimdi yapacağımız örnekte ben id ile bir sorgulama yapacağım ve cache’lemenin bu sorgulamadaki performans etkisini inceleyeceğiz.

ÖRNEK KODLAR:

Driver tablomuza karşılık gelen entity sınıfımız.

package com.ilkaygunel.entities;

import javax.persistence.*;

@Entity
public class Driver {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @Column(name = "name")
    private String name;

    @Column(name = "surname")
    private String surname;

    public Long getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSurname() {
        return surname;
    }

    public void setSurname(String surname) {
        this.surname = surname;
    }
}

Driver tablomuz ile ilgili DB operasyonlarını gerçekleştirmemizi sağlayan repository interface’imiz. Bu interface içerisinde findById metodumuzun @Cacheable ile işaretli olduğuna dikkatinizi çekmek istiyorum. @Cacheable notasyonu findById metoduna parametre olarak geçilen id ile veritabanında kayıt bulunabilirse bunu getDriverById key’i ve gelen id bilgisi ile birlikte bizim için cache’liyor.

package com.ilkaygunel.repository;

import com.ilkaygunel.entities.Driver;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import java.util.Optional;

@Repository
public interface DriverRepository extends JpaRepository<Driver, Long> {
    Optional<Driver> findByName(String name);
    @Cacheable("getDriverById")
    Optional<Driver> findById(Long id);
}

Driver tablomuz ile ilgili işlemleri gerçekleyebilmemiz için kullandığımız DeviceService sınıfımız. Buradaki getDriverById metodu gelen id parametresi ile repository üzerinden db sorgulaması yapıyor ve bu sınıf içerisindeki getDriverById metodunun çalışma süresini bizim için konsola yazdırıyor.

package com.ilkaygunel.service;

import com.ilkaygunel.entities.Driver;
import com.ilkaygunel.repository.DriverRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.Duration;
import java.time.Instant;
import java.util.Optional;

@Service
public class DriverService {

    private final DriverRepository driverRepository;

    @Autowired
    public DriverService(DriverRepository driverRepository) {
        this.driverRepository = driverRepository;
    }

    public Driver getDriverById(Long id) {
        Instant start = Instant.now();
        try {
            return driverRepository.findById(id).orElseThrow(() -> new RuntimeException("Couldn't find any driver with that id!"));
        } finally {
            Instant finish = Instant.now();
            long time = Duration.between(start, finish).toMillis();
            System.out.println("Taking Time " + time + " ms");
        }
    }

}

Dışarıdan gelecek API isteklerini karşılayacak DriverController sınıfımız. Buradaki getDriverById servisi URL parametresi olarak gelen id bilgisini DriverService’e geçip gelen bilgiyi client’a döndürüyor.

package com.ilkaygunel.api;

import com.ilkaygunel.entities.Driver;
import com.ilkaygunel.service.DriverService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.*;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/driver")
public class DriverController {

    private final DriverService driverService;

    @Autowired
    public DriverController(DriverService driverService) {
        this.driverService = driverService;
    }

    @RequestMapping(method = RequestMethod.GET, value = "/driver/{driverId}")
    public ResponseEntity<Driver> getDriverById(@PathVariable(value = "driverId") Long driverId) {
        Driver driver = driverService.getDriverById(driverId);
        return new ResponseEntity<>(driver, HttpStatus.OK);
    }

}

DEMO:

Şimdi bu kaynak kodumuzun bir demosunu yapalım.

Şimdi localhost:8080/driver/driver/1 adresine tarayıcı üzerinden istek gönderip uygulama loglarını kontrol ettiğimde veri ilk defa veritabanından çekiliyor ve metodumuzun çalışma süresi 177 ms olarak görünüyor.

Şimdi aynı isteği tekrarlıyorum. Bu kez metodun çalışma süresi 12 milisaniye inmiş durumda.

Şimdi ise üst üste aynı adresi 3 defa daha çağırıyorum ve görebileceğiniz gibi 0-1 milisaniye bandına kadar bir düşüm süresi yakalayabiliyorum.

SONUÇ:

Yukarıda yaptığımız demo’dan görebileceğimiz üzere bir veriyi sürekli db’ye gidip sorgulamak yerine cache’e koyup db’ye gitmeden alıp kullanmak bize ciddi bir performans getirisi sağlayabilir. Tabii ki bu noktada her türlü verinin cache’e koyulabilecek veri olmadığını da unutmamak lazım. Özellikle Payment dünyasında her ne kadar hızlı ve performanslı bir sistem istense de anlık değişen/değişme ihtimali bulunan veriler için de veritabanına sorgulama yapmak kaçınılmaz olur.

Bu yazı ile birlikte bir Spring Boot projesinde Spring’in Caching mekanizması ile nasıl veri cache’leyebiliriz onu görmüş olduk. Gelecek yazıda Spring Boot ve Redis’in birlikte kullanımını irdeleyeceğiz.

Görüşene kadar hoşçakalın.

Latest posts by İlkay Günel (see all)

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir