JavaRush /مدونة جافا /Random-AR /كيانات JPA وعلاقات قاعدة البيانات
Nikita Koliadin
مستوى
Днепр

كيانات JPA وعلاقات قاعدة البيانات

نشرت في المجموعة

كيانات JPA وعلاقات قاعدة البيانات

يوم جيد أيها الزملاء!
كيانات JPA وعلاقات قاعدة البيانات - 1
هذه المادة مخصصة لأولئك الذين لديهم بالفعل فهم لتنظيم قواعد البيانات (المشار إليها فيما بعد بـ DB - "قاعدة البيانات")، والحد الأدنى من المعرفة بكيفية عمل تعيين الكائنات العلائقية (المشار إليها فيما بعد بـ ORM )، وتطبيقاتها، مثل Hibernate / JPA . إذا لم تكن على دراية بهذا، أنصحك بالبدء بـ JDBC ، وعندها فقط انتقل إلى نموذج ORM. لقد حذرتك، ولا أتحمل مسؤولية نفسيتك بعد قراءة هذا المقال دون تحضير مناسب! :) لنبدأ في التعامل مع كل شيء بالترتيب. أولا، سوف نتعمق قليلا في النظرية، قليلا فقط. ثانيًا، سنتعرف على كيفية القيام بهذا الأمر في لغة جافا المفضلة لدى الجميع. سنكتب معك أيضًا ورقة غش للمشروع، والتي ستعزز فهمنا للموضوع وستكون بمثابة نموذج لكيفية عمل الخرائط . لنفعلها اذا !

ما هو الكيان؟

الكيان هو كائن من الحياة الواقعية (على سبيل المثال، سيارة) له سمات (أبواب، عجلات ، محرك). كيان قاعدة البيانات: في هذه الحالة، يتم تخزين كياننا في قاعدة بيانات، كل شيء بسيط. لماذا وكيف نضع السيارة في قاعدة البيانات - سننظر إليها لاحقًا.

ما هي علاقات قاعدة البيانات؟

منذ وقت طويل، في المملكة البعيدة، تم إنشاء قاعدة بيانات علائقية . في قاعدة البيانات هذه، تم تقديم البيانات في شكل جداول. ولكن حتى حمار شريك فهم أنه من الضروري إنشاء آلية لربط هذه الجداول. ونتيجة لذلك، ظهرت 4 علاقات قاعدة بيانات :
  1. واحد لواحد
  2. واحد لكثير
  3. كثير إلى واحد
  4. الكثير للكثيرين
إذا كنت ترى كل هذا للمرة الأولى، فإنني أحذرك مرة أخرى - فسوف يزداد الأمر سوءًا: فكر في الذهاب في نزهة على الأقدام. سنقوم بتحليل كل هذه العلاقات باستخدام مثال، وفهم الفرق بينها.

مثال الرعب

سيكون لدينا مشروع واحد يحتوي على 5 فروع: رئيسي، حيث سيكون هناك وصف للمشروع، وفرع واحد لكل علاقة قاعدة بيانات. سيحتوي كل فرع على نصوص SQL لإنشاء قاعدة بيانات وملئها ببيانات الاختبار، بالإضافة إلى فئة الكيان مع تعيين التعليقات التوضيحية. سيكون هناك أيضًا ملف تكوين Hibernate لكل فرع. سأستخدم قاعدة بيانات H2 المضمنة للمشروع حتى لا يتم تشتيت انتباهي بالجوانب الفردية لقاعدة البيانات السحابية أو قاعدة البيانات الخارجية. باتباع الرابط، قم بتثبيت H2 DB على المكنسة الكهربائية الخاصة بك. سأصف كل خطوة في فرع واحد، والباقي مجرد النقاط الرئيسية. في النهاية سوف نلخص. يذهب. هذا رابط للفرع الرئيسي لمشروعي.

علاقة فردية

