Skip to content

1. مقدمه

1.1. Objectifs

نسخه PDF این سند در |ICI| موجود است.

نمونه‌های موجود در سند در |ICI| در دسترس هستند.

هدف در اینجا بررسی مفاهیم اصلی پایداری داده‌ها با استفاده از API JPA (Java Persistence API) است. پس از مطالعه این سند و آزمایش مثال‌ها، خواننده باید پایه‌های لازم را برای ادامه کار به‌تنهایی کسب کرده باشد.

API JPA یک توسعه جدید است. این قابلیت تنها از JDK 1.5 در دسترس بوده است. لایه JPA جایگاه خود را در یک معماری چندلایه دارد. بیایید یک معماری نسبتاً رایج از این نوع را در نظر بگیریم: معماری سه‌لایه:

  • لایه [1]، که در اینجا با نام [ui] (رابط کاربری) ذکر شده است، لایه‌ای است که از طریق یک رابط گرافیکی Swing، یک رابط کنسول یا یک رابط وب با کاربر تعامل دارد. نقش آن ارائه داده‌ها از کاربر به لایه [2] یا نمایش داده‌های ارائه‌شده توسط لایه [2] به کاربر است.
  • لایه [2]، که در اینجا با نام [metier] ذکر می‌شود، لایه‌ای است که قواعد کسب‌وکار موسوم به c.a.d را اعمال می‌کند. منطق خاص برنامه، بدون آنکه نگران باشد داده‌های ورودی از کجا می‌آیند یا نتایج تولیدشده به کجا می‌روند.
  • لایه [3]، که در اینجا با نام [dao] (ابژه دسترسی به داده) ذکر شده است، لایه‌ای است که داده‌های از پیش ذخیره‌شده (فایل‌ها، پایگاه‌های داده، ...) و بخشی از نتایج ارائه‌شده توسط لایه [2] را ذخیره می‌کند.
  • لایه [JDBC] لایه استاندارد مورد استفاده در جاوا برای دسترسی به پایگاه‌های داده است. این معمولاً به عنوان درایور JDBC SGBD شناخته می‌شود.

تلاش‌های فراوانی صورت گرفته است تا نوشتن این لایه‌های مختلف برای توسعه‌دهندگان آسان‌تر شود. در میان این‌ها، لایه JPA با هدف ساده‌سازی توسعه لایه [dao] که به داده‌های پایدار (persistent data) می‌پردازد، ایجاد شده است؛ از این رو به آن API (Java Persistence API) گفته می‌شود. یک راه‌حل که در سال‌های اخیر در این زمینه محبوبیت یافته، Hibernate است:

لایه [Hibernate] بین لایه [dao] که توسط توسعه‌دهنده نوشته شده و لایه [Jdbc] قرار دارد. هایبرنت یک ابزار ORM (نقشه‌برداری شیء–رابطه‌ای) است که شکاف میان دنیای رابطه‌ای پایگاه‌های داده و دنیای اشیاء قابل مدیریت با جاوا را پر می‌کند. توسعه‌دهنده لایه [dao] دیگر لایه [Jdbc] یا جداول پایگاه داده‌ای را که مایل به استفاده از محتوای آن‌هاست، نمی‌بیند. او تنها نمایش شیءی پایگاه داده را می‌بیند که توسط لایه [Hibernate] ارائه می‌شود. ارتباط بین جداول پایگاه داده و اشیایی که توسط لایه [dao] مدیریت می‌شوند، عمدتاً به دو روش برقرار می‌شود:

  • از طریق فایل‌های پیکربندی از نوع XML
  • از طریق حاشیه‌نویسی‌های جاوا در کد، تکنیکی که تنها از نسخه JDK 1.5 به بعد در دسترس است.

لایه [Hibernate] یک لایه انتزاعی است که برای شفاف بودن تا حد امکان طراحی شده است. هدف این است که توسعه‌دهنده‌ای که روی لایه [dao] کار می‌کند، کاملاً از اینکه با یک پایگاه داده سر و کار دارد، بی‌خبر باشد. این امر امکان‌پذیر است، به شرطی که خودشان مسئول نوشتن پیکربندی‌ای نباشند که دنیای رابطه‌ای و شیءگرا را به هم پیوند می‌دهد. پیکربندی این پل کار نسبتاً دشواری است و به مقداری تمرین نیاز دارد.

