MongoDB

MongoDB , NoSQL cross platformlu document tabanlı bir veritabanıdır. Mevcut en popüler veritabanlarından biridir. MongoDB, MongoDB Inc. tarafından geliştirilmiştir ve ücretsiz ve açık kaynaklı bir yazılım olarak yayınlanmaktadır.

Spring Data MongoDB projesi, MongoDB document veri tabanı ile entegrasyon sağlar.

Reaktif Programlama

Reaktif programlama , functional, event tabanlı, non blocking, ve streaming data işleme merkezli bir programlama paradigmasıdır. Reaktif terimi , fare tıklamaları veya G / Ç olayları gibi değişikliklere tepki göstermemizden gelir.

Reaktif uygulamalar daha iyi ölçeklenir ve çok sayıda streamindata uğraşırken daha verimli olurlar. Reaktif uygulamalar non blockingdir; işlemler bitene kadar kaynakları kullanmıyorlar.

Reaktif bir uygulama oluştururken, veritabanına kadar her şeyin reaktif olması gerekir.Bunun içinde Reaktif programlamayı destekleyen bir veritabanı kullanmamız gerekiyor. MongoDB reaktif desteğe sahip bir veritabanıdır.

Reaktif uygulamalar, verilerin kullanıcıya(consumer) gönderildiği event tabanlı bir model uygular. Veri tüketicisine abone denir, çünkü asenkron data streamı yayınlayan publishera abonedir.

Spring Reactor

Spring Reaktörü , Reaktif Streams Spesifikasyonuna dayanarak JVM’de non blocking uygulamalar oluşturmak için kullanılan reaktif bir kütüphanedir.

Reactor Projesi iki tür yayıncı sunar: Monove FluxFlux 0’dan N’ye kadar değerler üreten bir yayıncıdır. Birden çok öğe döndüren işlemler bu türü kullanır. Mono0 ile 1 arasında değer üreten bir yayıncıdır. Tek bir eleman döndüren işlemler için kullanılır.

Spring Boot MongoDB Reactive Örneği

Biz yapacağımız uygulamada, MongoDB veritabanı ile reaktif programlama örneği yapacağız.

Not: Varsayılan olarak, herhangi bir özel yapılandırma olmadan, Spring Boot test veritabanı adını kullanarak yerel olarak barındırılan bir MongoDB örneğine bağlanmaya çalışır .

İlk önce spring initializr kullanarak group idsi com,artifact id si spring-boot-reactive ve paket adı com.reactive olan hiçbir bağımlılığı olmayan bir spring boot projesi oluşturalım.

Proje Oluşturma

Proje adı olarak spring-boot-reactive verelim.Finish diyerek projemizi oluşturalım.

Uygulamamızın proje yapısı aşağıdaki gibi olmalıdır.

Proje Yapısı

Yapacağımı uygulama jdk 1.8 üzerinde çalışacaktır.

pom.xml dosyamıza aşağıdaki dependecyleri ekleyelim.

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb-reactive</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>

spring-boot-starter-data-mongodb-reactive starteri Spring Data MongoDB Reactive ve MongoDB document-oriented databaseyi kullanan bir frameworktür.

resource dizinindeki application.propertiese aşağıdaki ayarı ekleyelim.

spring.main.banner-mode=off

Biz bu application.properties’de Spring Boot banneri kapattık

Spring Boot, varsayılan olarak test veritabanını kullanarak yerel olarak erişilen bir MongoDB örneğine bağlanmaya çalışır.

Application.propertiese aşağıdaki ayarları ekleyerek mongo db ayarlarınızı yapılandırabilirsiniz.Ben aşağıdaki ayarları yapılandırdım.

# mongodb
spring.data.mongodb.host = localhost
spring.data.mongodb.port = 27017
spring.data.mongodb.database = testdb
spring.data.mongodb.username=mongo
spring.data.mongodb.password=mongo

MongoDb Docker

Bende mongo db ve mongo db nin monitoring aracı localde yüklü olmadığı için docker üzerinden mongo db yi ve mongo db monitoring aracı olan mongo expresssi oluşturacağım.Bunun için localinizde docker ve docker-compose yüklü olmalıdır.