رابط الفرع هنا .
  1. نحن بحاجة إلى توصيل H2 DB بمشروعنا. نحن هنا بحاجة إلى التأكيد على أننا بحاجة إلى Ultimate IDEA للعمل بشكل مريح مع قاعدة البيانات وأشياء أخرى. إذا كان لديك بالفعل، فانتقل مباشرة إلى اتصال قاعدة البيانات. انتقل إلى علامة التبويب "قاعدة البيانات" وافعل كما في لقطة الشاشة:

    JPA Entities and DB Relationships - 2

    بعد ذلك ننتقل إلى إعدادات قاعدة البيانات. يمكنك إدخال بياناتك، وحتى نظام إدارة قواعد البيانات (DBMS)، وأكرر أنني أستخدم H2 DB من أجل البساطة.

    JPA Entities and DB Relationships - 3

    المقبل، دعونا إعداد الدائرة. هذه الخطوة اختيارية ولكن يوصى بها إذا كان لديك مخططات متعددة في قاعدة البيانات.

    JPA Entities and DB Relationships - 4

    قم بتطبيق الإعدادات، وفي النهاية يجب أن نحصل على شيء مثل هذا:

    JPA Entities and DB Relationships - 5
  2. لقد أنشأنا قاعدة البيانات وقمنا بتكوين الوصول إليها من IDEA. أنت الآن بحاجة إلى إنشاء جداول فيه وملئها ببعض البيانات. على سبيل المثال، سآخذ كيانين: المؤلف والكتاب. قد يكون للكتاب مؤلف، أو قد يكون له مؤلفون متعددون، أو قد لا يكون له مؤلف واحد. في هذا المثال سوف نقوم بإنشاء كافة أنواع الاتصالات. ولكن في هذه المرحلة - علاقة فردية. لنقم بإنشاء البرنامج النصي المقابل الذي يقوم بإنشاء جداول قاعدة البيانات :

    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)
    );

    ولننفذها:

    JPA Entities and DB Relationships - 6

    نتيجة التنفيذ في وحدة التحكم:

    JPA Entities and DB Relationships - 7

    النتيجة في قاعدة البيانات:

    JPA Entities and DB Relationships - 8
  3. دعونا نلقي نظرة على الرسم البياني لجداولنا. للقيام بذلك، الرنمينبي على قاعدة بياناتنا:

    JPA Entities and DB Relationships - 9

    نتيجة:

    JPA Entities and DB Relationships - 10

    في مخطط UML يمكننا رؤية جميع المفاتيح الأساسية والمفاتيح الخارجية، كما نرى أيضًا الارتباط بين جداولنا.

  4. لنكتب نصًا يملأ قاعدة بياناتنا ببيانات الاختبار:

    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). في مثالنا، يجب أن يكون للكتاب الواحد مؤلف واحد. لا توجد طريقة أخرى.

  5. الآن الشيء الأكثر إثارة للاهتمام هو كيفية ربط فئة Java بكيانات قاعدة البيانات؟ بسيط جدا. لنقم بإنشاء فصلين للكتاب والمؤلف. باستخدام مثال، سأقوم بتحليل الفصل 1 ومجالات الاتصال الرئيسية. لنأخذ فئة المؤلف كمثال :

    @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;
    }
دعونا معرفة ذلك بالترتيب:
  1. تكرر كافة الحقول الموجودة في الفصل سمات كيان قاعدة البيانات.
  2. تقول @Data (من Lombok ) أنه سيتم إنشاء مُحضر ومُحدد لكل حقل، وسيتم تجاوز كود التجزئة، وسيتم إنشاء طريقة toString.
  3. يقول @Entity أن الفئة المحددة هي كيان وترتبط بكيان قاعدة البيانات.
  4. يقول @DynamicInsert و DynamicUpdate أنه سيتم تنفيذ عمليات الإدراج والتحديثات الديناميكية في قاعدة البيانات. هذه هي إعدادات السبات الأعمق التي ستكون مفيدة لك حتى تحصل على الدفعة الصحيحة.
  5. @Table (الاسم = "AUTHOR") يربط فئة الكتاب بجدول AUTHOR في قاعدة البيانات.
  6. @Id يقول أن هذا الحقل هو المفتاح الأساسي.
  7. @GeneratedValue (استراتيجية = GenerationType.IDENTITY) – استراتيجية إنشاء المفتاح الأساسي.
  8. @Column (name = "ID"، nullable = false) يربط حقلاً بسمة قاعدة بيانات، ويوضح أيضًا أن حقل قاعدة البيانات المحدد لا يمكن أن يكون خاليًا. وهذا مفيد أيضًا عند إنشاء الجداول من الكيانات. العملية العكسية لكيفية إنشاء مشروعنا الآن، مطلوبة في قواعد بيانات الاختبار لاختبارات الوحدة.
  9. يقول @OneToOne أن الحقل المحدد هو حقل علاقة رأس برأس.
  10. @JoinColumn (الاسم = "BOOK_ID"، فريد = صحيح، لاغٍ = خطأ) - سيتم إنشاء عمود BOOK_ID، وهو فريد وليس فارغًا.
