JavaRush /Java Blog /Random-TL /Mga Entidad ng JPA at Relasyon ng DB
Nikita Koliadin
Antas
Днепр

Mga Entidad ng JPA at Relasyon ng DB

Nai-publish sa grupo

Mga Entidad ng JPA at Mga Relasyon sa DB

Magandang araw, mga kasamahan!
Mga Entidad ng JPA at Relasyon ng DB - 1
Ang materyal na ito ay inilaan para sa mga mayroon nang pang-unawa sa organisasyon ng mga database (simula dito ay simpleng DB - "Database"), kaunting kaalaman sa kung paano gumagana ang Object-Relational Mapping (simula dito ay simpleng ORM ), at ang mga pagpapatupad nito, tulad ng Hibernate / JPA . Kung hindi ka pamilyar dito, ipinapayo ko sa iyo na magsimula sa JDBC , at pagkatapos ay lumipat sa modelo ng ORM. Binalaan kita, at hindi ako mananagot para sa iyong pag-iisip pagkatapos basahin ang artikulong ito nang walang tamang paghahanda! :) Simulan na nating harapin ang lahat sa pagkakasunud-sunod. Una, susuriin natin ng kaunti ang teorya, kaunti lang. Pangalawa, aalamin natin kung paano gawin ang tae na ito sa paboritong Java ng lahat. Magsusulat din kami sa iyo ng project-cheat sheet, na magpapatatag sa aming pag-unawa sa paksa at magsisilbing template para sa PAANO dapat gawin ang pagmamapa . Kaya gawin na natin!

Ano ang Entity?

Ang Entity ay isang bagay mula sa totoong buhay (halimbawa, isang kotse) na may mga katangian (pinto, GULONG , makina). DB Entity: Sa kasong ito, ang aming entity ay nakaimbak sa isang DB, lahat ay simple. Bakit at paano namin inilalagay ang kotse sa database - titingnan namin ito sa ibang pagkakataon.

Ano ang DB Relationships?

Noong unang panahon, sa malayong kaharian , isang relational DB ang nilikha . Sa DB na ito, ipinakita ang data sa anyo ng mga talahanayan. Ngunit kahit na ang asno mula sa Shrek ay naunawaan na ito ay kinakailangan upang lumikha ng isang mekanismo para sa interconnecting mga talahanayan. Bilang resulta, lumitaw ang 4 na relasyon sa DB :
  1. Isa sa isa
  2. Isa-sa-Marami
  3. Marami-sa-Isa
  4. Marami-sa-Marami
Kung nakita mo ang lahat ng ito sa unang pagkakataon, binabalaan kita muli - lalala ito: mag-isip tungkol sa paglalakad. Susuriin namin ang lahat ng ugnayang ito gamit ang isang halimbawa, at mauunawaan ang pagkakaiba sa pagitan ng mga ito.

Halimbawa ng Horror

Magkakaroon tayo ng isang proyekto na magkakaroon ng 5 sangay: master, kung saan magkakaroon ng paglalarawan ng proyekto, at 1 sangay para sa bawat relasyon ng DB. Ang bawat sangay ay maglalaman ng mga script ng SQL para sa paglikha ng isang DB at pagpuno dito ng data ng pagsubok, kasama ang isang klase ng Entity na may pagmamapa ng anotasyon. Magkakaroon din ng Hibernate config file para sa bawat branch. Gagamitin ko ang H2 na naka-embed na DB para sa proyekto upang hindi magambala ng mga indibidwal na aspeto ng cloud DB o panlabas na DB. Sa pamamagitan ng pagsunod sa link, i-install ang H2 DB sa iyong vacuum cleaner. Ilalarawan ko ang bawat hakbang sa 1 sangay, ang iba ay ang mga pangunahing punto lamang. Sa dulo ay ibubuod natin. Pumunta ka. Ito ay isang link sa master branch ng aking proyekto.

Isa-sa-Isang Relasyon

