Spring Boot ve MongoDB Entegrasyonu: Modern Uygulama Geliştirme Rehberi
Günümüzün hızla değişen yazılım dünyasında, esneklik, ölçeklenebilirlik ve yüksek performans, modern uygulama geliştirmenin temel taşları haline gelmiştir. Bu ihtiyaçları karşılamak üzere ortaya çıkan teknolojilerden ikisi, uygulama geliştirme çerçevesi olarak Spring Boot ve NoSQL veritabanı olarak MongoDB’dir. Bu makalede, Spring Boot ve MongoDB’nin bir araya gelerek nasıl güçlü, dinamik ve verimli uygulamalar oluşturulabileceğini detaylı bir şekilde inceleyeceğiz. İki teknolojinin temel özelliklerinden başlayarak, entegrasyon adımlarına, kod örneklerine ve gelişmiş kullanım senaryolarına kadar geniş bir yelpazede bilgi sunacağız.
MongoDB’ye Kapsamlı Bir Bakış
MongoDB, belge tabanlı (document-oriented) bir NoSQL veritabanıdır. İlişkisel veritabanlarının aksine, verileri tablolar ve satırlar yerine JSON benzeri BSON (Binary JSON) formatında belgeler halinde depolar. Bu yaklaşım, modern uygulamaların dinamik veri yapılarına ve hızlı geliştirme süreçlerine mükemmel uyum sağlar.
Temel Özellikleri ve Avantajları:
* Şemasız Yapı (Schema-less): MongoDB’nin en önemli özelliklerinden biridir. Her belge, farklı alanlara sahip olabilir; bu da veri yapısında büyük bir esneklik sağlar. Uygulama gereksinimleri değiştikçe veritabanı şemasını değiştirmeye gerek kalmaz, bu da geliştirme hızını artırır.
* Yüksek Ölçeklenebilirlik: MongoDB, yatay ölçeklenebilirliği (horizontal scaling) destekler. Sharding adı verilen bir teknikle veriler birden fazla sunucuya dağıtılarak büyük veri kümeleri ve yüksek trafik yükleri kolayca yönetilebilir.
* Yüksek Performans: Bellek içi (in-memory) depolama motorları ve optimize edilmiş sorgu motoru sayesinde yüksek okuma ve yazma hızları sunar. Özellikle büyük veri kümeleri üzerinde karmaşık sorgular için etkilidir.
* Zengin Sorgu Dili: SQL’e benzer güçlü bir sorgu dili sunar. CRUD (Create, Read, Update, Delete) operasyonlarının yanı sıra, agregasyon çerçevesi (aggregation framework) ile karmaşık veri analizleri ve dönüşümleri yapılabilir.
* Esnek Veri Modeli: Belgeler, iç içe geçmiş (nested) belgeleri ve dizileri destekler. Bu, karmaşık veri ilişkilerini tek bir belge içinde modellemeye olanak tanır ve genellikle JOIN işlemlerine olan ihtiyacı azaltır.
* Replikasyon (Replication): Veri yedekliliği ve yüksek erişilebilirlik için replika setleri (replica sets) oluşturulabilir. Birincil sunucunun çökmesi durumunda otomatik olarak bir ikincil sunucu birincil hale gelir.
Ne Zaman MongoDB Kullanılmalı?
* Büyük Veri Uygulamaları: Terabaytlarca veya petabaytlarca veri ile uğraşan uygulamalar için ölçeklenebilirlik avantajı sunar.
* Gerçek Zamanlı Uygulamalar: Düşük gecikme süresi ve yüksek verim gerektiren oyunlar, IoT platformları, sosyal medya uygulamaları gibi senaryolarda idealdir.
* Esnek Şema Gerektiren Uygulamalar: Veri yapısının sık sık değiştiği veya henüz tam olarak tanımlanmadığı başlangıç projeleri veya çevik geliştirme ortamları için uygundur.
* İçerik Yönetim Sistemleri (CMS) ve Kataloglar: Çeşitli veri türlerini ve dinamik içerikleri depolamak için mükemmeldir.
Spring Boot’a Giriş
Spring Boot, Spring Framework’ün üzerine inşa edilmiş, mikroservis tabanlı uygulamaların hızlı ve kolay bir şekilde geliştirilmesini sağlayan bir araçtır. “Konfigürasyondan çok kural” (convention over configuration) prensibiyle çalışarak geliştiricilerin boilerplate kod yazma yükünü azaltır ve uygulamaları daha hızlı ayağa kaldırmalarına olanak tanır.
Temel Özellikleri ve Avantajları:
* Oto-Konfigürasyon (Auto-configuration): Uygulama sınıf yolundaki bağımlılıklara ve geliştiricinin tercihlerine göre otomatik olarak konfigürasyon yapar. Örneğin, bir veritabanı bağımlılığı eklediğinizde, Spring Boot otomatik olarak bir DataSource bean’i yapılandırabilir.
* Stand-alone Uygulamalar: Spring Boot uygulamaları, gömülü Tomcat, Jetty veya Undertow sunucuları ile bağımsız olarak çalışabilir. Bu, uygulamaları bir JAR dosyası olarak paketleyip kolayca dağıtmayı sağlar.
* Başlangıç Bağımlılıkları (Starter Dependencies): Yaygın kullanılan kütüphanelerin ve çerçevelerin kolayca eklenmesini sağlayan önceden tanımlanmış bağımlılık setleri sunar. Örneğin, spring-boot-starter-web web uygulamaları için gerekli tüm bağımlılıkları içerir.
* Üretime Hazır Özellikler: Sağlık kontrolleri, metrikler, harici konfigürasyon ve daha fazlası gibi üretime yönelik özellikleri kolayca entegre etmeye olanak tanır.
* Geliştirici Verimliliği: Azaltılmış konfigürasyon, hızlı başlangıç süreleri ve zengin ekosistem sayesinde geliştiricilerin iş mantığına odaklanmasını sağlar.
Neden Spring Boot ve MongoDB Birlikte Kullanılmalı?
Spring Boot ve MongoDB, modern uygulama geliştirmenin iki güçlü ayağını temsil eder. Bu iki teknolojinin birleşimi, geliştiricilere aşağıdaki önemli avantajları sunar:
* Spring Data MongoDB: Spring ekosisteminin bir parçası olan Spring Data MongoDB projesi, MongoDB ile etkileşim kurmayı son derece kolaylaştırır. Object-Document Mapping (ODM) yetenekleri sayesinde Java nesnelerini MongoDB belgelerine ve tersine dönüştürmek için boilerplate kod yazma ihtiyacını ortadan kaldırır.
* Esnek Veri Modeli ve Hızlı Geliştirme: MongoDB’nin şemasız yapısı, Spring Boot’un hızlı geliştirme felsefesiyle mükemmel uyum sağlar. Uygulama gereksinimleri değiştikçe hem kodda hem de veritabanı yapısında hızlı değişiklikler yapmak mümkün olur.
* Ölçeklenebilirlik: Spring Boot uygulamaları genellikle mikroservis mimarisinde geliştirilir ve yatay olarak ölçeklenebilir. MongoDB’nin doğal yatay ölçeklenebilirlik yeteneği (sharding), bu mimariye mükemmel bir destek sağlar.
* Zengin Ekosistem: Spring Boot, güvenlik (Spring Security), REST API geliştirme, test etme ve daha birçok alanda zengin bir ekosistem sunar. MongoDB entegrasyonu, bu ekosistemden tam olarak faydalanabilir.
* Performans: Spring Data MongoDB, performanslı sorgular ve veri erişimi için optimize edilmiştir. MongoDB’nin yüksek performanslı doğasıyla birleştiğinde, hızlı ve tepkisel uygulamalar geliştirmek mümkün olur.
Spring Boot ve MongoDB Projesi Kurulumu
Spring Boot ve MongoDB entegrasyonu için ilk adım, bir Spring Boot projesi oluşturmaktır.
1. Spring Initializr Kullanımı
Yeni bir Spring Boot projesi oluşturmanın en kolay yolu, Spring Initializr (start.spring.io) kullanmaktır. Aşağıdaki bağımlılıkları seçerek bir proje oluşturun:
* Project: Maven Project (veya Gradle)
* Language: Java
* Spring Boot: En son stabil sürüm
* Dependencies:
* Spring Web: RESTful API’ler oluşturmak için.
* Spring Data MongoDB: MongoDB ile entegrasyon için.
* Lombok (isteğe bağlı): Getter, Setter, Constructor gibi boilerplate kodları azaltmak için.
Projeyi oluşturduktan sonra ZIP dosyasını indirin ve favori IDE’nize (IntelliJ IDEA, VS Code, Eclipse vb.) aktarın.
2. MongoDB Bağlantı Ayarları
src/main/resources/application.properties (veya application.yml) dosyasına MongoDB bağlantı ayarlarını eklemeniz gerekir. Varsayılan olarak MongoDB, 27017 portunda test adında bir veritabanına bağlanmaya çalışır. Eğer farklı bir veritabanı veya sunucu kullanıyorsanız, bu ayarları değiştirmelisiniz.
Örnek application.properties:
spring.data.mongodb.host=localhost
spring.data.mongodb.port=27017
spring.data.mongodb.database=my_database_name
Eğer kimlik doğrulama gerekiyorsa:
spring.data.mongodb.username=myuser
spring.data.mongodb.password=mypassword
Bu ayarlar, Spring Boot uygulamanızın hangi MongoDB sunucusuna ve veritabanına bağlanacağını belirler.
Temel MongoDB İşlemleri için Model Oluşturma
MongoDB’de veriler belgeler (documents) halinde depolandığı için, bu belgelere karşılık gelen Java sınıfları (modeller) oluşturmamız gerekir. Spring Data MongoDB, bu model sınıflarını MongoDB belgeleriyle eşlemek için anotasyonlar sağlar.
Örnek bir Product (Ürün) modeli oluşturalım:
package com.example.mongodbdemo.model;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Field;
@Document(collection = "products") // Bu sınıfın MongoDB'deki 'products' koleksiyonuna eşleneceğini belirtir.
@Data // Lombok: Getter, Setter, toString, equals, hashCode metodlarını otomatik oluşturur.
@AllArgsConstructor // Lombok: Tüm argümanları içeren bir kurucu metod oluşturur.
@NoArgsConstructor // Lombok: Argümansız bir kurucu metod oluşturur.
public class Product {
@Id // Bu alanın MongoDB belgesinin _id alanı olduğunu belirtir.
private String id;
@Field("name") // MongoDB belgesindeki alan adını belirtir. Opsiyoneldir, varsayılan olarak Java alan adını kullanır.
private String name;
private String description;
private double price;
private int quantity;
private String category;
}
* @Document(collection = "products"): Bu anotasyon, Product sınıfının MongoDB’deki products koleksiyonuna eşleneceğini belirtir. Eğer belirtmezseniz, sınıf adının küçük harfle başlayan hali (örneğin product) varsayılan koleksiyon adı olarak kullanılır.
* @Id: Bu anotasyon, bir alanın MongoDB belgesinin birincil anahtarı olan _id alanına karşılık geldiğini işaret eder. Spring Data MongoDB, bu alanı otomatik olarak yönetir (örneğin, yeni bir belge kaydedilirken otomatik olarak bir ObjectId atar).
* @Field("name"): Bu anotasyon, Java sınıfındaki bir alan adının MongoDB belgesindeki farklı bir alan adıyla eşleşmesini sağlamak için kullanılır. Eğer Java alan adı ile MongoDB alan adı aynıysa bu anotasyonu kullanmak zorunlu değildir.
* @Data, @AllArgsConstructor, @NoArgsConstructor: Lombok anotasyonlarıdır ve boilerplate kodları azaltarak model sınıfını daha okunabilir hale getirir.
Repository Katmanı Oluşturma (Spring Data MongoDB)
Spring Data MongoDB, CRUD (Create, Read, Update, Delete) operasyonlarını ve özel sorguları son derece kolaylaştıran MongoRepository arayüzünü sunar.
ProductRepository adında bir arayüz oluşturalım:
package com.example.mongodbdemo.repository;
import com.example.mongodbdemo.model.Product;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.data.mongodb.repository.Query;
import java.util.List;
import java.util.Optional;
public interface ProductRepository extends MongoRepository<Product, String> {
// Spring Data JPA/MongoDB'nin isim kurallarına göre otomatik olarak sorgu oluşturur.
List<Product> findByCategory(String category);
List<Product> findByNameContaining(String name);
Optional<Product> findByName(String name);
// Fiyatı belirli bir değerden yüksek olan ürünleri bulmak için.
List<Product> findByPriceGreaterThan(double price);
// Özel bir MongoDB sorgusu tanımlamak için @Query anotasyonu kullanılır.
// JSON formatında bir sorgu dizesi alır. ?0 ilk metoda argümanını temsil eder.
@Query("{ 'category' : ?0, 'price' : { $gt: ?1 } }")
List<Product> findByCategoryAndPriceGreaterThan(String category, double price);
}
* MongoRepository: MongoRepository arayüzünü genişletiyoruz. İlk parametre, üzerinde işlem yapacağımız model sınıfı (Product), ikinci parametre ise modelin @Id ile işaretlenmiş alanının veri tipidir (String).
* Otomatik Sorgu Metotları: Spring Data MongoDB, metot isimlerine göre otomatik olarak sorgular oluşturabilir. Örneğin:
* findByCategory(String category): category alanına göre ürünleri bulur.
* findByNameContaining(String name): name alanında belirli bir dizeyi içeren ürünleri bulur.
* findByPriceGreaterThan(double price): price alanı belirli bir değerden büyük olan ürünleri bulur.
* @Query Anotasyonu: Eğer otomatik sorgu metotları yeterli gelmezse, @Query anotasyonunu kullanarak doğrudan MongoDB sorgu sözdizimi ile özel sorgular yazabilirsiniz. ?0, ?1 gibi ifadeler metot parametrelerini temsil eder.
Servis Katmanı Oluşturma
Servis katmanı, iş mantığını ve repository katmanı ile controller katmanı arasındaki köprüyü oluşturur.
package com.example.mongodbdemo.service;
import com.example.mongodbdemo.exception.ResourceNotFoundException;
import com.example.mongodbdemo.model.Product;
import com.example.mongodbdemo.repository.ProductRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
@Service // Bu sınıfın bir servis bileşeni olduğunu ve Spring tarafından yönetileceğini belirtir.
public class ProductService {
private final ProductRepository productRepository;
@Autowired // ProductRepository'yi enjekte eder.
public ProductService(ProductRepository productRepository) {
this.productRepository = productRepository;
}
public List<Product> getAllProducts() {
return productRepository.findAll();
}
public Optional<Product> getProductById(String id) {
return productRepository.findById(id);
}
public Product createProduct(Product product) {
return productRepository.save(product);
}
public Product updateProduct(String id, Product productDetails) {
Product product = productRepository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException("Product not found with id: " + id));
product.setName(productDetails.getName());
product.setDescription(productDetails.getDescription());
product.setPrice(productDetails.getPrice());
product.setQuantity(productDetails.getQuantity());
product.setCategory(productDetails.getCategory());
return productRepository.save(product);
}
public void deleteProduct(String id) {
Product product = productRepository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException("Product not found with id: " + id));
productRepository.delete(product);
}
public List<Product> getProductsByCategory(String category) {
return productRepository.findByCategory(category);
}
public List<Product> getProductsByNameContaining(String name) {
return productRepository.findByNameContaining(name);
}
}
* @Service: Bu anotasyon, Spring’e bu sınıfın bir servis bileşeni olduğunu ve bağımlılık enjeksiyonu için taranması gerektiğini bildirir.
* @Autowired: ProductRepository bağımlılığını enjekte etmek için kullanılır. Constructor enjeksiyonu, bağımlılık enjeksiyonu için önerilen yöntemdir.
* İş Mantığı: createProduct, updateProduct, deleteProduct gibi metotlar, repository’den çağrılarak iş mantığını yürütür. updateProduct metodu, güncellenecek ürünün var olup olmadığını kontrol etmek için bir istisna fırlatır (ResourceNotFoundException).
Not: ResourceNotFoundException özel bir istisna sınıfıdır. Kendi projenizde oluşturmanız gerekebilir:
package com.example.mongodbdemo.exception;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;
@ResponseStatus(HttpStatus.NOT_FOUND)
public class ResourceNotFoundException extends RuntimeException {
public ResourceNotFoundException(String message) {
super(message);
}
}
REST API Oluşturma (Controller Katmanı)
Controller katmanı, gelen HTTP isteklerini işler, servis katmanını çağırır ve HTTP yanıtlarını döndürür.
package com.example.mongodbdemo.controller;
import com.example.mongodbdemo.model.Product;
import com.example.mongodbdemo.service.ProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController // Bu sınıfın bir REST Controller olduğunu belirtir.
@RequestMapping("/api/products") // Tüm endpoint'ler için temel URL'yi belirler.
public class ProductController {
private final ProductService productService;
@Autowired
public ProductController(ProductService productService) {
this.productService = productService;
}
@GetMapping // Tüm ürünleri getirir. GET /api/products
public ResponseEntity<List<Product>> getAllProducts() {
List<Product> products = productService.getAllProducts();
return new ResponseEntity<>(products, HttpStatus.OK);
}
@GetMapping("/{id}") // Belirli bir ID'ye sahip ürünü getirir. GET /api/products/{id}
public ResponseEntity<Product> getProductById(@PathVariable String id) {
return productService.getProductById(id)
.map(product -> new ResponseEntity<>(product, HttpStatus.OK))
.orElseGet(() -> new ResponseEntity<>(HttpStatus.NOT_FOUND));
}
@PostMapping // Yeni bir ürün oluşturur. POST /api/products
public ResponseEntity<Product> createProduct(@RequestBody Product product) {
Product createdProduct = productService.createProduct(product);
return new ResponseEntity<>(createdProduct, HttpStatus.CREATED);
}
@PutMapping("/{id}") // Belirli bir ID'ye sahip ürünü günceller. PUT /api/products/{id}
public ResponseEntity<Product> updateProduct(@PathVariable String id, @RequestBody Product productDetails) {
Product updatedProduct = productService.updateProduct(id, productDetails);
return new ResponseEntity<>(updatedProduct, HttpStatus.OK);
}
@DeleteMapping("/{id}") // Belirli bir ID'ye sahip ürünü siler. DELETE /api/products/{id}
public ResponseEntity<HttpStatus> deleteProduct(@PathVariable String id) {
productService.deleteProduct(id);
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
@GetMapping("/category/{category}") // Kategoriye göre ürünleri getirir. GET /api/products/category/{category}
public ResponseEntity<List<Product>> getProductsByCategory(@PathVariable String category) {
List<Product> products = productService.getProductsByCategory(category);
return new ResponseEntity<>(products, HttpStatus.OK);
}
@GetMapping("/search") // İsme göre ürünleri arar. GET /api/products/search?name=keyword
public ResponseEntity<List<Product>> searchProductsByName(@RequestParam String name) {
List<Product> products = productService.getProductsByNameContaining(name);
return new ResponseEntity<>(products, HttpStatus.OK);
}
}
* @RestController: Bu anotasyon, sınıfın bir REST Controller olduğunu ve metotların doğrudan HTTP yanıtları döndüreceğini belirtir (yani @ResponseBody anotasyonuna gerek kalmaz).
* @RequestMapping("/api/products"): Bu anotasyon, bu controller’daki tüm endpoint’ler için temel URL yolunu belirler.
* @GetMapping, @PostMapping, @PutMapping, @DeleteMapping: HTTP metotlarına karşılık gelen anotasyonlardır.
* @PathVariable: URL yolundaki değişkenleri metot parametrelerine bağlamak için kullanılır (örneğin /products/{id}).
* @RequestBody: HTTP isteğinin gövdesindeki JSON veya XML verisini Java nesnesine dönüştürmek için kullanılır.
* @RequestParam: URL sorgu parametrelerini metot parametrelerine bağlamak için kullanılır (örneğin /products/search?name=keyword).
* ResponseEntity: HTTP yanıtının durum kodunu, başlıklarını ve gövdesini kontrol etmek için kullanılır.
Gelişmiş Konular
Spring Boot ve MongoDB entegrasyonu, temel CRUD işlemlerinin ötesinde birçok gelişmiş özelliği destekler.
1. Veri Doğrulama (Validation)
Gelen istek verilerinin doğruluğunu sağlamak için Bean Validation API’sini (Hibernate Validator implementasyonu ile) kullanabilirsiniz.
Model sınıfına javax.validation.constraints paketinden anotasyonlar ekleyin:
import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
// ... diğer import'lar ...
public class Product {
// ... id ...
@NotBlank(message = "Product name cannot be empty")
@Size(min = 3, max = 100, message = "Product name must be between 3 and 100 characters")
private String name;
private String description;
@NotNull(message = "Price cannot be null")
@Min(value = 0, message = "Price must be non-negative")
private double price;
@Min(value = 0, message = "Quantity must be non-negative")
private int quantity;
@NotBlank(message = "Category cannot be empty")
private String category;
}
Controller metodunda @Valid anotasyonunu kullanarak doğrulamayı tetikleyin:
import javax.validation.Valid;
// ...
@PostMapping
public ResponseEntity<Product> createProduct(@Valid @RequestBody Product product) {
Product createdProduct = productService.createProduct(product);
return new ResponseEntity<>(createdProduct, HttpStatus.CREATED);
}
2. İstisna Yönetimi (Exception Handling)
Uygulamanızdaki istisnaları merkezi olarak yönetmek için @ControllerAdvice ve @ExceptionHandler anotasyonlarını kullanabilirsiniz.
package com.example.mongodbdemo.exception;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.WebRequest;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(ResourceNotFoundException.class)
public ResponseEntity<?> handleResourceNotFoundException(ResourceNotFoundException ex, WebRequest request) {
ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getMessage(), request.getDescription(false));
return new ResponseEntity<>(errorDetails, HttpStatus.NOT_FOUND);
}
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<?> handleValidationExceptions(MethodArgumentNotValidException ex) {
Map<String, String> errors = new HashMap<>();
ex.getBindingResult().getFieldErrors().forEach(error ->
errors.put(error.getField(), error.getDefaultMessage()));
return new ResponseEntity<>(errors, HttpStatus.BAD_REQUEST);
}
@ExceptionHandler(Exception.class)
public ResponseEntity<?> handleGlobalException(Exception ex, WebRequest request) {
ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getMessage(), request.getDescription(false));
return new ResponseEntity<>(errorDetails, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
// ErrorDetails yardımcı sınıfı
class ErrorDetails {
private Date timestamp;
private String message;
private String details;
public ErrorDetails(Date timestamp, String message, String details) {
this.timestamp = timestamp;
this.message = message;
this.details = details;
}
// Getter metotları
public Date getTimestamp() { return timestamp; }
public String getMessage() { return message; }
public String getDetails() { return details; }
}
3. Dizinler (Indexes)
MongoDB’de sorgu performansını artırmak için indeksler kritik öneme sahiptir. Spring Data MongoDB, model sınıfında @Indexed anotasyonunu kullanarak indeksleri tanımlamanıza olanak tanır.
import org.springframework.data.mongodb.core.index.Indexed;
// ...
public class Product {
// ...
@Indexed(unique = true) // 'name' alanı üzerinde benzersiz bir indeks oluşturur.
private String name;
@Indexed // 'category' alanı üzerinde normal bir indeks oluşturur.
private String category;
// ...
}
Uygulama başladığında, Spring Data MongoDB bu anotasyonları okuyarak veritabanında gerekli indeksleri otomatik olarak oluşturacaktır.
4. Embedded Dokümanlar ve Referanslar
MongoDB’de ilişkisel verileri modellemenin iki ana yolu vardır:
* Embedded Dokümanlar: Bir belgeyi başka bir belge içine yerleştirmek. Genellikle “contains” (içerir) ilişkileri ve sıkça birlikte erişilen veriler için kullanılır. Performansı artırabilir, ancak belge boyutunu sınırlayabilir (16MB).
// Örnek: Adres bilgisini kullanıcı belgesine gömmek
public class User {
// ...
private Address address; // Address sınıfı da bir @Document olmasa da bir POJO olabilir.
// ...
}
public class Address {
private String street;
private String city;
// ...
}
* Referanslar: Belgeler arasında _id alanları aracılığıyla referanslar oluşturmak. Genellikle “references” (referans verir) ilişkileri ve seyrek erişilen veya büyük veriler için kullanılır. İlişkisel veritabanlarındaki JOIN’lere benzer şekilde, verileri almak için birden fazla sorgu gerekebilir. Spring Data MongoDB, @DBRef anotasyonu ile bu referansları yönetmeyi kolaylaştırır.
import org.springframework.data.mongodb.core.mapping.DBRef;
public class Order {
// ...
@DBRef // Bu alanın başka bir koleksiyondaki belgeye referans verdiğini belirtir.
private User customer; // User sınıfı ayrı bir koleksiyonda olmalı.
// ...
}
5. Agregasyon Çerçevesi (Aggregation Framework)
MongoDB’nin güçlü agregasyon çerçevesi, karmaşık veri analizleri ve dönüşümleri için kullanılır. Spring Data MongoDB, MongoTemplate veya @Aggregation anotasyonları aracılığıyla agregasyon boru hatlarını oluşturmayı destekler.
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.aggregation.GroupOperation;
import org.springframework.data.mongodb.core.aggregation.MatchOperation;
import org.springframework.data.mongodb.core.query.Criteria;
// ...
@Service
public class ProductService {
// ...
@Autowired
private MongoTemplate mongoTemplate;
public List<ProductCategoryStats> getProductCategoryStats() {
// Kategoriye göre toplam ürün miktarını ve ortalama fiyatı hesapla
GroupOperation groupByCategory = Aggregation.group("category")
.count().as("totalProducts")
.avg("price").as("averagePrice");
Aggregation aggregation = Aggregation.newAggregation(groupByCategory);
AggregationResults<ProductCategoryStats> result = mongoTemplate.aggregate(
aggregation, "products", ProductCategoryStats.class);
return result.getMappedResults();
}
}
// Sonuçları tutacak yardımcı sınıf
class ProductCategoryStats {
@Id
private String category;
private int totalProducts;
private double averagePrice;
// Getter/Setter ve constructor'lar
}
6. İşlemler (Transactions)
MongoDB 4.0 ve üzeri sürümlerde, replika setleri üzerinde çoklu belge işlemleri (multi-document transactions) desteklenmektedir. Spring Data MongoDB, @Transactional anotasyonu ile bu işlemleri kolayca entegre etmenize olanak tanır.
application.properties dosyasına spring.data.mongodb.transactions.enabled=true eklemeniz ve işlem yöneticisi bean’ini tanımlamanız gerekebilir.
import org.springframework.transaction.annotation.Transactional;
// ...
@Service
public class OrderService {
// ...
@Transactional // Bu metodun bir işlem içinde çalışmasını sağlar.
public void createOrderAndDecreaseStock(Order order, String productId, int quantity) {
// 1. Siparişi kaydet
orderRepository.save(order);
// 2. Ürün stokunu azalt
Product product = productRepository.findById(productId)
.orElseThrow(() -> new ResourceNotFoundException("Product not found"));
if (product.getQuantity() < quantity) {
throw new IllegalArgumentException("Not enough stock for product: " + product.getName());
}
product.setQuantity(product.getQuantity() - quantity);
productRepository.save(product);
// Eğer herhangi bir adım başarısız olursa, tüm işlem geri alınır.
}
}
Performans ve Optimizasyon İpuçları
Spring Boot ve MongoDB uygulamalarınızın performansını artırmak için bazı önemli ipuçları:
* Doğru İndeksleme: En sık sorgulanan alanlara ve sıralama yapılan alanlara indeks ekleyin. Benzersiz alanlar için benzersiz indeksler kullanın. explain() metodunu kullanarak sorgularınızın indeksleri nasıl kullandığını analiz edin.
* Veri Modelleme Stratejisi: Embedded dokümanlar ve referanslar arasındaki dengeyi iyi kurun. Sıkça birlikte erişilen veriler için gömme, seyrek erişilen veya büyük veriler için referans kullanın. Denormalizasyon, okuma performansını artırabilir.
* Sorguları Optimize Etme:
* projection: Yalnızca ihtiyacınız olan alanları döndürün (.fields().include("name", "price")).
* limit ve skip: Büyük sonuç kümeleri üzerinde sayfalama yaparken kullanın.
* Agregasyon boru hatlarında $match aşamasını mümkün olduğunca erken kullanın.
* Connection Pool Ayarları: application.properties dosyasındaki spring.data.mongodb.auto-index-creation gibi ayarları kontrol edin. Üretim ortamında indeks oluşturmanın otomatik olarak yapılmasını kapatmak isteyebilirsiniz.
* Okuma Tercihleri (Read Preferences): Replikasyon kullanıyorsanız, okuma işlemlerini ikincil sunuculara yönlendirerek birincil sunucunun yükünü azaltabilirsiniz.
* Yazma Endişeleri (Write Concerns): Veri tutarlılığı ve performans arasında denge kurmak için yazma endişelerini (örneğin, w: 1 veya w: "majority") ayarlayın.
Sonuç
Spring Boot ve MongoDB, modern, ölçeklenebilir ve yüksek performanslı uygulamalar geliştirmek için güçlü bir kombinasyon sunar. Spring Boot’un hızlı geliştirme yetenekleri ve MongoDB’nin esnek, şemasız veri modeli, geliştiricilere çeviklik ve verimlilik sağlar. Spring Data MongoDB projesi ise Java uygulamalarından MongoDB ile etkileşimi son derece basitleştirir.
Bu makalede, bir Spring Boot projesinin MongoDB ile nasıl entegre edileceğinden, temel CRUD operasyonlarından, model, repository, servis ve controller katmanlarının nasıl oluşturulacağından bahsettik. Ayrıca veri doğrulama, istisna yönetimi, indeksleme, veri modelleme stratejileri ve agregasyon gibi gelişmiş konulara da değindik.
Günümüzün veri yoğun ve dinamik uygulama gereksinimlerinde, Spring Boot ve MongoDB entegrasyonu, geliştiricilere sağlam bir temel sunarak karmaşık problemleri çözmeleri ve yenilikçi çözümler üretmeleri için gereken araçları sağlar. Bu rehber, kendi Spring Boot ve MongoDB uygulamalarınızı geliştirirken size yol göstermeyi amaçlamaktadır.