على الجانب الخلفي (في فئة الكتاب ) نحتاج أيضًا إلى إجراء اتصال واحد لواحد والإشارة إلى الحقل الذي يحدث فيه التعيين. @OneToOne(mappedBy = "book") - في هذا المثال، هذا هو حقل الكتاب الخاص بفئة المؤلف. سوف تقوم JPA بربطها بنفسها. للوهلة الأولى، قد يبدو أن هناك فوضى في التعليقات التوضيحية، لكنها في الحقيقة مريحة للغاية ومع الخبرة ستضيفها تلقائيًا دون حتى التفكير.
  1. الآن دعونا نقوم بتكوين السبات. للقيام بذلك، قم بإنشاء ملف 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>
وصف الخصائص :
  1. hibernate.dialect هي لهجة نظام إدارة قواعد البيانات (DBMS) الذي اخترناه.
  2. hibernate.connection.driver_class - فئة برنامج التشغيل لقاعدة بياناتنا.
  3. hibernate.connection.url - UTL الخاص بقاعدة بياناتنا. يمكنك أن تأخذ الأمر من النقطة الأولى حيث قمنا بتكوين قاعدة البيانات.
  4. hibernate.connection.username - اسم مستخدم قاعدة البيانات.
  5. hibernate.connection.password - كلمة مرور مستخدم قاعدة البيانات.
  6. hbernate.hbm2ddl.auto - إعداد إنشاء الجدول. إذا تم التحديث، فلن يتم إنشاؤه إذا تم إنشاؤه بالفعل، ولكن يقوم فقط بتحديثه.
  7. hibernate.show_sql - ما إذا كان سيتم عرض استعلامات قاعدة البيانات.
  8. hibernate.format_sql - ما إذا كان سيتم تنسيق استعلامات قاعدة البيانات. إذا لم يكن الأمر كذلك، فسيكونون جميعا على سطر واحد. أوصي بتشغيله.
  9. hibernate.use_sql_comments - تعليقات استعلامات قاعدة البيانات. إذا كان هذا إدراج، فسيتم كتابة تعليق فوق الطلب بأن الطلب من النوع إدراج.
  10. hibernate.generate_statistics - يقوم بإنشاء السجلات. أوصي وأوصي بإعداد التسجيل إلى الحد الأقصى. ستؤدي قراءة السجلات إلى زيادة فرصك في العمل بشكل صحيح مع ORM.
  11. hibernate.jdbc.batch_size - الحد الأقصى لحجم الدفعة.
  12. hibernate.jdbc.fetch_size - الحد الأقصى لحجم الجلب.
  13. hibernate.order_inserts - يسمح بالإدراج الديناميكي.
  14. hibernate.order_updates - يسمح بالتحديثات الديناميكية.
  15. hibernate.jdbc.batch_versioned_data - يسمح بالتجميع. انظر إلى نظام إدارة قواعد البيانات لديك: لا يدعم الجميع هذا.
  16. فئة رسم الخرائط - الفئات التي تمثل كياناتنا. كل شيء يحتاج إلى أن يتم سردها.
  1. الآن يجب تحديد جوهرنا. يمكننا التحقق من ذلك في علامة تبويب الثبات:

    JPA Entities and DB Relationships - 11

    نتيجة:

    JPA Entities and DB Relationships - 12
  2. نحتاج أيضًا إلى تكوين البيانات المخصصة:

    JPA Entities and DB Relationships - 13 JPA Entities and DB Relationships - 14

    النتائج: لقد قمنا برسم خرائط فردية. المواد هي لأغراض إعلامية فقط، التفاصيل في المراجع.

علاقة واحد إلى متعدد

