JavaRush /وبلاگ جاوا /Random-FA /نهادهای JPA و روابط DB
Nikita Koliadin
مرحله
Днепр

نهادهای JPA و روابط DB

در گروه منتشر شد

نهادهای JPA و روابط DB

روز بخیر، همکاران!
نهادهای JPA و روابط DB - 1
این مطالب برای کسانی در نظر گرفته شده است که قبلاً درک درستی از سازماندهی پایگاه های داده دارند (از این پس به سادگی DB - "پایگاه داده")، حداقل دانش در مورد نحوه کار نقشه برداری شی - رابطه ای (از این پس به سادگی ORM ) و پیاده سازی های آن مانند Hibernate / JPA دارند. . اگر با این امر آشنا نیستید، به شما توصیه می کنم که با JDBC شروع کنید و تنها پس از آن به سراغ مدل ORM بروید. من به شما هشدار دادم و پس از خواندن این مقاله بدون آمادگی مناسب مسئولیتی در قبال روحیه شما ندارم! :) بیایید شروع کنیم به رسیدگی به همه چیز به ترتیب. در ابتدا، ما کمی به تئوری می پردازیم، فقط کمی. در مرحله دوم، نحوه انجام این کار را در جاوا مورد علاقه همه خواهیم فهمید. ما همچنین با شما یک برگه تقلب پروژه می نویسیم، که درک ما از موضوع را تثبیت می کند و به عنوان الگویی برای نحوه انجام نقشه برداری عمل می کند . خب بیا انجام بدیمش!

Entity چیست؟

یک موجودیت یک شی از زندگی واقعی است (مثلاً یک ماشین) که دارای ویژگی هایی است (درها، چرخ ها ، موتور). DB Entity: در این مورد، موجودیت ما در یک DB ذخیره می شود، همه چیز ساده است. چرا و چگونه ماشین را در پایگاه داده قرار می دهیم - بعداً به آن نگاه خواهیم کرد.

DB Relationship چیست؟

مدتها پیش، در پادشاهی دور ، یک DB رابطه ای ایجاد شد . در این بانک اطلاعاتی داده ها در قالب جداول ارائه شده است. اما حتی الاغ شرک فهمید که لازم است مکانیزمی برای اتصال این میزها ایجاد شود. در نتیجه، 4 رابطه DB ظاهر شد :
  1. یک به یک
  2. یک به چند
  3. چند به یک
  4. چند به چند
اگر برای اولین بار است که همه اینها را می بینید، دوباره به شما هشدار می دهم - بدتر می شود: به پیاده روی فکر کنید. ما تمام این روابط را با استفاده از یک مثال تجزیه و تحلیل خواهیم کرد و تفاوت بین آنها را درک خواهیم کرد.

مثال ترسناک

ما یک پروژه خواهیم داشت که دارای 5 شاخه است: master، که در آن شرح پروژه وجود دارد، و 1 شاخه برای هر رابطه DB. هر شاخه شامل اسکریپت های SQL برای ایجاد یک DB و پر کردن آن با داده های آزمایشی، به علاوه یک کلاس Entity با نگاشت حاشیه نویسی خواهد بود. همچنین برای هر شاخه یک فایل پیکربندی Hibernate وجود خواهد داشت. من از DB تعبیه‌شده H2 برای پروژه استفاده خواهم کرد تا با جنبه‌های جداگانه Cloud DB یا DB خارجی منحرف نشم. با دنبال کردن لینک، H2 DB را روی جاروبرقی خود نصب کنید. من هر مرحله را در 1 شاخه توضیح خواهم داد، بقیه فقط نکات کلیدی هستند. در پایان به جمع بندی می پردازیم. برو این یک لینک به شاخه اصلی پروژه من است.

رابطه یک به یک

لینک شعبه در اینجا
  1. ما باید H2 DB را به پروژه خود متصل کنیم. در اینجا باید تاکید کنیم که برای کار راحت با DB و سایر موارد به Ultimate IDEA نیاز داریم. اگر قبلاً آن را دارید، مستقیماً به اتصال DB بروید. به تب Database بروید و مانند تصویر زیر عمل کنید:

    نهادهای JPA و روابط DB - 2

    سپس به تنظیمات DB می رویم. شما می توانید داده های خود و حتی DBMS خود را وارد کنید؛ تکرار می کنم، من برای سادگی از H2 DB استفاده می کنم.

    نهادهای JPA و روابط DB - 3

    بعد، بیایید مدار را تنظیم کنیم. این مرحله اختیاری است اما اگر طرحواره های متعددی در DB دارید توصیه می شود.

    نهادهای JPA و روابط DB - 4

    تنظیمات را اعمال کنید و در پایان باید چیزی شبیه به این دریافت کنیم:

    نهادهای JPA و روابط DB - 5
  2. ما پایگاه داده را ایجاد کردیم و دسترسی به آن را از 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)
    );

    و بیایید آن را اجرا کنیم:

    نهادهای JPA و روابط DB - 6

    نتیجه اجرا در کنسول:

    نهادهای JPA و روابط DB - 7

    نتیجه در DB:

    نهادهای JPA و روابط DB - 8
  3. بیایید به نمودار جداول خود نگاه کنیم. برای انجام این کار، RMB در DB ما:

    نهادهای JPA و روابط DB - 9

    نتیجه:

    نهادهای JPA و روابط DB - 10

    در نمودار UML می توانیم تمام کلیدهای اصلی و کلیدهای خارجی را ببینیم، همچنین ارتباط بین جداول خود را می بینیم.

  4. بیایید یک اسکریپت بنویسیم که 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 حذف شود اصلاً مرتبط نباشد). در مثال ما، یک کتاب باید یک نویسنده داشته باشد. راه دیگری نیست.

  5. حالا جالب ترین چیز این است که چگونه یک کلاس جاوا را با موجودیت های 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;
    }
بیایید به ترتیب آن را بفهمیم:
  1. تمام فیلدهای کلاس ویژگی های موجودیت DB را تکرار می کنند.
  2. @Data (از Lombok ) می‌گوید که برای هر فیلد یک گیرنده و تنظیم‌کننده ایجاد می‌شود، برابر است، کد هش بازنویسی می‌شود و یک متد toString ایجاد می‌شود.
  3. @Entity می گوید که کلاس داده شده یک موجودیت است و با یک موجودیت DB مرتبط است.
  4. @DynamicInsert و @DynamicUpdate می‌گویند که درج‌ها و به‌روزرسانی‌های پویا در DB انجام خواهند شد. اینها تنظیمات Hibernate عمیق تری هستند که برای شما مفید خواهند بود تا بچینگ صحیح را داشته باشید.
  5. @Table (name = "AUTHOR") کلاس Book را به جدول DB AUTHOR متصل می کند.
  6. @Id می گوید که این فیلد کلید اصلی است.
  7. @GeneratedValue (استراتژی = GenerationType.IDENTITY) – استراتژی تولید کلید اولیه.
  8. @Column (name = "ID"، nullable = false) یک فیلد را با ویژگی DB مرتبط می کند و همچنین می گوید که فیلد DB داده شده نمی تواند null باشد. این همچنین هنگام تولید جداول از موجودیت ها مفید است. روند معکوس به نحوه ایجاد پروژه خود، این در DB های آزمایشی برای تست های واحد مورد نیاز است.
  9. @OneToOne می گوید که فیلد داده شده یک فیلد رابطه یک به یک است.
  10. @JoinColumn (نام = "BOOK_ID"، منحصر به فرد = درست، پوچ = نادرست) - یک ستون BOOK_ID ایجاد می شود که منحصر به فرد است و پوچ نیست.
در سمت عقب (در کلاس Book ) همچنین باید یک اتصال یک به یک ایجاد کنیم و فیلدی را که نگاشت روی آن انجام می شود نشان دهیم. @OneToOne(mappedBy = "book") - در این مثال، این فیلد کتاب از کلاس Author است. JPA خودش آنها را به هم مرتبط خواهد کرد. در نگاه اول، ممکن است به نظر برسد که حاشیه‌نویسی به هم ریخته است، اما در واقع بسیار راحت است و با تجربه به طور خودکار بدون حتی فکر کردن آنها را اضافه خواهید کرد.
  1. حال بیایید 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>
شرح خواص :
  1. hibernate.dialect گویش DBMS است که ما انتخاب کرده ایم.
  2. hibernate.connection.driver_class - کلاس درایور DB ما.
  3. hibernate.connection.url - utl از DB ما. می توانید آن را از اولین نقطه ای که ما DB را پیکربندی کردیم، بگیرید.
  4. hibernate.connection.username - نام کاربری DB.
  5. hibernate.connection.password — رمز عبور کاربر DB.
  6. hibernate.hbm2ddl.auto - تنظیم تولید جدول. اگر به‌روزرسانی شود، اگر قبلاً ایجاد شده باشد، تولید نمی‌کند، بلکه فقط آن را به‌روزرسانی می‌کند.
  7. hibernate.show_sql - نمایش پرس و جوهای DB.
  8. hibernate.format_sql - آیا فرمت پرس و جوهای DB. اگر نه، همه آنها در یک خط خواهند بود. توصیه می کنم آن را روشن کنید.
  9. hibernate.use_sql_comments - نظرات پرس و جوهای DB. اگر این یک Insert باشد، بالای درخواست یک نظر نوشته می شود که درخواست از نوع Insert است.
  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 - امکان دسته بندی را فراهم می کند. به DBMS خود نگاه کنید: همه از این پشتیبانی نمی کنند.
  16. کلاس نگاشت - کلاس هایی که موجودیت های ما هستند. همه چیز باید فهرست شود.
  1. حال باید جوهره ما مشخص شود. ما می توانیم این را در برگه پایداری بررسی کنیم:

    نهادهای JPA و روابط DB - 11

    نتیجه:

    نهادهای JPA و روابط DB - 12
  2. ما همچنین باید داده های اختصاصی را پیکربندی کنیم:

    نهادهای JPA و روابط DB - 13 نهادهای JPA و روابط DB - 14

    نتایج: ما نقشه برداری یک به یک را انجام داده ایم. مطالب فقط برای اهداف اطلاعاتی است، جزئیات در منابع موجود است.

رابطه یک به چند

لینک شعبه در اینجا من دیگر کد را در مقاله ارسال نمی کنم، زیرا در حال حاضر بسیار طولانی است. ما به تمام کدهای موجود در GitHub نگاه می کنیم.
  1. در نتیجه اجرای اسکریپت اولیه سازی، موارد زیر را دریافت می کنیم:

    نهادهای JPA و روابط DB - 15

    آیا تفاوت را با جدول قبلی احساس می کنید؟

  2. نمودار:

    نهادهای JPA و روابط DB - 16

    رابطه یک به چند - یک نویسنده می تواند چندین کتاب داشته باشد. موجودیت سمت چپ مربوط به یک یا چند مورد سمت راست است.

  3. تفاوت در نقشه برداری در حاشیه نویسی و فیلدها خواهد بود:

    فیلدی در کلاس 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 در مورد ارتباطات دو طرفه چیزی نمی داند. برای او، اینها دو ارتباط متفاوت هستند: یکی در یک جهت، دیگری در جهت مخالف.

  4. هیچ چیز زیادی در hibernate.cfg.xml تغییر نکرده است .

  5. ماندگاری:

    نهادهای JPA و روابط DB - 17

رابطه چند به یک

از آنجایی که Many-to-One یک تصویر آینه ای از One-to-Many است، تفاوت های کمی وجود خواهد داشت. لینک شعبه در اینجا
  1. در نتیجه اجرای اسکریپت اولیه سازی، نتیجه زیر را دریافت می کنیم:

    نهادهای JPA و روابط DB - 18
  2. نمودار:

    نهادهای JPA و روابط DB - 19
  3. تفاوت در نقشه برداری در حاشیه نویسی و فیلدها خواهد بود:

    دیگر مجموعه‌ای در کلاس Author وجود ندارد، زیرا به کلاس Book منتقل شده است .

  4. hibernate.cfg.xml

  5. ماندگاری:

    نهادهای JPA و روابط DB - 20

رابطه چند به چند

بیایید به سمت جالب ترین رابطه برویم. این رابطه طبق تمام قواعد نجابت و منافی عفت از طریق جدول اضافی ایجاد می شود. اما این جدول یک موجودیت نیست. جالبه، درسته؟ بیایید نگاهی به این گند بیاندازیم لینک شعبه در اینجا
  1. به اسکریپت اولیه نگاه کنید ، یک جدول HAS اضافی در اینجا ظاهر می شود. ما چیزی شبیه نویسنده-دارای-کتاب دریافت می کنیم.

    در نتیجه اجرای اسکریپت، جداول زیر را دریافت خواهیم کرد:

    نهادهای JPA و روابط DB - 21
  2. نمودار:

    نهادهای JPA و روابط DB - 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 ما دوباره بدون تغییر باقی ماند (من این واقعیت را در نظر نمی‌گیرم که برای هر شاخه یک DB جدید ایجاد کرده‌ایم).

  5. ماندگاری:

    نهادهای JPA و روابط DB - 23

تشریح

بنابراین، ما به طور سطحی انواع روابط DB را بررسی کرده ایم و نحوه پیاده سازی آنها را در مدل ORM کشف کرده ایم. ما یک پروژه آزمایشی نوشتیم که تمام اتصالات را نشان می دهد و نحوه پیکربندی hibernate / jpa را فهمیدیم. فوو

لینک های مفید

مقالات قبلی من: PS ممکن است خطاها و کاستی هایی در متن وجود داشته باشد. PPS نویسنده در حین نوشتن این مقاله چیزی عجیب سیگار می کشید. با تشکر از توجه شما!
نظرات
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION