نهادهای JPA و روابط DB
روز بخیر، همکاران!Entity چیست؟
یک موجودیت یک شی از زندگی واقعی است (مثلاً یک ماشین) که دارای ویژگی هایی است (درها، چرخ ها ، موتور). DB Entity: در این مورد، موجودیت ما در یک DB ذخیره می شود، همه چیز ساده است. چرا و چگونه ماشین را در پایگاه داده قرار می دهیم - بعداً به آن نگاه خواهیم کرد.DB Relationship چیست؟
مدتها پیش، در پادشاهی دور ، یک DB رابطه ای ایجاد شد . در این بانک اطلاعاتی داده ها در قالب جداول ارائه شده است. اما حتی الاغ شرک فهمید که لازم است مکانیزمی برای اتصال این میزها ایجاد شود. در نتیجه، 4 رابطه DB ظاهر شد : اگر برای اولین بار است که همه اینها را می بینید، دوباره به شما هشدار می دهم - بدتر می شود: به پیاده روی فکر کنید. ما تمام این روابط را با استفاده از یک مثال تجزیه و تحلیل خواهیم کرد و تفاوت بین آنها را درک خواهیم کرد.مثال ترسناک
ما یک پروژه خواهیم داشت که دارای 5 شاخه است: master، که در آن شرح پروژه وجود دارد، و 1 شاخه برای هر رابطه DB. هر شاخه شامل اسکریپت های SQL برای ایجاد یک DB و پر کردن آن با داده های آزمایشی، به علاوه یک کلاس Entity با نگاشت حاشیه نویسی خواهد بود. همچنین برای هر شاخه یک فایل پیکربندی Hibernate وجود خواهد داشت. من از DB تعبیهشده H2 برای پروژه استفاده خواهم کرد تا با جنبههای جداگانه Cloud DB یا DB خارجی منحرف نشم. با دنبال کردن لینک، H2 DB را روی جاروبرقی خود نصب کنید. من هر مرحله را در 1 شاخه توضیح خواهم داد، بقیه فقط نکات کلیدی هستند. در پایان به جمع بندی می پردازیم. برو این یک لینک به شاخه اصلی پروژه من است.رابطه یک به یک
لینک شعبه در اینجا-
ما باید H2 DB را به پروژه خود متصل کنیم. در اینجا باید تاکید کنیم که برای کار راحت با DB و سایر موارد به Ultimate IDEA نیاز داریم. اگر قبلاً آن را دارید، مستقیماً به اتصال DB بروید. به تب Database بروید و مانند تصویر زیر عمل کنید:
سپس به تنظیمات DB می رویم. شما می توانید داده های خود و حتی DBMS خود را وارد کنید؛ تکرار می کنم، من برای سادگی از H2 DB استفاده می کنم.
بعد، بیایید مدار را تنظیم کنیم. این مرحله اختیاری است اما اگر طرحواره های متعددی در DB دارید توصیه می شود.
تنظیمات را اعمال کنید و در پایان باید چیزی شبیه به این دریافت کنیم:
-
ما پایگاه داده را ایجاد کردیم و دسترسی به آن را از IDEA پیکربندی کردیم. اکنون باید جداول را در آن ایجاد کنید و آن را با مقداری داده پر کنید. به عنوان مثال، من دو نهاد را انتخاب می کنم: نویسنده و کتاب. یک کتاب ممکن است یک نویسنده داشته باشد، ممکن است چندین نویسنده داشته باشد، یا ممکن است یک نویسنده نداشته باشد. در این مثال ما انواع اتصالات را ایجاد خواهیم کرد. اما در این مرحله - رابطه یک به یک. بیایید اسکریپت مربوطه را ایجاد کنیم که جداول DB را ایجاد می کند :
DROP TABLE IF EXISTS PUBLIC.BOOK; CREATE TABLE PUBLIC.BOOK ( ID INTEGER NOT NULL AUTO_INCREMENT, NAME VARCHAR(255) NOT NULL, PRINT_YEAR INTEGER(4) NOT NULL, CONSTRAINT BOOK_PRIMARY_KEY PRIMARY KEY (ID) ); DROP TABLE IF EXISTS PUBLIC.AUTHOR; CREATE TABLE PUBLIC.AUTHOR ( ID INTEGER NOT NULL AUTO_INCREMENT, FIRST_NAME VARCHAR(255) NOT NULL, SECOND_NAME VARCHAR(255) NOT NULL, BOOK_ID INTEGER NOT NULL UNIQUE, CONSTRAINT AUTHOR_PRIMARY_KEY PRIMARY KEY (ID), CONSTRAINT BOOK_FOREIGN_KEY FOREIGN KEY (BOOK_ID) REFERENCES BOOK (ID) );
و بیایید آن را اجرا کنیم:
نتیجه اجرا در کنسول:
نتیجه در DB:
-
بیایید به نمودار جداول خود نگاه کنیم. برای انجام این کار، RMB در DB ما:
نتیجه:
در نمودار UML می توانیم تمام کلیدهای اصلی و کلیدهای خارجی را ببینیم، همچنین ارتباط بین جداول خود را می بینیم.
-
بیایید یک اسکریپت بنویسیم که DB ما را با داده های آزمایشی پر کند:
INSERT INTO PUBLIC.BOOK (NAME, PRINT_YEAR) VALUES ('First book', 2010), ('Second book', 2011), ('Third book', 2012); INSERT INTO PUBLIC.AUTHOR (FIRST_NAME, SECOND_NAME, BOOK_ID) VALUES ('Pablo', 'Lambado', 1), ('Pazo', 'Zopa', 2), ('Lika', 'Vika', 3);
یعنی چی میشه؟ رابطه یک به یک زمانی مورد نیاز است که موجودیت یک جدول با موجودیت دیگری مرتبط باشد (یا اگر NOT NULL از BOOK_ID حذف شود اصلاً مرتبط نباشد). در مثال ما، یک کتاب باید یک نویسنده داشته باشد. راه دیگری نیست.
-
حالا جالب ترین چیز این است که چگونه یک کلاس جاوا را با موجودیت های DB متصل کنیم؟ بسیار ساده. بیایید دو کلاس Book و Author ایجاد کنیم. با استفاده از یک مثال، کلاس 1 و زمینه های ارتباطی کلیدی را تجزیه و تحلیل خواهم کرد. بیایید کلاس Author را به عنوان مثال در نظر بگیریم :
@Data @Entity @DynamicInsert @DynamicUpdate @Table(name = "AUTHOR") public class Author { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "ID", nullable = false) private Long id; @Column(name = "FIRST_NAME", nullable = false) private String firstName; @Column(name = "SECOND_NAME", nullable = false) private String secondName; @OneToOne @JoinColumn(name = "BOOK_ID", unique = true, nullable = false) private Book book; }
- تمام فیلدهای کلاس ویژگی های موجودیت DB را تکرار می کنند.
- @Data (از Lombok ) میگوید که برای هر فیلد یک گیرنده و تنظیمکننده ایجاد میشود، برابر است، کد هش بازنویسی میشود و یک متد toString ایجاد میشود.
- @Entity می گوید که کلاس داده شده یک موجودیت است و با یک موجودیت DB مرتبط است.
- @DynamicInsert و @DynamicUpdate میگویند که درجها و بهروزرسانیهای پویا در DB انجام خواهند شد. اینها تنظیمات Hibernate عمیق تری هستند که برای شما مفید خواهند بود تا بچینگ صحیح را داشته باشید.
- @Table (name = "AUTHOR") کلاس Book را به جدول DB AUTHOR متصل می کند.
- @Id می گوید که این فیلد کلید اصلی است.
- @GeneratedValue (استراتژی = GenerationType.IDENTITY) – استراتژی تولید کلید اولیه.
- @Column (name = "ID"، nullable = false) یک فیلد را با ویژگی DB مرتبط می کند و همچنین می گوید که فیلد DB داده شده نمی تواند null باشد. این همچنین هنگام تولید جداول از موجودیت ها مفید است. روند معکوس به نحوه ایجاد پروژه خود، این در DB های آزمایشی برای تست های واحد مورد نیاز است.
- @OneToOne می گوید که فیلد داده شده یک فیلد رابطه یک به یک است.
- @JoinColumn (نام = "BOOK_ID"، منحصر به فرد = درست، پوچ = نادرست) - یک ستون BOOK_ID ایجاد می شود که منحصر به فرد است و پوچ نیست.
-
حال بیایید Hibernate را پیکربندی کنیم. برای انجام این کار، یک فایل hibernate.cfg.xml ایجاد کنید:
<?xml version='1.0' encoding='utf-8'?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD//EN" "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <property name="hibernate.dialect">org.hibernate.dialect.H2Dialect</property> <property name="hibernate.connection.driver_class">org.h2.Driver</property> <property name="hibernate.connection.url">jdbc:h2:~/db/onetoone</property> <property name="hibernate.connection.username">root</property> <property name="hibernate.connection.password"/> <property name="hibernate.hbm2ddl.auto">update</property> <property name="hibernate.show_sql">true</property> <property name="hibernate.format_sql">true</property> <property name="hibernate.use_sql_comments">true</property> <property name="hibernate.generate_statistics">true</property> <property name="hibernate.jdbc.batch_size">50</property> <property name="hibernate.jdbc.fetch_size">50</property> <property name="hibernate.order_inserts">true</property> <property name="hibernate.order_updates">true</property> <property name="hibernate.jdbc.batch_versioned_data">true</property> <mapping class="com.qthegamep.forjavarushpublication2.entity.Book"/> <mapping class="com.qthegamep.forjavarushpublication2.entity.Author"/> </session-factory> </hibernate-configuration>
- hibernate.dialect گویش DBMS است که ما انتخاب کرده ایم.
- hibernate.connection.driver_class - کلاس درایور DB ما.
- hibernate.connection.url - utl از DB ما. می توانید آن را از اولین نقطه ای که ما DB را پیکربندی کردیم، بگیرید.
- hibernate.connection.username - نام کاربری DB.
- hibernate.connection.password — رمز عبور کاربر DB.
- hibernate.hbm2ddl.auto - تنظیم تولید جدول. اگر بهروزرسانی شود، اگر قبلاً ایجاد شده باشد، تولید نمیکند، بلکه فقط آن را بهروزرسانی میکند.
- hibernate.show_sql - نمایش پرس و جوهای DB.
- hibernate.format_sql - آیا فرمت پرس و جوهای DB. اگر نه، همه آنها در یک خط خواهند بود. توصیه می کنم آن را روشن کنید.
- hibernate.use_sql_comments - نظرات پرس و جوهای DB. اگر این یک Insert باشد، بالای درخواست یک نظر نوشته می شود که درخواست از نوع Insert است.
- hibernate.generate_statistics - گزارشها را تولید میکند. من توصیه می کنم و توصیه می کنم حداکثر ثبت نام را تنظیم کنید. خواندن گزارش ها شانس شما را برای کار درست با ORM افزایش می دهد.
- hibernate.jdbc.batch_size - حداکثر اندازه دسته.
- hibernate.jdbc.fetch_size - حداکثر اندازه واکشی.
- hibernate.order_inserts - اجازه درج پویا را می دهد.
- hibernate.order_updates - بهروزرسانیهای پویا را میدهد.
- hibernate.jdbc.batch_versioned_data - امکان دسته بندی را فراهم می کند. به DBMS خود نگاه کنید: همه از این پشتیبانی نمی کنند.
- کلاس نگاشت - کلاس هایی که موجودیت های ما هستند. همه چیز باید فهرست شود.
-
حال باید جوهره ما مشخص شود. ما می توانیم این را در برگه پایداری بررسی کنیم:
نتیجه:
-
ما همچنین باید داده های اختصاصی را پیکربندی کنیم:
نتایج: ما نقشه برداری یک به یک را انجام داده ایم. مطالب فقط برای اهداف اطلاعاتی است، جزئیات در منابع موجود است.
رابطه یک به چند
لینک شعبه در اینجا من دیگر کد را در مقاله ارسال نمی کنم، زیرا در حال حاضر بسیار طولانی است. ما به تمام کدهای موجود در GitHub نگاه می کنیم.-
در نتیجه اجرای اسکریپت اولیه سازی، موارد زیر را دریافت می کنیم:
آیا تفاوت را با جدول قبلی احساس می کنید؟
-
نمودار:
رابطه یک به چند - یک نویسنده می تواند چندین کتاب داشته باشد. موجودیت سمت چپ مربوط به یک یا چند مورد سمت راست است.
-
تفاوت در نقشه برداری در حاشیه نویسی و فیلدها خواهد بود:
فیلدی در کلاس Author ظاهر می شود :
@OneToMany(fetch = FetchType.LAZY, mappedBy = "author") private Set<Book> books;
این در حال حاضر یک مجموعه است، زیرا ما می توانیم چندین کتاب داشته باشیم. @OneToMany در مورد نوع نگرش صحبت می کند. FetchType.Lazy می گوید که اگر در درخواست مشخص نشده باشد، نیازی به بارگذاری کل لیست کتاب ها نداریم. همچنین باید گفت که این فیلد را نمی توان به String اضافه کرد، در غیر این صورت شروع به کشیدن StackOverflowError می کنیم. لومبوک محبوب من از این امر مراقبت می کند:
@ToString(exclude = "books")
در کلاس Book ما بازخورد چند به یک انجام می دهیم:
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL) @JoinColumn(name = "AUTHOR_ID", nullable = false) private Author author;
در اینجا نتیجه می گیریم که One-to-Many تصویر آینه ای از Many-to-One است و بالعکس. لازم به تاکید است که Hibernate در مورد ارتباطات دو طرفه چیزی نمی داند. برای او، اینها دو ارتباط متفاوت هستند: یکی در یک جهت، دیگری در جهت مخالف.
-
هیچ چیز زیادی در hibernate.cfg.xml تغییر نکرده است .
-
ماندگاری:
رابطه چند به یک
از آنجایی که Many-to-One یک تصویر آینه ای از One-to-Many است، تفاوت های کمی وجود خواهد داشت. لینک شعبه در اینجا-
در نتیجه اجرای اسکریپت اولیه سازی، نتیجه زیر را دریافت می کنیم:
-
نمودار:
-
تفاوت در نقشه برداری در حاشیه نویسی و فیلدها خواهد بود:
دیگر مجموعهای در کلاس Author وجود ندارد، زیرا به کلاس Book منتقل شده است .
-
ماندگاری:
رابطه چند به چند
بیایید به سمت جالب ترین رابطه برویم. این رابطه طبق تمام قواعد نجابت و منافی عفت از طریق جدول اضافی ایجاد می شود. اما این جدول یک موجودیت نیست. جالبه، درسته؟ بیایید نگاهی به این گند بیاندازیم لینک شعبه در اینجا-
به اسکریپت اولیه نگاه کنید ، یک جدول HAS اضافی در اینجا ظاهر می شود. ما چیزی شبیه نویسنده-دارای-کتاب دریافت می کنیم.
در نتیجه اجرای اسکریپت، جداول زیر را دریافت خواهیم کرد:
-
نمودار:
در مثال ما، معلوم می شود که یک کتاب می تواند نویسندگان زیادی داشته باشد، و یک نویسنده می تواند کتاب های زیادی داشته باشد. ممکن است همپوشانی داشته باشند.
-
کلاس های نگاشت دارای مجموعه هایی در داخل کلاس ها خواهند بود. اما همانطور که گفتم جدول HAS یک موجودیت نیست.
کلاس نویسنده :
@ManyToMany @JoinTable(name = "HAS", joinColumns = @JoinColumn(name = "AUTHOR_ID", referencedColumnName = "ID"), inverseJoinColumns = @JoinColumn(name = "BOOK_ID", referencedColumnName = "ID") ) private Set<Book> books;
@ManyToMany یک نوع رابطه است.
@JoinTable - این دقیقاً همان چیزی است که ویژگی را با یک جدول HAS اضافی مرتبط می کند. در آن ما دو ویژگی را مشخص می کنیم که به کلیدهای اصلی دو موجودیت اشاره می کند.
کلاس کتاب :
@ManyToMany(fetch = FetchType.LAZY, mappedBy = "books") private Set<Author> authors;
در اینجا FetchType و فیلدی را که برای نگاشت استفاده خواهیم کرد را نشان می دهیم.
-
hibernate.cfg.xml ما دوباره بدون تغییر باقی ماند (من این واقعیت را در نظر نمیگیرم که برای هر شاخه یک DB جدید ایجاد کردهایم).
-
ماندگاری:
تشریح
بنابراین، ما به طور سطحی انواع روابط DB را بررسی کرده ایم و نحوه پیاده سازی آنها را در مدل ORM کشف کرده ایم. ما یک پروژه آزمایشی نوشتیم که تمام اتصالات را نشان می دهد و نحوه پیکربندی hibernate / jpa را فهمیدیم. فوولینک های مفید
- در واقع خود پروژه
- شعبه یک به یک
- شعبه یک به چند
- شعبه چند به یک
- شعبه چند به چند
- بخوانش
- و آن را بخوانید
GO TO FULL VERSION