Link sa branch dito .
  1. Kailangan naming ikonekta ang H2 DB sa aming proyekto. Dito kailangan nating bigyang-diin na kailangan natin ang Ultimate IDEA upang gumana nang kumportable sa DB at iba pang mga bagay. Kung mayroon ka na nito, dumiretso sa koneksyon ng DB. Pumunta sa tab na Database at gawin tulad ng sa screenshot:

    JPA Entities and DB Relationships - 2

    Susunod na lumipat kami sa mga setting ng DB. Maaari mong ipasok ang iyong data, at maging ang iyong DBMS; Inuulit ko, gumagamit ako ng H2 DB para sa pagiging simple.

    JPA Entities and DB Relationships - 3

    Susunod, i-set up natin ang circuit. Opsyonal ang hakbang na ito ngunit inirerekomenda kung marami kang schema sa DB.

    JPA Entities and DB Relationships - 4

    Ilapat ang mga setting, at sa huli dapat tayong makakuha ng ganito:

    JPA Entities and DB Relationships - 5
  2. Ginawa namin ang database at na-configure ang access dito mula sa IDEA. Ngayon ay kailangan mong lumikha ng mga talahanayan sa loob nito at punan ito ng ilang data. Halimbawa, kukuha ako ng dalawang entity: May-akda at Aklat. Ang isang libro ay maaaring may may-akda, maaaring maraming may-akda, o maaaring walang isa. Sa halimbawang ito gagawa kami ng lahat ng uri ng koneksyon. Ngunit sa puntong ito - One-to-One na relasyon. Gawin natin ang kaukulang script na lumilikha ng 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)
    );

    At isagawa natin ito:

    JPA Entities and DB Relationships - 6

    Resulta ng pagpapatupad sa console:

    JPA Entities and DB Relationships - 7

    Resulta sa DB:

    JPA Entities and DB Relationships - 8
  3. Tingnan natin ang isang diagram ng aming mga talahanayan. Upang gawin ito, RMB sa aming DB:

    JPA Entities and DB Relationships - 9

    Resulta:

    JPA Entities and DB Relationships - 10

    Sa diagram ng UML makikita namin ang lahat ng pangunahing key at foreign key, nakikita rin namin ang koneksyon sa pagitan ng aming mga talahanayan.

  4. Sumulat tayo ng script na pumupuno sa ating DB ng data ng pagsubok:

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

    I mean, anong nangyayari? Kailangan ang One-to-One na relasyon kapag ang entity ng isang table ay nauugnay sa isang entity ng isa pa (o hindi nauugnay kung NOT NULL ay inalis sa BOOK_ID). Sa aming halimbawa, DAPAT may isang may-akda ang isang libro. Walang ibang paraan.

  5. Ngayon ang pinaka-kagiliw-giliw na bagay ay kung paano ikonekta ang isang klase ng Java sa mga entidad ng DB? Napakasimple. Gumawa tayo ng dalawang klase ng Aklat at May-akda. Gamit ang isang halimbawa, susuriin ko ang klase 1 at ang mga pangunahing larangan ng komunikasyon. Kunin natin ang klase ng May-akda bilang isang halimbawa :

    @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;
    }
Alamin natin ito sa pagkakasunud-sunod:
  1. Ang lahat ng mga field sa klase ay inuulit ang mga katangian ng DB entity.
  2. Sinasabi ng @Data (mula sa Lombok ) na para sa bawat field ay gagawa ng getter at setter, katumbas, ma-override ang hashcode, at bubuo ng toString method.
  3. Sinasabi ng @Entity na ang ibinigay na klase ay isang entity at nauugnay sa isang entity ng DB.
  4. Sinasabi ng @DynamicInsert at @DynamicUpdate na ang mga dynamic na pagsingit at pag-update ay isasagawa sa DB. Ito ang mga mas malalim na setting ng Hibernate na magiging kapaki-pakinabang sa iyo para magkaroon ka ng TAMANG batching.
  5. Ang @Table (name = "AUTHOR") ay nagbubuklod sa klase ng Aklat sa talahanayan ng DB AUTHOR.
  6. Sinasabi ng @Id na ang field na ito ang pangunahing susi.
  7. @GeneratedValue (diskarte = GenerationType.IDENTITY) – pangunahing diskarte sa pagbuo ng key.
  8. Ang @Column (pangalan = "ID", nullable = false) ay nag-uugnay ng isang patlang sa isang katangian ng DB, at sinasabi rin na ang ibinigay na patlang ng DB ay hindi maaaring null. Ito ay kapaki-pakinabang din kapag bumubuo ng mga talahanayan mula sa mga entity. Ang baligtad na proseso sa kung paano namin ginagawa ngayon ang aming proyekto, ito ay kinakailangan sa mga pagsubok na DB para sa mga pagsubok sa Unit.
  9. Sinabi ni @OneToOne na ang ibinigay na field ay isang One-to-One na field ng relasyon.
  10. @JoinColumn (pangalan = "BOOK_ID", unique = true, nullable = false) - gagawa ng BOOK_ID column, na kakaiba at hindi null.