Projenin root dizininde init-mongo.js adlı bir js dosyası oluşturun.

db.createUser({ user : "mongo", pwd : "mongo", roles: [ { role : "readWrite", db : "testdb" } ]
}
)

init-mongo.js dosyasında testdb adlı bir database oluşturduk.Bu testdbye de kullanıcı adı mongo ve şifresi mongo olan bir kullanıcı tanımladık.mongo kullanıcısına testdbye yazma ve okuma yetkisi verdik.

Root dizinde docker-compose.yml dosyası oluşturun.

version: '3'

services:
mongo:
image: mongo
environment:
MONGO_INITDB_ROOT_USERNAME: mongo
MONGO_INITDB_ROOT_PASSWORD: mongo
MONGO_INITDB_DATABASE: testdb
ports:
- 27017:27017
networks:
- mongo-compose-network
volumes:
- ./init-mongo.js:/docker-entrypoint-initdb.d/init-mongo.js:ro
# - ./db:/data/db

mongo-express:
image: mongo-express
ports:
- 8081:8081
environment:
ME_CONFIG_MONGODB_SERVER : mongo
ME_CONFIG_MONGODB_PORT: 27017
ME_CONFIG_MONGODB_AUTH_DATABASE: testdb
ME_CONFIG_MONGODB_AUTH_USERNAME: mongo
ME_CONFIG_MONGODB_AUTH_PASSWORD: mongo
ME_CONFIG_MONGODB_ADMINUSERNAME: mongo
ME_CONFIG_MONGODB_ADMINPASSWORD: mongo
ME_CONFIG_MONGODB_ENABLE_ADMIN : 'false'
links:
- mongo
networks:
- mongo-compose-network

networks:
mongo-compose-network:
driver: bridge

mongodb ve mongo express için gerekli yapılandırmaları ayarladık.mongodb localhostdan 27017 portundan erişilebilir.mongodb ayağa kalktığında testdbyi otomatik olarak oluşturulmaktadır.

mongo exprese localhostdan 8081 portundan erişilebilir.Otomatik olarak testdb sini monitoring edecek şekilde mongo expressi ayarladık.

Root dizinde docker-compose up -d komutunu çalıştırıp mongodbyi ve . mongo expressi localimizde kaldıralım.

mongodb ve mongo express localimizde başarılı bir şekide ayağa kalktı.

localhost:8081 adresinden mongo expressin arayüzüne erişelim.

Mongo Express Anasayfa

Otomatik olarak oluşturduğumuz testdbye mongo express üzerinden erişebiliyoruz.

Kod kısmına tekrardan dönelim.

Model Katmanının Oluşturulması

com.reactive paketi içerisinde model adlı bir paket oluşturalım.Bu paketin içerisinde City isimli bir class oluşturalım.

@Data
@NoArgsConstructor(access= AccessLevel.PRIVATE, force=true)
@RequiredArgsConstructor
@Document(value="cities")
public class City {
@Id
private String id;
@NonNull
private String name;
@NonNull
private int population;
}

City classı 3 tane attribute sahip.Bunlar id,name ve population

@Document(value="cities")
public class City {

@Document(value=”cities”) anatasyonu ile mongodb cities isimli bir Document oluşturacaktır.