لایهٔ شیء [4] که منعکس‌کنندهٔ لایهٔ BD است، «زمینهٔ پایداری» نامیده می‌شود. یک لایه [dao] مبتنی بر Hibernate عملیات پایداری (CRUD: ایجاد – خواندن – به‌روزرسانی – حذف) را روی اشیاء در زمینه پایداری انجام می‌دهد؛ این عملیات توسط Hibernate به دستورات SQL تبدیل می‌شوند. برای عملیات پرس‌وجوی پایگاه داده (SQL Select)، هایبرنت یک زبان (زبان پرس‌وجوی هایبرنت) را در اختیار توسعه‌دهندگان قرار می‌دهد تا به جای خود پایگاه داده، از زمینه پایداری پرس‌وجو کنند.

هایبرنت محبوب است اما تسلط بر آن پیچیده است. منحنی یادگیری، که اغلب آسان جلوه داده می‌شود، در واقع بسیار تند است. به محض اینکه با پایگاه داده‌ای سر و کار داشته باشید که شامل جداول با روابط یک‌به‌چند یا چند‌به‌چند باشد، پیکربندی پل رابطه‌ای-به-شیء فراتر از توانایی‌های یک مبتدی معمولی است. سپس خطاهای پیکربندی می‌تواند به برنامه‌های کم‌کارایی منجر شود.

در دنیای تجاری، محصولی معادل Hibernate به نام Toplink وجود داشت:

با توجه به موفقیت محصولات ORM، شرکت سان، خالق جاوا، تصمیم گرفت یک لایه ORM را از طریق مشخصه‌ای به نام JPA استاندارد کند که همزمان با جاوا ۵ منتشر شد. مقررات JPA توسط هر دو Toplink و Hibernate پیاده‌سازی شده است. Toplink که در ابتدا یک محصول تجاری بود، از آن زمان به یک محصول متن‌باز تبدیل شده است. با JPA، معماری قبلی به شرح زیر در می‌آید:

لایه [dao] اکنون با مشخصه JPA، که مجموعه‌ای از رابط‌ها است، تعامل دارد. این امر استانداردسازی بیشتری را برای توسعه‌دهنده به ارمغان آورده است. پیش از این، اگر آن‌ها لایه ORM خود را تغییر می‌دادند، مجبور بودند لایه [dao] خود را نیز تغییر دهند، لایه‌ای که برای تعامل با یک ORM خاص نوشته شده بود. اکنون، آن‌ها یک لایه [dao] خواهند نوشت که با یک لایه JPA تعامل خواهد داشت. صرف‌نظر از اینکه کدام محصول این لایه را پیاده‌سازی می‌کند، رابط لایه JPA که به لایه [dao] ارائه می‌شود، یکسان باقی می‌ماند.

این سند مثال‌هایی از JPA را در حوزه‌های مختلف ارائه خواهد داد:

  • ابتدا، به پل رابطه‌ای/شیءمحور که لایه ORM ایجاد می‌کند، نگاه خواهیم کرد. این پل با استفاده از anotationهای Java 5 برای پایگاه‌داده‌هایی که در آن‌ها روابط یک‌به‌یک بین جداول وجود دارد، ایجاد می‌شود:
    • یک‌به‌یک
    • یک به چند
    • چند به چند

برای روشن‌سازی این حوزه، معماری‌های آزمایشی زیر را ایجاد خواهیم کرد:

برنامه‌های آزمایشی ما برنامه‌های کنسولی خواهند بود که مستقیماً با لایه JPA تعامل دارند. در این راستا، ما روش‌های اصلی لایه JPA را بررسی خواهیم کرد. ما در یک محیط موسوم به «Java SE» (ویرایش استاندارد) کار خواهیم کرد. JPA هم در محیط Java SE و هم در محیط Java EE5 (ویرایش سازمانی) اجرا می‌شود.

  • پس از تسلط بر پیکربندی پل رابطه‌ای/شیءگرا و استفاده از متدهای لایه JPA، به معماری چندلایه سنتی‌تر باز خواهیم گشت:

لایه [JPA] از طریق یک معماری دو لایه متشکل از [metier] و [dao] دسترسی خواهد داشت. چارچوب Spring [7]، و پس از آن کانtejner EJB3 از JBoss، برای پیوند دادن این لایه‌ها به یکدیگر استفاده خواهد شد.

قبلاً اشاره کردیم که JPA در محیط‌های SE و EE5 در دسترس است. محیط جاوا EE5 خدمات متعددی در ارتباط با دسترسی به داده‌های پایدار ارائه می‌دهد، از جمله استخرهای اتصال، مدیران تراکنش و غیره. ممکن است برای یک توسعه‌دهنده جالب باشد که از این خدمات استفاده کند. محیط جاوای EE5 هنوز به طور گسترده مورد استفاده قرار نگرفته است (مه ۲۰۰۷). این محیط در حال حاضر بر روی سرور برنامه‌های کاربردی Sun 9.x (GlassFish) در دسترس است. یک سرور برنامه‌های کاربردی در اصل یک سرور برنامه‌های کاربردی وب است. اگر در حال ساخت یک برنامه گرافیکی مستقل مانند یک برنامه Swing هستید، نمی‌توانید به محیط EE و خدماتی که ارائه می‌دهد دسترسی پیدا کنید. این یک مشکل است. ما در حال مشاهده محیط‌های «مستقل» EE و c.a.d هستیم. که می‌توان از آن‌ها خارج از یک سرور برنامه‌ای استفاده کرد. این مورد در مورد JBos و EJB3 صدق می‌کند که در این سند از آن‌ها استفاده خواهیم کرد.

در محیط EE5، لایه‌ها توسط اشیایی به نام EJB (Enterprise Java Beans) پیاده‌سازی می‌شوند. در نسخه‌های قبلی EE، لایه‌های EJB (EJB و 2.x) پیاده‌سازی و تست آن‌ها دشوار تلقی می‌شد و گاهی عملکرد ضعیفی داشتند. تفاوتی بین «اِنتیتی» EJB2.x و «سشن» EJB2.x قائل می‌شوند. به طور خلاصه، یک «اِنتیتی» EJB2.x نمایانگر یک سطر در یک جدول پایگاه داده است، در حالی که یک «سشن» EJB2.x ابجکتی است که برای پیاده‌سازی [metier] استفاده می‌شود، لایه‌های [dao] یک معماری چندلایه. یکی از انتقادات اصلی که به لایه‌هایی که با EJB پیاده‌سازی شده‌اند وارد می‌شود این است که آنها فقط می‌توانند در داخل کانتینرهای EJB، سرویسی که توسط محیط EE ارائه می‌شود، استفاده شوند. این امر تست واحد را مشکل‌ساز می‌کند. بنابراین، در نمودار بالا، تست‌های واحد برای لایه‌های [metier] و [dao] که با استفاده از EJB ساخته شده‌اند، مستلزم استقرار یک سرور اپلیکیشن هستند – عملیاتی نسبتاً دست‌وپاگیر که چندان توسعه‌دهندگان را به انجام مکرر تست‌ها ترغیب نمی‌کند.

چارچوب Spring در پاسخ به پیچیدگی EJB2 ایجاد شد. در یک محیط SE، Spring تعداد قابل توجهی از خدماتی را که معمولاً توسط محیط‌های EE ارائه می‌شوند، فراهم می‌کند. بنابراین، در حوزه «پایداری داده‌ها» - که در اینجا مورد توجه ماست - اسپرینگ استخرهای اتصال و مدیران تراکنش مورد نیاز برنامه‌های کاربردی را فراهم می‌کند. ظهور اسپرینگ، فرهنگ تست واحد را ترویج داده است، که ناگهان پیاده‌سازی آن بسیار آسان‌تر شده است. اسپرینگ امکان پیاده‌سازی لایه‌های یک برنامه را با استفاده از اشیاء استاندارد جاوا (POJO، Plain Old/Ordinary Java Object) فراهم می‌کند و این امکان را می‌دهد که این اشیاء در زمینه‌ای متفاوت دوباره استفاده شوند. در نهایت، این فریم‌ورک ابزارهای شخص ثالث متعددی را به شکلی نسبتاً شفاف یکپارچه می‌کند، به‌ویژه ابزارهای پایداری داده‌ای مانند Hibernate، iBatis و غیره.

Java EE5 برای رفع کاستی‌های مشخصه‌ی قبلی EE طراحی شد. EJB و 2.x به EJB3 تبدیل شده‌اند. این‌ها نمونه‌های POJOs هستند که با حاشیه‌نویسی‌ها برچسب‌گذاری شده‌اند و وقتی در یک کانتینر EJB3 قرار می‌گیرند، به اشیاء ویژه‌ای تبدیل می‌شوند. در داخل این کانتینر، EJB3 قادر خواهد بود از خدمات کانتینر (استخر اتصال، مدیر تراکنش و غیره) بهره‌مند شود. خارج از کانتینر EJB3، EJB3 به یک شیء معمولی جاوا تبدیل می‌شود. انوتیشن‌های EJB آن نادیده گرفته می‌شوند.

در بالا، ما Spring و JBoss EJB3 را به عنوان یک چارچوب احتمالی برای معماری چندلایه خود به تصویر کشیدیم. این چارچوب است که خدمات مورد نیاز ما را فراهم می‌کند: یک استخر اتصال و یک مدیر تراکنش.

  • در Spring، لایه‌ها با استفاده از POJOs پیاده‌سازی خواهند شد. این لایه‌ها از طریق تزریق وابستگی به این POJOs به خدمات Spring (استخر اتصال، مدیر تراکنش) دسترسی خواهند داشت: هنگامی که این POJOs نمونه می‌شوند، Spring مراجعی به خدماتی که به آنها نیاز دارند را تزریق می‌کند.
  • JBoss EJB3 یک کانتینر EJB است که قادر به اجرا در خارج از یک سرور برنامه است. اصل کار آن (از دیدگاه توسعه‌دهنده) مشابه آنچه برای Spring توصیف شده است می‌باشد. تفاوت‌های اندکی وجود دارد.

  • این سند را با مثالی از یک برنامه وب سه‌لایه به پایان می‌رسانیم که اگرچه ساده است، اما همچنان نمونه و نماینده‌ای مناسب است:

1.2. Références

[ref1]: پایداری جاوا با هایبرنت، نوشته کریستین بائر و گاوین کینگ، منتشر شده توسط منینگ.

[ref1] سندی است که مطالب زیر بر اساس آن ارائه شده است. این کتاب جامعی با بیش از ۸۰۰ صفحه در مورد استفاده از Hibernate در دو زمینهٔ متفاوت است: با یا بدون JPA. استفاده از Hibernate بدون JPA در واقع همچنان برای توسعه‌دهندگانی که از JDK 1.4 یا نسخه‌های قدیمی‌تر استفاده می‌کنند، کاربرد دارد، زیرا JPA تنها با JDK 1.5 ارائه شد.

پس از خواندن بیش از سه‌چهارم کتاب و مرور اجمالی بقیه، به این نتیجه رسیدم که همه چیز در این کتاب مفید است. کاربر باتجربه هایبرنیت باید با تقریباً تمام اطلاعات ارائه‌شده در ۸۰۰ صفحه آن آشنا باشد. کریستین بائر و گاوین کینگ جامع عمل کرده‌اند، اما به ندرت به جزئیاتی درباره موقعیت‌هایی که هیچ‌گاه پیش نمی‌آید، می‌پردازند. خواندن همه آن ارزشمند است. کتاب به سبک آموزشی نوشته شده است: در آن تمایل واقعی وجود دارد که هیچ چیزی در تاریکی باقی نماند. اینکه این کتاب هم برای استفاده از Hibernate با JPA و هم بدون آن نوشته شده است، برای کسانی که تنها به یکی از این فناوری‌ها علاقه‌مند هستند، یک چالش ایجاد می‌کند. برای مثال، نویسندگان با استفاده از مثال‌های متعدد، پل رابطه‌ای/شیءگرا را در هر دو زمینه توصیف می‌کنند. مفاهیم مورد استفاده بسیار شبیه به هم هستند، زیرا JPA به شدت از Hibernate الهام گرفته است. با این حال، تفاوت‌هایی وجود دارد. در نتیجه، چیزی که برای Hibernate صادق است ممکن است برای JPA صدق نکند، که در نهایت برای خواننده ایجاد سردرگمی می‌کند.

نویسندگان مثال‌هایی از برنامه‌های سه‌لایه را در چارچوب یک کانتینر EJB3 ارائه می‌دهند. آن‌ها به اسپرینگ اشاره‌ای نمی‌کنند. از یک مثال خواهیم دید که Spring، با این حال، استفاده از آن ساده‌تر است و دامنه وسیع‌تری نسبت به کانتینر JBoss EJB3 مورد استفاده در [ref1] دارد. با این وجود، *Java Persistence with Hibernate* کتابی عالی است که من به خاطر تمام مبانی‌ای که در مورد ORM پوشش می‌دهد، توصیه می‌کنم.

استفاده از ORM برای یک مبتدی پیچیده است.

  • برای پیکربندی پل رابطه‌ای/شیءگرا باید مفاهیمی را درک کرد.
  • مفهوم «زمینه پایداری» (persistence context) وجود دارد که با مفاهیم اشیاء در وضعیت‌های «پایدار شده» (persisted)، «جداشده» (detached) یا «جدید» (new) همراه است
  • مکانیزم‌های پیرامون پایداری (معاملات، استخرهای اتصال) وجود دارند که عموماً خدماتی هستند که توسط یک کانتینر ارائه می‌شوند
  • تنظیمات عملکردی برای پیکربندی وجود دارد (کش سطح دوم)
  • ...

ما این مفاهیم را با استفاده از مثال‌ها معرفی خواهیم کرد. قصد نداریم وارد جزئیات نظری زیادی در مورد آن‌ها شویم. هدف ما صرفاً این است که در هر مورد، خواننده بتواند مثال را درک کرده و آن را به نحوی در اختیار بگیرد که بتواند خود تغییرات لازم را در آن ایجاد کند یا آن را در زمینه‌ای متفاوت به کار گیرد.

1.3. ابزارهای مورد استفاده

نمونه‌های این سند از ابزارهای زیر استفاده می‌کنند. برخی از این ابزارها در ضمیمه‌ها (دانلود، نصب، پیکربندی، استفاده) توضیح داده شده‌اند. در این موارد، شماره بند و شماره صفحه ذکر شده است.

  • JDK 1.6 (بند 5.1)
  • IDE برای توسعهٔ جاوا در Eclipse 3.2.2 (بند 5.2)
  • افزونه Eclipse WTP (بسته ابزارهای وب) (بند 5.2.3)
  • پلاگین SQL Explorer اکلیپس (بخش 5.2.6)
  • افزونه ابزارهای Hibernate اکلیپس (بخش 5.2.5)
  • پلاگین Eclipse TestNG (بخش 5.2.4)
  • کانتینر سرولت Tomcat 5.5.23 (بخش 5.3)
  • SGBD فایربرد ۲.۱ (بخش ۵.۴)
  • SGBD MySQL5 (بخش ۵.۵)
  • SGBD PosgreSQL (بخش 5.6)
  • SGBD Oracle 10g Express (بخش 5.7)
  • SGBD SQL سرور ۲۰۰۵ اکسپرس (بخش ۵.۸)
  • SGBD HSQLDB (بخش 5.9)
  • SGBD آپاچی دربی (بخش 5.10)
  • اسپرینگ ۲.۱ (بخش ۵.۱۱)
  • EJB3 کانتینر برای JBoss (بخش 5.12)

1.4. دانلود مثال