Sa reverse side (sa klase ng Aklat ) kailangan din nating gumawa ng One-to-One na koneksyon at ipahiwatig ang field kung saan nangyayari ang pagmamapa. @OneToOne(mappedBy = "book") - sa halimbawang ito, ito ang field ng libro ng klase ng May-akda. Ang JPA ang magli-link sa kanila mismo. Sa unang sulyap, maaaring mukhang may gulo ng mga anotasyon, ngunit sa katunayan ito ay napaka-maginhawa at may karanasan ay awtomatiko mong idaragdag ang mga ito nang hindi man lang nag-iisip.
  1. Ngayon ay i-configure natin ang Hibernate. Upang gawin ito, lumikha ng hibernate.cfg.xml file:

    <?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>
Paglalarawan ng mga ari-arian :
  1. hibernate.dialect ay ang dialect ng DBMS na napili namin.
  2. hibernate.connection.driver_class - Klase ng driver ng aming DB.
  3. hibernate.connection.url - utl ng aming DB. Maaari mo itong kunin mula sa unang punto kung saan namin na-configure ang DB.
  4. hibernate.connection.username - DB user name.
  5. hibernate.connection.password — DB user password.
  6. hibernate.hbm2ddl.auto - pagse-set up ng pagbuo ng talahanayan. Kung na-update, hindi ito bubuo kung ito ay nalikha na, ngunit ina-update lamang ito.
  7. hibernate.show_sql - kung magpapakita ng mga query sa DB.
  8. hibernate.format_sql - kung i-format ang mga query sa DB. Kung hindi, lahat sila ay nasa isang linya. Inirerekomenda kong i-on ito.
  9. hibernate.use_sql_comments - nagkomento sa mga query sa DB. Kung ito ay isang Insert, ang isang komento ay nakasulat sa itaas ng kahilingan na ang kahilingan ay nasa uri ng Insert.
  10. hibernate.generate_statistics - bumubuo ng mga log. Inirerekomenda at inirerekumenda ko ang pag-set up ng pag-log sa maximum. Ang pagbabasa ng mga log ay magpapalaki sa iyong mga pagkakataong magtrabaho nang tama sa ORM.
  11. hibernate.jdbc.batch_size — Pinakamataas na laki ng batch.
  12. hibernate.jdbc.fetch_size — Pinakamataas na laki ng pagkuha.
  13. hibernate.order_inserts - nagbibigay-daan sa mga dynamic na pagsingit.
  14. hibernate.order_updates - Pinapayagan ang mga dynamic na update.
  15. hibernate.jdbc.batch_versioned_data - nagbibigay-daan sa pag-batch. Tingnan ang iyong DBMS: hindi lahat ay sumusuporta dito.
  16. klase ng pagmamapa - mga klase na aming mga entity. Kailangang ilista ang lahat.
  1. Ngayon ang ating kakanyahan ay dapat matukoy. Maaari naming suriin ito sa tab na persistence:

    JPA Entities and DB Relationships - 11

    Resulta:

    JPA Entities and DB Relationships - 12
  2. Kailangan din naming i-configure ang pagtatalaga ng data:

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

    Mga Resulta: Nakagawa kami ng One-to-One na pagmamapa. Ang materyal ay para sa mga layuning pang-impormasyon lamang, ang mga detalye ay nasa mga sanggunian.

Isa-sa-Maraming Relasyon

Link sa branch dito . Hindi ko na ipo-post ang code sa artikulo, dahil ito ay masyadong mahaba. Tinitingnan namin ang lahat ng code sa GitHub.
  1. Bilang resulta ng pagpapatupad ng script ng pagsisimula, nakukuha namin ang sumusunod:

    JPA Entities and DB Relationships - 15

    Nararamdaman mo ba ang pagkakaiba sa nakaraang talahanayan?

  2. Diagram:

    JPA Entities and DB Relationships - 16

    Isa-sa-Maraming Relasyon - maaaring magkaroon ng ilang aklat ang isang may-akda. Ang kaliwang entity ay tumutugma sa isa o higit pang mga kanan.

  3. Ang pagkakaiba sa pagmamapa ay nasa mga anotasyon at field:

    Lumilitaw ang isang patlang sa klase ng May-akda :

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

    Ito ay isang set na, dahil maaari tayong magkaroon ng ilang mga libro. Ang @OneToMany ay nagsasalita tungkol sa uri ng relasyon. Sinasabi ng FetchType.Lazy na hindi namin kailangang i-load ang buong listahan ng mga aklat kung hindi ito tinukoy sa kahilingan. Dapat ding sabihin na HINDI MAAARI idagdag ang field na ito sa toString, kung hindi, magsisimula kaming manigarilyo ng StackOverflowError. Inaalagaan ito ng aking minamahal na Lombok:

    @ToString(exclude = "books")

    Sa klase ng Aklat gumagawa kami ng Many-to-One na feedback:

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

    Dito natin napaghihinuha na ang One-to-Many ay ang mirror image ng Many-to-One at vice versa. Dapat itong bigyang-diin na ang Hibernate ay walang alam tungkol sa mga bidirectional na komunikasyon. Para sa kanya, ito ay dalawang magkaibang koneksyon: ang isa sa isang direksyon, ang isa sa kabaligtaran na direksyon.

  4. Walang masyadong nagbago sa hibernate.cfg.xml .

  5. Pagtitiyaga:

    JPA Entities and DB Relationships - 17