 @Id private String id;

@Id anatasyonu ile spring her city objesi oluşturulduğunda otomatik olarak id üretecektir.

Repository Katmanının Oluşturulması

com.reactive paketi içerisinde repository adlı bir paket oluşturalım.Bu paketin içerisinde CityRepository isimli bir interface oluşturalım.

public interface CityRepository extends ReactiveMongoRepository<City,String> {
}

ReactiveMongoRepository repositoryden extend alarak Reaktif Mongo Repositorye sahip olduk.

com.reactive paketi içerisinde service adlı bir paket oluşturalım.Bu paketin içerisinde ICityService isimli bir interface oluşturalım.

public interface ICityService {

Mono<City> insert(City city);
Flux<City> saveAll(List<City> cities);
Mono<City> findById(String id);
Flux<City> findAll();
Mono<Void> deleteAll();
}

ICityService interfacesi 5 tane temel method tanımı içeriyor.

Service Katmanının Oluşturulması

Şimdide service paketi içerisinde CityService clasını tanımlayalım.

@RequiredArgsConstructor
@Service
public class CityService implements ICityService { private final CityRepository cityRepository; @Override public Mono<City> insert(City city) { return cityRepository.insert(city); } @Override public Flux<City> saveAll(List<City> cities) { return cityRepository.saveAll(cities); } @Override public Mono<City> findById(String id) { return cityRepository.findById(id); } @Override public Flux<City> findAll() { return cityRepository.findAll(); } @Override public Mono<Void> deleteAll() { return cityRepository.deleteAll(); }
}

com.h2 paketi içerisinde bootstrap adlı bir paket oluşturalım.Bu bootstrap paketinin içerisinde DataLoader adlı bir class oluşturalım.

@Slf4j
@RequiredArgsConstructor
@Component
public class DataLoader implements CommandLineRunner { private final CityService cityService; @Override public void run(String... args) throws Exception { log.info("Cities oluşturudu."); List<City> cities = Arrays.asList(new City("Bratislava", 432000), new City("Budapest", 1759000), new City("Prague", 1280000), new City("Warsaw", 1748000)); Mono<Void> one = cityService.deleteAll(); Flux<City> two = cityService.saveAll(cities); Flux<City> three = cityService.findAll(); three.subscribe(city -> log.info("{}", city)); Mono<Void> all = Mono.when(one, two, three); all.block(); }
} 

Bir command line runnerimiz var. Onun içinde run()methodu ile reaktif programlama kullanarak MongoDB erişiyoruz.

 Mono<Void> one = cityService.deleteAll();

Koleksiyonda varsa tüm şehirleri siliyoruz.

Flux<City> two = cityService.saveAll(cities);

Şehirlerin listesini mongoya kaydetiyoruz.

Flux<City> three = cityService.findAll();
three.subscribe(city -> log.info("{}", city));

Koleksiyondaki tüm şehirleri buluyoruz. Bu subscribe()methodu ile yayıncıya publisher oluruz ve alınan şehirleri terminale yazdırıyoruz.

 Mono<Void> all = Mono.when(one, two, three);

Mono.when()komutu 3 publisherda işini tamamladığında yerine getirilecektir ve 3 yayıncıyıda yeni bir mono içerisine toplar.

all.block();

block() methodu her 3 operasyonuda tetikler ve bu operasyonların tamamlanmasını bekler.. Bir konsol uygulamamız olduğundan, sonuçları terminale yazmak için bir blocking işlem başlattık.

subscribe()methodu işe başlar ve hemen döner. İşlemin, uygulamanın diğer bölümleri çalıştırıldığında gerçekleştirileceğini garanti etmiyoruz. block()methodu bloke edici bir işlemdir: bu işlem tetiklenir ve bu işlemin tamamlanması beklenir.

Not: Genel olarak, uygulamalarımızda blocklama çağrılarını nadiren kullanırız. Bukonsol uygulamasındaki işlemler birkaç istisnadan biridir.

Uygulamayı Çalıştırma

Uygulama kullanıma hazır. ./mvnw spring-boot:run komutu ile uygulamamızı çalıştıralım.

Uygulamayı Başlatma

Uygulamamız başarılı bir şekilde ayağa kalktı.

http://localhost:8081/ adresinden mongo expresse bağlanalım.

Mongo Express Anasayfa

testdb ye view deyip oluşturduğumuz cities collectiondaki oluşturduğumuz datalara bakalım.

Mongodb Cities Koleksiyonu

Görüldüğü üzere oluşturduğumuz 4 datada başarılı bir şekilde cities collectionunda oluşturulmuş.


Projenin Github Linki : https://github.com/susimsek/spring-boot-reactive

Slack Kanalımın Linki ;

https://join.slack.com/t/javadevelopercorp58/shared_invite/enQtODM3NzU5NDMzMjA1LWQ1YjFlZGE5MTI0ZDNjZDdlNGE4ZDE4NmM0NTBiODJlMTJiYmZjMjJiZTY3NzI0MTc5ZjJhZmQxN2MyMTlmYjU

Daha fazla konu içeriği ve çeşitliliği istiyorsanız slack kanalımı takip edebilirsiniz.

Responses

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