در وب‌سایت این سند، مثال‌های پوشش‌داده‌شده را می‌توان به صورت یک فایل زیپ دانلود کرد که پس از استخراج، پوشه زیر را ایجاد می‌کند:

  • در [1]: ساختار دایرکتوری مثال‌ها
  • در [2]: پوشه <annexes> حاوی مواردی است که در بخش ANNEXES، پاراگراف 5 ارائه شده‌اند. به طور خاص، پوشه <jdbc> حاوی درایورهای JDBC از SGBD است که برای مثال‌های این آموزش استفاده می‌شوند.
  • در [3]: پوشه <lib> شامل پنج پوشه است که آرشیوهای مختلف .jar مورد استفاده در آموزش را در خود دارد.
  • در [4]: پوشه <lib/divers> شامل آرشیوهای زیر است: - درایورهای JDBC از SGBD - برای ابزار تست واحد [testNG] - ابزار لاگ‌گیری [log4j]
  • در [5]: آرشیوهایی برای پیاده‌سازی JPA/Hibernate و ابزارهای شخص ثالث مورد نیاز Hibernate
  • به [6]: آرشیوهای پیاده‌سازی JPA/Toplink
  • در [7]: آرشیوها برای Spring 2.x و ابزارهای شخص ثالث مورد نیاز برای Spring
  • در [8]: آرشیوهای کانتینر EJB3 از JBoss
  • در [9]: پوشه <hibernate> شامل مثال‌هایی است که از لایه پایداری JPA/Hibernate استفاده می‌کنند
  • در [10]: پوشه <hibernate/direct> شامل مثال‌هایی است که در آن لایه JPA مستقیماً با برنامه‌ای از نوع [Main] استفاده می‌شود.
  • در [11] و [12]: مثال‌هایی که در آن لایه JPA از طریق لایه‌های [metier] و [dao] در یک معماری چندلایه، که سناریوی عملیاتی استاندارد است، به کار گرفته می‌شود. سرویس‌ها (استخر اتصال، مدیر تراکنش) که توسط لایه‌های [metier] و [dao] استفاده می‌شوند، یا توسط Spring [11] یا توسط JBoss، EJB3 و [12].
  • در [13]: پوشه <toplink> از مثال‌های پوشه <hibernate> ([9]) استفاده می‌کند، اما این بار با لایه پایداری JPA/Toplink به جای JPA/Hibernate. در آنجادر [13] پوشه <jbossejb3> وجود ندارد، زیرا امکان راه‌اندازی مثالی که در آن لایه پایداری توسط Toplink و خدمات توسط کانتینر EJB3 از JBoss فراهم شود، وجود نداشت.
  • در [14]: یک پوشه <web> شامل سه مثال از برنامه‌های وب با لایه پایداری است JPA:
  • [15]: مثالی با استفاده از Spring / JPA / Hibernate
  • [16]: همان مثال با استفاده از Spring / JPA / Toplink
  • [17]: همان مثال با JBoss، EJB3 و JPA / Hibernate. این مثال کار نمی‌کند، احتمالاً به دلیل یک مشکل پیکربندی حل‌نشده. با این حال، این مثال گنجانده شده است تا خواننده بتواند آن را بررسی کرده و احتمالاً راه‌حلی برای این مشکل بیابد.

این آموزشگاه مکرراً به این ساختار دایرکتوری اشاره می‌کند، به‌ویژه هنگام آزمایش مثال‌های پوشش‌داده‌شده. از خوانندگان دعوت می‌شود این مثال‌ها را دانلود و نصب کنند. از این پس، ما به ساختار دایرکتوری مثال‌های توصیف‌شده در بالا به‌عنوان <examples> اشاره خواهیم کرد.

1.5. پیکربندی پروژه‌های « » اکلیپس از روی مثال‌ها

نمونه‌ها از کتابخانه‌های «user» استفاده می‌کنند. این‌ها آرشیوهای .jar هستند که تحت یک نام واحد گروه‌بندی شده‌اند. وقتی چنین کتابخانه‌ای در classpath یک پروژهٔ جاوا گنجانده می‌شود، همهٔ آرشیوهایی که در آن وجود دارد در آن classpath گنجانده می‌شوند. بیایید ببینیم چگونه این کار را در Eclipse انجام دهیم:

  • در [1]: [Window / Preferences / Java / Buld Path / User Libraries]
  • به [2]: یک کتابخانه جدید ایجاد کنید
  • در [3]: برای آن نامی انتخاب کرده و تأیید کنید
  • در [4]: فایل‌های JAR را برای گنجانده شدن در کتابخانه [jpa-divers] انتخاب کنید
  • در [5]: تمام فایل‌های JAR را از پوشه <examples>/lib/misc انتخاب کنید
  • در [6]: کتابخانهٔ کاربری [jpa-divers] تعریف شده است
  • به [7]: همین فرایند را برای ایجاد چهار کتابخانهٔ دیگر تکرار کنید:
کتابخانه
پوشه کتابخانه JAR
jpa-hibernate
<examples>/lib/hibernate
jpa-toplink
<examples>/lib/toplink
jpa-spring
<examples>/lib/spring
jpa-jbossejb3
<examples>/lib/jbossejb3