Maraming-sa-Isang Relasyon

Dahil ang Many-to-One ay isang mirror image ng One-to-Many, magkakaroon ng kaunting pagkakaiba. Link sa branch dito .
  1. Bilang resulta ng pagpapatupad ng script ng pagsisimula, nakukuha namin ang sumusunod na resulta:

    JPA Entities and DB Relationships - 18
  2. Diagram:

    JPA Entities and DB Relationships - 19
  3. Ang pagkakaiba sa pagmamapa ay nasa mga anotasyon at field:

    Wala nang set sa klase ng May-akda , dahil lumipat na ito sa klase ng Aklat .

  4. hibernate.cfg.xml

  5. Pagtitiyaga:

    JPA Entities and DB Relationships - 20

Many-to-Many Relationship

Lumipat tayo sa pinaka-kagiliw-giliw na relasyon. Ang relasyon na ito, ayon sa lahat ng mga alituntunin ng pagiging disente at kawalanghiyaan, ay nilikha sa pamamagitan ng isang karagdagang talahanayan. Ngunit ang talahanayang ito ay hindi isang entity. Kawili-wili, tama? Tingnan natin ang kalokohang ito. Link sa branch dito .
  1. Tingnan ang script ng initialization , may lalabas na karagdagang HAS table dito. Nakakakuha kami ng isang bagay tulad ng may-akda-may-libro.

    Bilang resulta ng pagpapatupad ng script, makukuha natin ang mga sumusunod na talahanayan:

    JPA Entities and DB Relationships - 21
  2. Diagram:

    JPA Entities and DB Relationships - 22

    Sa aming halimbawa, lumalabas na ang isang libro ay maaaring magkaroon ng maraming mga may-akda, at ang isang may-akda ay maaaring magkaroon ng maraming mga libro. Maaari silang mag-overlap.

  3. Ang mga klase sa pagmamapa ay magkakaroon ng mga set sa loob ng mga klase. Ngunit tulad ng sinabi ko, ang HAS table ay hindi isang entity.

    Klase ng may-akda :

    @ManyToMany
    @JoinTable(name = "HAS",
            joinColumns = @JoinColumn(name = "AUTHOR_ID", referencedColumnName = "ID"),
            inverseJoinColumns = @JoinColumn(name = "BOOK_ID", referencedColumnName = "ID")
    )
    private Set<Book> books;

    Ang @ManyToMany ay isang uri ng relasyon.

    @JoinTable - ito mismo ang magkokonekta sa attribute na may karagdagang HAS table. Dito ay tinukoy namin ang dalawang katangian na magtuturo sa mga pangunahing key ng dalawang entity.

    Klase ng libro :

    @ManyToMany(fetch = FetchType.LAZY, mappedBy = "books")
    private Set<Author> authors;

    Dito ay ipinapahiwatig namin ang FetchType at ang field na gagamitin namin sa pagmamapa.

  4. Ang aming hibernate.cfg.xml muli ay nanatiling hindi nagbabago (hindi ko isinasaalang-alang ang katotohanan na lumikha kami ng bagong DB para sa bawat sangay).

  5. Pagtitiyaga:

    JPA Entities and DB Relationships - 23

Debriefing

Kaya, mababaw naming sinuri ang mga uri ng mga relasyon sa DB at naisip kung paano ipatupad ang mga ito sa modelong ORM. Sumulat kami ng isang pagsubok na proyekto na nagpapakita ng lahat ng mga koneksyon, at naisip kung paano i-configure ang hibernate / jpa. Phew.

kapaki-pakinabang na mga link

Ang aking mga nakaraang artikulo: PS Maaaring may mga pagkakamali at pagkukulang sa teksto. PPS Ang may-akda ay naninigarilyo ng kakaiba habang isinusulat ang artikulong ito. Salamat sa iyong atensyon!
Mga komento
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION