স্প্রিং-হাইবারনেটে সাধারণত পুরো অবজেক্ট আপডেট করতে হয় — কিন্তু যখন শুধুমাত্র একটা বা দুটো ফিল্ড পরিবর্তন করতে চান, তখন পুরো অবজেক্ট পাঠানো অপ্রয়োজনীয় ও ব্যয়বহুল। এই পোস্টে আমরা শিখব কীভাবে কার্যকরভাবে partial update বাস্তবায়ন করা যায়।
পার্শিয়াল আপডেট কেন দরকার?
স্প্রিং ডেটার repository.save() মেথড সবসময় পুরো অবজেক্টটা ডেটাবেসে লিখে দেয়। ছোট অবজেক্টের ক্ষেত্রে এটা সমস্যা নয়, কিন্তু বড় এবং জটিল এন্টিটিতে এটা কয়েকটা সমস্যা তৈরি করে:
| সমস্যা | সমাধান |
|---|---|
| বড় অবজেক্টের সব ফিল্ড নেটওয়ার্কে পাঠানো হয়, যদিও একটাই পরিবর্তন হয়েছে। | DTO + Optional ব্যবহার করে শুধু পরিবর্তিত ফিল্ডগুলো টার্গেট করা যায়। |
| ঘন ঘন আপডেট প্রয়োজন হলে প্রতিবার পুরো অবজেক্ট fetch করে আবার save করতে হয়। | কাস্টম JPQL query দিয়ে নির্দিষ্ট কলাম আপডেট করা যায়, পুরো row নয়। |
বাস্তব উদাহরণ — ব্লগ এডিটর
একজন লেখক এক ঘন্টা ধরে একটি দীর্ঘ পোস্ট লিখছেন। পোস্টের বডি বারবার আপডেট হওয়া দরকার — কিন্তু পোস্টের টাইটেল, ট্যাগ, কভার ইমেজ ইত্যাদি অপরিবর্তিত থাকে। এই পরিস্থিতিতে শুধু body ফিল্ডটাই আপডেট করা উচিত।
ডেটা ফ্লো:
কীস্ট্রোক → কাউন্টার +১ → কাউন্টার = ২০? → API কল → কাউন্টার রিসেট
ফ্রন্টএন্ড — Angular
ব্যবহারকারী যতবার এডিটরে কিছু টাইপ করেন, প্রতিবার API কল না করে একটি কাউন্টার ব্যবহার করা হয়। কাউন্টার নির্দিষ্ট সংখ্যায় পৌঁছালে তবেই আপডেট কল হয়।
১. Quill Editor — মডেল চেঞ্জ ইভেন্ট
<quill-editor
(ngModelChange)="updateBody()"
[(ngModel)]="post.body"
[styles]="{height: '300px'}">
</quill-editor>
২. কম্পোনেন্ট — কাউন্টার লজিক
bodyCounter = 0;
updateBody() {
this.bodyCounter++;
if (this.post.id && this.bodyCounter === 20) {
const payload = new Post();
payload.id = this.post.id;
payload.body = this.post.body;
this.adminPostService
.partialUpdate(payload)
.subscribe(() => {
this.bodyCounter = 0;
});
}
}
৩. সার্ভিস — HTTP কল
partialUpdate(post: Post): Observable<any> {
return this.http.put(
ApiUrl.adminPosts + 'partial-update/',
post
);
}
ব্যাকএন্ড — Java · Spring Data JPA
ব্যাকএন্ডে মূল কৌশল হলো একটি DTO তৈরি করা যেখানে প্রতিটি আপডেটযোগ্য ফিল্ডের জন্য একটি করে Optional মেথড থাকবে। কোনো ফিল্ড null পাঠানো হলে সেটা আপডেট হবে না — শুধু যে ফিল্ডে ভ্যালু আছে, সেটাই আপডেট হবে।
১. DTO — Optional সহ
@Data
public class PostPartialDto {
@NotNull
private String id;
private String body;
private Integer position;
/** body উপস্থিত থাকলে Optional.of(), না থাকলে Optional.empty() */
public Optional<String> body() { return Optional.ofNullable(body); }
public Optional<Integer> position() { return Optional.ofNullable(position); }
}
২. Service — Optional.ifPresent() দিয়ে শর্তসাপেক্ষ আপডেট
@Override
public Optional<Integer> partialUpdate(PostPartialDto dto) {
// body পাঠানো হলে শুধু body আপডেট হবে
dto.body()
.ifPresent(body ->
postRepository.updateBody(dto.getId(), body));
// position পাঠানো হলে শুধু position আপডেট হবে
dto.position()
.ifPresent(pos ->
postRepository.updatePosition(dto.getId(), pos));
return Optional.of(1);
}
৩. Repository — JPQL partial update query
@Modifying
@Transactional
@Query("update Post p set p.body = :body where p.id = :id")
Integer updateBody(
@Param("id") String id,
@Param("body") String body
);
@Modifying
@Transactional
@Query("update Post p set p.position = :position where p.id = :id")
Integer updatePosition(
@Param("id") String id,
@Param("position") Integer position
);
সারসংক্ষেপ
| স্তর | কৌশল |
|---|---|
| DTO | Optional মেথড সহ শুধু আপডেটযোগ্য ফিল্ড |
| Service | ifPresent() দিয়ে শর্তসাপেক্ষ Repository কল |
| Repository | @Modifying query দিয়ে নির্দিষ্ট কলাম আপডেট |
এই প্যাটার্ন ব্যবহার করলে বড় এন্টিটিতেও দক্ষতার সাথে partial update করা যায় — অপ্রয়োজনীয় ডেটা ট্রান্সফার এবং Hibernate-এর dirty checking overhead ছাড়াই।