GeneratedValue in JPA | GeneratedValue در JPA
توضیحات جلسه
جزوه و مستندات
مفاهیم کلیدی
- GeneratedValue
انوتیشنی در JPA است که برای تعیین استراتژی تولید خودکار مقدارها برای فیلدهای کلید اصلی یا Primary Key استفاده میشود. این انوتیشن به برنامهنویس اجازه میدهد بدون درگیر شدن با مدیریت دستی آیدیها، تولید مقدارهای منحصربهفرد را به دیتابیس یا JPA Provider بسپارد.
- GenerationType.IDENTITY
استراتژی تولید کلید اصلی است که بر قابلیت Auto-increment خود پایگاه داده تکیه دارد. در این حالت، دیتابیس پس از انجام عملیات Insert مقدار آیدی را تولید میکند. این روش در دیتابیسهایی مانند MySQL و PostgreSQL پشتیبانی میشود.
- GenerationType.SEQUENCE
استراتژیای است که از یک شیء جداگانه در پایگاه داده به نام Sequence برای تولید مقدارهای منحصربهفرد استفاده میکند. در این روش، قبل از انجام Insert، مقدار بعدی از Sequence دریافت میشود و به Entity اختصاص مییابد. این روش برای برنامههای بزرگ و پرترافیک بسیار بهینه است.
- GenerationType.TABLE
روشی است که از یک جدول جداگانه در دیتابیس برای شبیهسازی Sequence و نگهداری آخرین مقدار تولیدشده استفاده میکند. این استراتژی مستقل از نوع دیتابیس است، اما به دلیل نیاز به قفلگذاری و اجرای کوئریهای اضافه، کارایی یا Performance پایینتری دارد.
- GenerationType.AUTO
استراتژی پیشفرض است که در آن JPA Provider، مانند Hibernate، بر اساس نوع پایگاه داده متصل به پروژه، بهترین استراتژی تولید آیدی را انتخاب میکند.
- Allocation Size
پارامتری در SequenceGenerator است که تعیین میکند در هر بار درخواست به دیتابیس، چه تعداد شماره آیدی رزرو شود و در حافظه یا Cache برنامه نگهداری شود. این کار باعث کاهش تعداد مراجعهها به دیتابیس و افزایش سرعت میشود.
موارد مصاحبه ای
- چرا استفاده از
@GeneratedValueضروری است؟
در محیطهای عملیاتی که چندین کاربر بهصورت همزمان داده درج میکنند، مدیریت دستی آیدیها میتواند باعث خطای Duplicate Key Value شود. این انوتیشن تضمین میکند که هر رکورد یک کلید اصلی منحصربهفرد و غیرنال دریافت کند.
- تفاوت اصلی بین IDENTITY و SEQUENCE چیست؟
در استراتژی IDENTITY، مقدار آیدی بعد از اجرای دستور Insert مشخص میشود. بنابراین Hibernate نمیتواند عملیات درج گروهی یا Batch Insert را بهخوبی بهینه کند.
اما در استراتژی SEQUENCE، مقدار آیدی قبل از درج از دیتابیس گرفته میشود و این موضوع امکان بهینهسازی بهتر را فراهم میکند.
- چرا SEQUENCE برای برنامههای با مقیاس بزرگ Large Scale مناسبتر است؟
به دلیل قابلیت Allocation Size. برنامه میتواند برای مثال 50 عدد آیدی را یکجا از دیتابیس رزرو کند و در حافظه نگه دارد. تا زمانی که این ظرفیت پر نشود، نیازی به ارتباط مجدد با دیتابیس برای گرفتن آیدی جدید نیست. این موضوع فشار روی دیتابیس را بهشدت کاهش میدهد.
- کدام استراتژی بیشترین سازگاری را با انواع دیتابیسها دارد؟
استراتژی TABLE؛ زیرا تمام دیتابیسها از جدول پشتیبانی میکنند. با این حال، به دلیل Overhead بالا، فقط زمانی توصیه میشود که دیتابیس از Identity یا Sequence پشتیبانی نکند.
- مفهوم
GenerationType.AUTOدر دیتابیس PostgreSQL چگونه عمل میکند؟
در PostgreSQL، Hibernate بهصورت هوشمند تشخیص میدهد که این دیتابیس از Sequence پشتیبانی میکند. بنابراین بهصورت خودکار استراتژی را روی SEQUENCE تنظیم میکند و یک شیء توالی برای آن میسازد.
سناریو کاربردی
در یک سیستم مدیریت دانشجویان، کلاسی به نام Student تعریف شده است. در ابتدا اگر برنامهنویس بخواهد آیدی هر دانشجو را دستی وارد کند، باید مدام آخرین آیدی موجود در دیتابیس را بررسی کند و یکی به آن اضافه کند. این کار در سیستمهای واقعی و همزمان عملاً غیرقابلاعتماد است.
با قرار دادن @GeneratedValue(strategy = GenerationType.SEQUENCE) روی فیلد آیدی، Hibernate هنگام اجرای برنامه در PostgreSQL، یک شیء به نام student_table_seq در دیتابیس میسازد.
در هر بار ذخیره دانشجو، Hibernate ابتدا یک کوئری SELECT NEXTVAL اجرا میکند، شماره آیدی را دریافت میکند و سپس دانشجو را با آن آیدی ذخیره میکند.
اگر Allocation Size روی 50 باشد، Hibernate یک بار عدد را از دیتابیس میگیرد و برای 50 دانشجوی بعدی، آیدی را در حافظه خودش تولید میکند؛ بدون اینکه دوباره برای هر رکورد به دیتابیس درخواست بفرستد.
بیشتر بدانید
- نکته در مورد
@SequenceGenerator
برای شخصیسازی نام Sequence در دیتابیس و تنظیم allocationSize، باید از انوتیشن @SequenceGenerator در کنار @GeneratedValue استفاده کنید و نام آنها را از طریق فیلد generator به هم متصل کنید.
- نکته در مورد تنظیمات Hibernate
برای مشاهده نحوه ساخت جدولها و Sequenceها در کنسول، میتوانید در فایل persistence.xml خاصیت hibernate.hbm2ddl.auto را روی create-drop قرار دهید تا در هر بار اجرای برنامه، جدولها پاک شوند و دوباره با ساختار جدید ساخته شوند.
- توسعه با UUID
اگر پروژه شما بهجای اعداد از رشتههای طولانی و منحصربهفرد جهانی یا UUID استفاده میکند، JPA در نسخههای جدید استراتژی مخصوصی برای تولید خودکار این نوع آیدیها دارد که از طریق GenerationType.UUID در دسترس است.
