ישויות JPA && קשרי DB
יום טוב, עמיתים!מהי ישות?
ישות היא אובייקט מהחיים האמיתיים (לדוגמה, מכונית) שיש לו תכונות (דלתות, גלגלים , מנוע). DB Entity: במקרה זה, הישות שלנו מאוחסנת ב-DB, הכל פשוט. למה ואיך אנחנו מכניסים את המכונית למסד הנתונים - נסתכל על זה מאוחר יותר.מה זה DB Relations?
לפני זמן רב, בממלכה הרחוקה, נוצר DB יחסי . ב-DB זה הוצגו נתונים בצורה של טבלאות. אבל אפילו החמור משרק הבין שיש צורך ליצור מנגנון לחיבור השולחנות הללו. כתוצאה מכך, הופיעו 4 קשרי DB : אם אתה רואה את כל זה בפעם הראשונה, אני מזהיר אותך שוב - זה יחמיר: תחשוב על יציאה לטיול. ננתח את כל היחסים הללו באמצעות דוגמה, ונבין את ההבדל ביניהם.דוגמה לאימה
יהיה לנו פרויקט אחד שיהיו לו 5 סניפים: מאסטר, שבו יהיה תיאור הפרויקט, וענף 1 לכל קשר DB. כל ענף יכיל סקריפטים של SQL ליצירת DB ומילויו בנתוני בדיקה, בתוספת מחלקת Entity עם מיפוי הערות. יהיה גם קובץ תצורה של Hibernate עבור כל סניף. אני אשתמש ב-H2 משובץ DB עבור הפרויקט כדי לא להיות מוסחת על ידי היבטים בודדים של ענן DB או DB חיצוני. על ידי לחיצה על הקישור, התקן את H2 DB על שואב האבק שלך. אתאר כל שלב בענף אחד, השאר הם רק נקודות המפתח. בסוף נסכם. ללכת. זהו קישור לענף המאסטר של הפרויקט שלי.מערכת יחסים אחד לאחד
קישור לסניף כאן .-
אנחנו צריכים לחבר את H2 DB לפרויקט שלנו. כאן אנחנו צריכים להדגיש שאנחנו צריכים את Ultimate IDEA כדי לעבוד בנוחות עם DB ודברים אחרים. אם כבר יש לך את זה, אז עבור ישירות לחיבור DB. עבור ללשונית מסד נתונים ועשה כמו בצילום המסך:
לאחר מכן נעבור להגדרות DB. אתה יכול להזין את הנתונים שלך, ואפילו את ה-DBMS שלך; אני חוזר, אני משתמש ב-H2 DB בשביל הפשטות.
לאחר מכן, בואו נגדיר את המעגל. שלב זה הוא אופציונלי אך מומלץ אם יש לך סכימות מרובות ב-DB.
החל את ההגדרות, ובסופו של דבר אנחנו אמורים לקבל משהו כזה:
-
יצרנו את מסד הנתונים והגדרנו את הגישה אליו מ-IDEA. כעת עליך ליצור בו טבלאות ולמלא אותו בכמה נתונים. לדוגמה, אקח שתי ישויות: מחבר וספר. לספר יכול להיות מחבר, יכול להיות מספר מחברים, או שלא יהיה אחד. בדוגמה זו ניצור את כל סוגי החיבורים. אבל בשלב הזה - מערכת יחסים של אחד לאחד. בואו ניצור את הסקריפט המתאים שיוצר DB Tables :
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). בדוגמה שלנו, ספר אחד חייב להיות בעל מחבר אחד. אין דרך אחרת.
-
עכשיו הדבר המעניין ביותר הוא איך לחבר מחלקת Java עם ישויות DB? פשוט מאוד. בואו ניצור שתי כיתות ספר ומחבר. בעזרת דוגמה, אנתח שיעור 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 ) אומר שלכל שדה ייווצר getter ו-seter, equals, hashcode ידרוס, ותיווצר שיטת toString.
- @Entity אומר שהמחלקה הנתונה היא ישות ומשויכת לישות DB.
- @DynamicInsert ו- @DynamicUpdate אומרים שהוספות ועדכונים דינמיים יבוצעו ב-DB. אלו הן הגדרות Hibernate עמוקות יותר שיהיו שימושיות עבורך כך שתהיה לך אצווה נכונה.
- @Table (שם = "AUTHOR") קושר את מחלקת הספר לטבלת DB AUTHOR.
- @Id אומר שהשדה הזה הוא המפתח העיקרי.
- @GeneratedValue (אסטרטגיה = GenerationType.IDENTITY) – אסטרטגיית יצירת מפתח ראשי.
- @Column (שם = "ID", nullable = false) משייך שדה לתכונה DB, וגם אומר ששדה ה-DB הנתון אינו יכול להיות null. זה שימושי גם בעת יצירת טבלאות מיישויות. התהליך ההפוך לאופן שבו אנו יוצרים כעת את הפרויקט שלנו, זה נחוץ ב-DBs הבדיקה לבדיקות יחידה.
- @OneToOne אומר שהשדה הנתון הוא שדה קשר של אחד לאחד.
- @JoinColumn (שם = "BOOK_ID", ייחודי = true, nullable = false) - תיווצר עמודת BOOK_ID שהיא ייחודית ולא null.
-
עכשיו בואו נגדיר את מצב 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 אומר שאיננו צריכים לטעון את כל רשימת הספרים אם היא לא צוינה בבקשה. צריך גם לומר שאי אפשר להוסיף את השדה הזה ל-toString, אחרת נתחיל לעשן StackOverflowError. לומבוק האהוב שלי דואג לזה:
@ToString(exclude = "books")
בשיעור הספר אנו עושים משוב רב לאחד:
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL) @JoinColumn(name = "AUTHOR_ID", nullable = false) private Author author;
כאן אנו מסיקים שאחד-לרבים הוא תמונת המראה של רבים-לאחד ולהיפך. יש להדגיש כי Hibernate אינו יודע דבר על תקשורת דו-כיוונית. מבחינתו מדובר בשני קשרים שונים: האחד בכיוון אחד, השני בכיוון ההפוך.
-
שום דבר לא השתנה ב- hibernate.cfg.xml .
-
הַתמָדָה:
מערכת יחסים של רבים לאחד
מכיוון שרבים לאחד הוא תמונת מראה של אחד לרבים, יהיו מעט הבדלים. קישור לסניף כאן .-
כתוצאה מביצוע סקריפט האתחול, אנו מקבלים את התוצאה הבאה:
-
תרשים:
-
ההבדל במיפוי יהיה בהערות ובשדות:
-
הַתמָדָה:
מערכת יחסים של רבים לרבים
בואו נעבור למערכת היחסים המעניינת ביותר. מערכת יחסים זו, על פי כל כללי הגינות וחוסר הגינות, נוצרת באמצעות טבלה נוספת. אבל הטבלה הזו אינה ישות. מעניין, נכון? בואו נסתכל על החרא הזה. קישור לסניף כאן .-
תסתכל על סקריפט האתחול , טבלת 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