رابط الفرع هنا . لن أقوم بنشر الكود في المقالة بعد الآن، لأنه طويل جدًا بالفعل. نحن ننظر إلى كل التعليمات البرمجية على جيثب.
  1. نتيجة لتنفيذ البرنامج النصي للتهيئة، نحصل على ما يلي:

    JPA Entities and DB Relationships - 15

    هل تشعر بالفرق مع الجدول السابق؟

  2. رسم بياني:

    JPA Entities and DB Relationships - 16

    علاقة واحد إلى متعدد - يمكن لمؤلف واحد أن يكون لديه عدة كتب. الكيان الأيسر يتوافق مع واحد أو أكثر من الكيانات اليمنى.

  3. سيكون الاختلاف في التعيين في التعليقات التوضيحية والحقول:

    يظهر حقل في فئة المؤلف :

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "author")
    private Set<Book> books;

    إنها مجموعة بالفعل، حيث يمكن أن يكون لدينا عدة كتب. @OneToMany يتحدث عن نوع الموقف. يقول FetchType.Lazy أننا لا نحتاج إلى تحميل قائمة الكتب بأكملها إذا لم يتم تحديدها في الطلب. وينبغي أن يقال أيضًا أن هذا الحقل لا يمكن إضافته إلى السلسلة، وإلا فسنبدأ في تدخين StackOverflowError. بلدي الحبيب لومبوك يعتني بهذا:

    @ToString(exclude = "books")

    في فصل الكتاب ، نقوم بإجراء تعليقات متعددة:

    @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @JoinColumn(name = "AUTHOR_ID", nullable = false)
    private Author author;

    نستنتج هنا أن واحد إلى متعدد هو صورة طبق الأصل من متعدد إلى واحد والعكس صحيح. يجب التأكيد على أن Hibernate لا يعرف شيئًا عن الاتصالات ثنائية الاتجاه. بالنسبة له، هناك علاقتان مختلفتان: واحدة في اتجاه واحد، والآخر في الاتجاه المعاكس.

  4. لم يتغير شيء كثيرًا في hibernate.cfg.xml .

  5. إصرار:

    JPA Entities and DB Relationships - 17

علاقة كثير لواحد

وبما أن "متعدد إلى واحد" عبارة عن صورة طبق الأصل من "واحد إلى متعدد"، فسيكون هناك بعض الاختلافات. رابط الفرع هنا .
  1. ونتيجة لتنفيذ البرنامج النصي للتهيئة، نحصل على النتيجة التالية:

    JPA Entities and DB Relationships - 18
  2. رسم بياني:

    JPA Entities and DB Relationships - 19
  3. سيكون الاختلاف في التعيين في التعليقات التوضيحية والحقول:

    لم تعد هناك مجموعة في فئة المؤلف ، لأنها انتقلت إلى فئة الكتاب .

  4. hibernate.cfg.xml

  5. إصرار:

    JPA Entities and DB Relationships - 20

علاقة كثير إلى كثير

دعنا ننتقل إلى العلاقة الأكثر إثارة للاهتمام. ويتم إنشاء هذه العلاقة، وفق كل قواعد الحشمة والفحش، من خلال جدول إضافي. لكن هذا الجدول ليس كيانًا. مثير للاهتمام، أليس كذلك؟ دعونا نلقي نظرة على هذا القرف. رابط الفرع هنا .
  1. انظر إلى البرنامج النصي للتهيئة ، وسيظهر هنا جدول HAS إضافي. نحصل على شيء مثل المؤلف لديه كتاب.

    ونتيجة تنفيذ البرنامج سنحصل على الجداول التالية:

    JPA Entities and DB Relationships - 21
  2. رسم بياني:

    JPA Entities and DB Relationships - 22

    في مثالنا، يتبين أن الكتاب يمكن أن يكون له العديد من المؤلفين، ويمكن أن يكون للمؤلف العديد من الكتب. قد تتداخل.

  3. ستحتوي فئات رسم الخرائط على مجموعات داخل الفئات. ولكن كما قلت، الجدول 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 والحقل الذي سنستخدمه للتخطيط.

  4. ظل hibernate.cfg.xml الخاص بنا دون تغيير مرة أخرى (لا آخذ في الاعتبار حقيقة أننا أنشأنا قاعدة بيانات جديدة لكل فرع).

  5. إصرار:

    JPA Entities and DB Relationships - 23

استخلاص المعلومات

لذلك، قمنا بفحص أنواع علاقات قاعدة البيانات بشكل سطحي وتوصلنا إلى كيفية تنفيذها في نموذج ORM. لقد كتبنا مشروعًا اختباريًا يوضح جميع الاتصالات، وتوصلنا إلى كيفية تكوين السبات / jpa. أوف.

روابط مفيدة

مقالاتي السابقة: ملاحظة: قد تكون هناك أخطاء وأوجه قصور في النص. PPS كان المؤلف يدخن شيئًا غريبًا أثناء كتابة هذا المقال. شكرًا لكم على اهتمامكم!
تعليقات
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION