فاضل فرنیا
فاضل فرنیا
خواندن ۳ دقیقه·۵ سال پیش

بررسی رفتار Hibernate در ذخیره و بروزرسانی

اگه از هایبرنیت به عنوان orm برای ارتباط با دیتابیس استفاده کنیم و تمام transaction های ذخیره و بازیابی بک اند و لایه مدل با هایبرنیت انجام بشه لازمه نکاتی رو در خصوص update کرده رکوردها درنظر بگیریم.

معمولا ذخیره و بروزرسانی با یک متد persist از entity managerانجام میشه بصورتیکه اگر entityارسالی id که همان primary key است داشته باشد یعنی قبلا ذخیره شده و الان دستور update باید انجام شود و اگر idنداشته باشه یعنی این entity باید یک رکورد در جدول مربوطه new کنه.

تو بحث ذخیره داده ها بصورتی که یک رکورد جدید ایجاد کند بسته به استراتژی انتخاب شده برای ست کردن id به عنوان pkکه معمولا یک sequence از دیتابیس حالا اوراکل، mysql و یا postgreSQL فرقی نمیکنه (هرچند نحوه پیاده سازی sequence در این دیتابیس ها متفاوت است) را با فراخوانی nextval در یک session بدست آورده و مقدارو تو id ست میکنه بعد entity رو واسه persistمیفرسته برای دیتابیس. اینجا برای جلوگیری از یک رفت و برگشت مدل به دیتابیس برای گرفتن sequence میشه بر اساس قابلیت دیتابیس انتخابی sequence.nextval به عنوان default value در ساختار اون جدول تعریف شه اینجوری دریافت pk و ذخیرش توی یه سشن دیتابیس انجام میشه.

برای بروزرسانی داده های موجود در یک جدول حالت های مختلف داره که بسته به هرکدوم تاثیرگذاری متفاوتی تو performance میتونه داشته باشه. اولا بر اساس مدل update کردن میتونه نحوه انجامش هم متفاوت باشه، فرض کنیم مثلا یه کاربر در جدول user تعریف کردیم و میخوایم تو حالت خاصی اونو فعالش کنیم یعنی فیلد activeرا true کنیم یعنی update کردن یه فیلد خاص بعضی وقتا هم نمیدونیم کدوم فیلد update شده و مجبوریم کل فیلدها را تو دستور update بزاریم که اگه جدول ما تعداد ستون هاش زیاد باشه دردسرساز خواهد شد. رفتار پیش فرض اینجوریه که برای updateکردن اول یه findById میزنیم که مطمئن شیم اون رکورد تو دیتابیس وجود داره اگه نداشت که exception از نوع not_found پرتاپ میشه و اگر رکورد موجود باشه کل اطلاعات اون رکورد فراخوانی شده و هر فیلدی که تغییری کرده مقدار جدید ست میشه و برا ذخیره به دیتابیس ارسال میشه که در این حال دستور update برای تک تک فیلدها چه تغییر کرده باشه چه نکرده باشه اجرا میشه حالا اگه بخوایم جلوگیری کنیم از این اتفاق، دو راه وجود داره یکی اینکه مستقیم دستور update رو بنویسیم و فیلد مورد نظر رو فقط update کنیم که تو این حالت از متد save خودمون استفاده نمی کنیم.

@Entity

public class Account {

@Id

private int id;

@Column

private String name;

@Column

private String type;

@Column

private boolean active;

// Getters and Setters

}

اینجا از spring data jpa استفاده میکنیم

@Repository

public interface AccountRepository extends JpaRepository<Account, Integer> {

}

حالا میخوایم یه فیلد رو update کنیم

Account account = accountRepository.findOne(ACCOUNT_ID);

account.setName("Test Account");

accountRepository.save(account);

و چیزی که تو لاگ میبینیم

update Account set active=?, name=?, type=? where id=?

حالت دوم که حالت بهینه تری است استفاده از annotation @DynamicUpdate بالاسر کلاس entityهست به این صورت که مثل همون روش قبلی یه findبا id مورد نظر میزنیم اگر پیدا شد و کل دیتای رکورد مورد نظر فراخوانی شد حالا فیلد مورد نظر رو ست میکنیم به مقدار جدید که تو این حالت اگر saveرو صدا بزنیم و show-sql ما true باشد دستور updateبا تک فیلد رو تو log میبینیم. در واقع DynamicUpdate@ به ما این اطمینان رو میده که فقط ستون های modified شده در sql statementخواهد آمد. در ضمن باید دقت کنیم استفاده از این annotation برای ما performance overhead داره و هرجایی ازش استفاده نکنیم جایی که جدول تعداد ستون های بالایی داره و ما فقط چند تا از اونارو لازمه update کنیم.

@Entity

@DynamicUpdate

public class Account {

// Existing data and methods

}

و چیزی که تو لاگ میاد

update Account set name=? where id=?
hibernatejpaspringdatabase
توسعه دهنده نرم افزار، دوستدار هنر علی الخصوص سینما و تئاتر، طبیعتگرد و عکاس
شاید از این پست‌ها خوشتان بیاید