JavaRush /จาวาบล็อก /Random-TH /JPA: การแนะนำเทคโนโลยี
Viacheslav
ระดับ

JPA: การแนะนำเทคโนโลยี

เผยแพร่ในกลุ่ม
โลกแห่งการพัฒนาสมัยใหม่เต็มไปด้วยข้อกำหนดต่างๆ ที่ออกแบบมาเพื่อทำให้ชีวิตง่ายขึ้น เมื่อรู้เครื่องมือแล้วคุณสามารถเลือกเครื่องมือที่เหมาะสมได้ คุณสามารถทำให้ชีวิตของคุณยากขึ้นได้โดยไม่รู้ การตรวจสอบนี้จะปกปิดความลับเหนือแนวคิดของ JPA - Java Persistence API ฉันหวังว่าหลังจากอ่านแล้วคุณคงอยากจะดำดิ่งลงสู่โลกลึกลับนี้ให้ลึกยิ่งขึ้น
JPA : เทคโนโลยีเบื้องต้น - 1

การแนะนำ

อย่างที่เราทราบ งานหลักประการหนึ่งของโปรแกรมคือการจัดเก็บและประมวลผลข้อมูล ในสมัยก่อน ผู้คนเพียงจัดเก็บข้อมูลไว้ในไฟล์ แต่ทันทีที่จำเป็นต้องเข้าถึงการอ่านและแก้ไขพร้อมกัน เมื่อมีการโหลด (เช่น คำขอหลายรายการมาถึงพร้อมกัน) การจัดเก็บข้อมูลเพียงในไฟล์จะกลายเป็นปัญหา สำหรับข้อมูลเพิ่มเติมเกี่ยวกับปัญหาที่ฐานข้อมูลแก้ไขและวิธี ฉันแนะนำให้คุณอ่านบทความ “ โครงสร้างฐานข้อมูลอย่างไร ” ซึ่งหมายความว่าเราตัดสินใจจัดเก็บข้อมูลของเราไว้ในฐานข้อมูล เป็นเวลานานแล้วที่ Java สามารถทำงานกับฐานข้อมูลโดยใช้ JDBC API (การเชื่อมต่อฐานข้อมูล Java) คุณสามารถอ่านเพิ่มเติมเกี่ยวกับ JDBC ได้ที่นี่: “ JDBC หรือจุดเริ่มต้นทั้งหมด ” แต่เวลาผ่านไปและนักพัฒนาแต่ละครั้งต้องเผชิญกับความจำเป็นในการเขียนประเภทเดียวกันและรหัส "การบำรุงรักษา" ที่ไม่จำเป็น (ที่เรียกว่ารหัส Boilerplate) สำหรับการดำเนินการเล็กน้อยในการบันทึกอ็อบเจ็กต์ Java ในฐานข้อมูลและในทางกลับกัน การสร้างอ็อบเจ็กต์ Java โดยใช้ข้อมูลจาก ฐานข้อมูล จากนั้น เพื่อแก้ไขปัญหาเหล่านี้ แนวคิด ORM ก็ถือกำเนิดขึ้น ORM - การทำแผนที่เชิงวัตถุหรือแปลเป็นภาษารัสเซียในการทำแผนที่เชิงวัตถุสัมพันธ์ เป็นเทคโนโลยีการเขียนโปรแกรมที่เชื่อมโยงฐานข้อมูลกับแนวคิดของภาษาโปรแกรมเชิงวัตถุ เพื่อให้ง่ายขึ้น ORM คือการเชื่อมต่อระหว่างออบเจ็กต์ Java และบันทึกในฐานข้อมูล โดย JPA: เทคโนโลยีเบื้องต้น - 2พื้นฐานแล้ว ORM นั้นเป็นแนวคิดที่ว่าออบเจ็กต์ Java สามารถแสดงเป็นข้อมูลในฐานข้อมูลได้ (และในทางกลับกัน) มันถูกรวบรวมไว้ในรูปแบบของข้อกำหนด JPA - Java Persistence API ข้อกำหนดนี้เป็นคำอธิบายของ Java API ที่แสดงแนวคิดนี้อยู่แล้ว ข้อกำหนดระบุเราว่าเราต้องจัดเตรียมเครื่องมือใดบ้าง (เช่น อินเทอร์เฟซใดที่เราสามารถทำงานได้) เพื่อที่จะทำงานตามแนวคิด ORM และวิธีการใช้เงินเหล่านี้ ข้อมูลจำเพาะไม่ได้อธิบายการใช้งานเครื่องมือ ซึ่งทำให้สามารถใช้การใช้งานที่แตกต่างกันสำหรับข้อกำหนดเดียวได้ คุณสามารถทำให้มันง่ายขึ้นและบอกว่าข้อกำหนดนั้นเป็นคำอธิบายของ API ข้อความของข้อกำหนด JPA สามารถพบได้บนเว็บไซต์ Oracle: " JSR 338: JavaTM Persistence API " ดังนั้น ในการใช้ JPA เราจำเป็นต้องมีการดำเนินการบางอย่างซึ่งเราจะใช้เทคโนโลยี การใช้งาน JPA เรียกอีกอย่างว่าผู้ให้บริการ JPA หนึ่งในการใช้งาน JPA ที่โดดเด่นที่สุดคือHibernate ข้าพเจ้าจึงเสนอให้พิจารณา
JPA: เทคโนโลยีเบื้องต้น - 3

การสร้างโครงการ

เนื่องจาก JPA เป็นเรื่องเกี่ยวกับ Java เราจึงต้องมีโปรเจ็กต์ Java เราสามารถสร้างโครงสร้างไดเร็กทอรีด้วยตนเองและเพิ่มไลบรารีที่จำเป็นด้วยตนเอง แต่จะสะดวกกว่าและถูกต้องกว่ามากในการใช้ระบบสำหรับการประกอบโปรเจ็กต์อัตโนมัติ (กล่าวคือ โดยพื้นฐานแล้วนี่เป็นเพียงโปรแกรมที่จะจัดการแอสเซมบลีของโปรเจ็กต์ให้เรา สร้างไดเร็กทอรีเพิ่มไลบรารีที่จำเป็นใน classpath ฯลฯ .) หนึ่งในระบบดังกล่าวคือ Gradle คุณสามารถอ่านเพิ่มเติมเกี่ยวกับ Gradle ได้ที่นี่: " บทนำโดยย่อเกี่ยวกับ Gradle " ดังที่เราทราบ ฟังก์ชัน Gradle (เช่น สิ่งที่สามารถทำได้) ถูกนำมาใช้โดยใช้ Gradle Plugins ต่างๆ ลองใช้ Gradle และปลั๊กอิน " Gradle Build Init Plugin " มารันคำสั่งกัน:

gradle init --type java-application
Gradle จะทำโครงสร้างไดเร็กทอรีที่จำเป็นสำหรับเราและสร้างคำอธิบายพื้นฐานของโปรเจ็กต์ในสคริปต์บิลbuild.gradleด์ ดังนั้นเราจึงมีใบสมัคร เราต้องคิดถึงสิ่งที่เราต้องการอธิบายหรือสร้างโมเดลด้วยแอปพลิเคชันของเรา มาใช้เครื่องมือสร้างโมเดลกัน เช่นapp.quickdatabasediagrams.com JPA: เทคโนโลยีเบื้องต้น - 4เราควรพูดว่าสิ่งที่เราอธิบายไปคือ "โมเดลโดเมน" ของเรา โดเมนคือ "สาขาวิชา" โดยทั่วไป โดเมนคือ “การครอบครอง” ในภาษาลาติน ในยุคกลาง เป็นชื่อที่ตั้งให้กับพื้นที่ที่กษัตริย์หรือขุนนางศักดินาเป็นเจ้าของ และในภาษาฝรั่งเศสก็กลายเป็นคำว่า "domaine" ซึ่งแปลว่า "พื้นที่" ดังนั้นเราจึงอธิบาย "โมเดลโดเมน" = "โมเดลหัวเรื่อง" ของเรา องค์ประกอบแต่ละอย่างของโมเดลนี้คือ "แก่นแท้" บางอย่างจากชีวิตจริง ในกรณีของเรา สิ่งเหล่านี้คือเอนทิตี: หมวดหมู่ ( Category), หัวเรื่อง ( Topic) มาสร้างแพ็คเกจแยกต่างหากสำหรับเอนทิตี เช่น ด้วยชื่อโมเดล และมาเพิ่มคลาส Java ที่อธิบายเอนทิตีที่นั่น ในโค้ด Java เอนทิตีดังกล่าวจะเป็นPOJO ปกติ ซึ่งอาจมีลักษณะดังนี้:
public class Category {
    private Long id;
    private String title;

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }
}
ลองคัดลอกเนื้อหาของชั้นเรียนและสร้างชั้นเรียนโดยการTopicเปรียบเทียบ เขาจะแตกต่างเฉพาะในสิ่งที่เขารู้เกี่ยวกับประเภทที่เขาอยู่ ดังนั้น เรามาเพิ่มTopicฟิลด์หมวดหมู่และวิธีการทำงานกับฟิลด์นั้นในชั้นเรียน:
private Category category;

public Category getCategory() {
	return category;
}

public void setCategory(Category category) {
	this.category = category;
}
ตอนนี้เรามีแอปพลิเคชัน Java ที่มีโมเดลโดเมนเป็นของตัวเอง ตอนนี้ได้เวลาเริ่มเชื่อมต่อกับโครงการ JPA แล้ว
JPA: เทคโนโลยีเบื้องต้น - 5

เพิ่ม JPA

อย่างที่เราจำได้ JPA หมายความว่าเราจะบันทึกบางสิ่งลงในฐานข้อมูล ดังนั้นเราจึงจำเป็นต้องมีฐานข้อมูล หากต้องการใช้การเชื่อมต่อฐานข้อมูลในโครงการของเรา เราจำเป็นต้องเพิ่มไลบรารีการพึ่งพาเพื่อเชื่อมต่อกับฐานข้อมูล อย่างที่เราจำได้ เราใช้ Gradle ซึ่งสร้างสคริปต์สำหรับbuild.gradleเรา ในนั้นเราจะอธิบายการพึ่งพาที่โครงการของเราต้องการ การพึ่งพาคือไลบรารีเหล่านั้นซึ่งโค้ดของเราไม่สามารถทำงานได้ เริ่มต้นด้วยคำอธิบายของการพึ่งพาการเชื่อมต่อกับฐานข้อมูล เราทำสิ่งนี้ในลักษณะเดียวกับที่เราจะทำถ้าเราเพิ่งทำงานกับ JDBC:

dependencies {
	implementation 'com.h2database:h2:1.4.199'
ตอนนี้เรามีฐานข้อมูลแล้ว ขณะนี้เราสามารถเพิ่มเลเยอร์ให้กับแอปพลิเคชันของเราที่รับผิดชอบในการแมปออบเจ็กต์ Java ของเราเข้ากับแนวคิดฐานข้อมูล (จาก Java ถึง SQL) ดังที่เราจำได้ เราจะใช้การดำเนินการตามข้อกำหนด JPA ที่เรียกว่า Hibernate สำหรับสิ่งนี้:

dependencies {
	implementation 'com.h2database:h2:1.4.199'
	implementation 'org.hibernate:hibernate-core:5.4.2.Final'
ตอนนี้เราต้องกำหนดค่า JPA หากเราอ่านข้อกำหนดและส่วน "8.1 Persistence Unit" เราจะรู้ว่า Persistence Unit เป็นการผสมผสานระหว่างการกำหนดค่า ข้อมูลเมตา และเอนทิตี และเพื่อให้ JPA ทำงานได้ คุณต้องอธิบาย Persistence Unit อย่างน้อยหนึ่งหน่วยในไฟล์คอนฟิกูเรชัน ซึ่งเรียกว่าpersistence.xml. ตำแหน่งของมันถูกอธิบายไว้ในบทข้อมูลจำเพาะ "8.2 บรรจุภัณฑ์หน่วยการคงอยู่" ตามส่วนนี้ หากเรามีสภาพแวดล้อม Java SE เราต้องวางไว้ในรูทของไดเร็กทอรี META-INF
JPA: เทคโนโลยีเบื้องต้น - 6
มาคัดลอกเนื้อหาจากตัวอย่างที่ให้ไว้ในข้อกำหนด JPA ใน8.2.1 persistence.xml fileบท " ":
<persistence>
	<persistence-unit name="JavaRush">
        <description>Persistence Unit For test</description>
        <class>hibernate.model.Category</class>
        <class>hibernate.model.Topic</class>
    </persistence-unit>
</persistence>
แต่นี่ยังไม่เพียงพอ เราต้องบอกว่าใครคือผู้ให้บริการ JPA ของเรา เช่น ผู้ที่ใช้ข้อกำหนด JPA:
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
ตอนนี้เรามาเพิ่มการตั้งค่า ( properties) บางส่วน (เริ่มต้นด้วยjavax.persistence) เป็นการกำหนดค่า JPA มาตรฐาน และอธิบายไว้ในข้อกำหนด JPA ในส่วน "คุณสมบัติ 8.2.1.9" การกำหนดค่าบางอย่างเป็นแบบเฉพาะของผู้ให้บริการ (ในกรณีของเรา จะส่งผลต่อ Hibernate ในฐานะผู้ให้บริการ Jpa บล็อกการตั้งค่าของเราจะมีลักษณะดังนี้:
<properties>
    <property name="javax.persistence.jdbc.driver" value="org.h2.Driver" />
    <property name="javax.persistence.jdbc.url" value="jdbc:h2:mem:db1;DB_CLOSE_DELAY=-1;MVCC=TRUE" />
    <property name="javax.persistence.jdbc.user" value="sa" />
    <property name="javax.persistence.jdbc.password" value="" />
    <property name="hibernate.show_sql" value="true" />
    <property name="hibernate.hbm2ddl.auto" value="create" />
</properties>
ตอนนี้เรามีการกำหนดค่าที่เข้ากันได้กับ JPA persistence.xmlมีผู้ให้บริการ JPA Hibernate และมีฐานข้อมูล H2 และยังมี 2 คลาสที่เป็นโมเดลโดเมนของเรา ในที่สุดเรามาทำให้ทั้งหมดนี้ใช้งานได้ ในแค็ตตาล็อก/test/javaGradle ของเรากรุณาสร้างเทมเพลตสำหรับการทดสอบหน่วยและเรียกมันว่า AppTest มาใช้กันเถอะ ตามที่ระบุไว้ในบท "7.1 Persistence Contexts" ของข้อกำหนด JPA เอนทิตีในโลก JPA อาศัยอยู่ในพื้นที่ที่เรียกว่า Persistence Context แต่เราไม่ได้ทำงานโดยตรงกับ Persistence Context สำหรับสิ่งนี้ เราใช้Entity Managerหรือ "ผู้จัดการเอนทิตี" เขาคือผู้ที่รู้เกี่ยวกับบริบทและสิ่งที่อาศัยอยู่ที่นั่น เราโต้ตอบกับEntity Manager'อ้อม สิ่งที่เหลืออยู่ก็คือต้องเข้าใจว่าเราจะหาสิ่งนี้ได้จากที่ไหนEntity Manager? ตามบท "7.2.2 การได้รับ Application-managed Entity Manager" ของข้อกำหนด JPA เราต้องใช้EntityManagerFactory. ดังนั้น เรามาลองใช้ข้อกำหนด JPA และยกตัวอย่างจากบท “7.3.2 การได้รับ Entity Manager Factory ในสภาพแวดล้อม Java SE” และจัดรูปแบบในรูปแบบของการทดสอบหน่วยอย่างง่าย:
@Test
public void shouldStartHibernate() {
	EntityManagerFactory emf = Persistence.createEntityManagerFactory( "JavaRush" );
	EntityManager entityManager = emf.createEntityManager();
}
การทดสอบนี้จะแสดงข้อผิดพลาด "เวอร์ชัน XSD JPA Persence.xml ที่ไม่รู้จัก" แล้ว เหตุผลก็คือpersistence.xmlคุณต้องระบุสคีมาที่จะใช้อย่างถูกต้อง ตามที่ระบุไว้ในข้อกำหนด JPA ในส่วน "8.3 Persistence.xml Schema":
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
             http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd"
             version="2.2">
นอกจากนี้ลำดับขององค์ประกอบก็มีความสำคัญเช่นกัน จึงproviderต้องระบุก่อนที่จะแสดงรายการคลาส หลังจากนี้การทดสอบจะดำเนินการได้สำเร็จ เราได้เสร็จสิ้นการเชื่อมต่อ JPA โดยตรงแล้ว ก่อนที่เราจะไปต่อ เรามาคิดถึงการทดสอบที่เหลือกันดีกว่า การทดสอบแต่ละครั้งของเราจะต้องEntityManagerมี ตรวจสอบให้แน่ใจว่าการทดสอบแต่ละครั้งมีการทดสอบของตัวเองEntityManagerตั้งแต่เริ่มต้นการดำเนินการ นอกจากนี้เรายังต้องการให้ฐานข้อมูลใหม่ทุกครั้ง เนื่องจากเราใช้ ตัว เลือกinmemoryนี้ก็เพียงพอที่จะปิด EntityManagerFactoryการสร้างFactoryเป็นการดำเนินการที่มีราคาแพง แต่สำหรับการทดสอบก็ถือว่าสมเหตุสมผล JUnit ช่วยให้คุณสามารถระบุวิธีการที่จะดำเนินการก่อน (ก่อน) และหลัง (หลัง) การดำเนินการของการทดสอบแต่ละครั้ง:
public class AppTest {
    private EntityManager em;

    @Before
    public void init() {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory( "JavaRush" );
        em = emf.createEntityManager();
    }

    @After
    public void close() {
        em.getEntityManagerFactory().close();
        em.close();
    }
ตอนนี้ก่อนที่จะดำเนินการทดสอบใด ๆ จะมีการสร้างอันใหม่EntityManagerFactoryซึ่งจะเกี่ยวข้องกับการสร้างฐานข้อมูลใหม่เพราะ hibernate.hbm2ddl.autoมีความcreateหมาย และจากโรงงานแห่งใหม่ เราก็จะได้โรงงานEntityManagerใหม่
JPA: เทคโนโลยีเบื้องต้น - 7

เอนทิตี

อย่างที่เราจำได้ ก่อนหน้านี้เราได้สร้างคลาสที่อธิบายโมเดลโดเมนของเรา เราได้กล่าวไปแล้วว่าสิ่งเหล่านี้คือ "สาระสำคัญ" ของเรา นี่คือเอนทิตีที่เราจะจัดการโดยEntityManagerใช้ มาเขียนการทดสอบง่ายๆ เพื่อบันทึกสาระสำคัญของหมวดหมู่:
@Test
public void shouldPersistCategory() {
	Category cat = new Category();
	cat.setTitle("new category");
	// JUnit обеспечит тест свежим EntityManager'ом
	em.persist(cat);
}
แต่การทดสอบนี้จะไม่ทำงานทันที เพราะ... เราจะได้รับข้อผิดพลาดต่างๆ ที่จะช่วยให้เราเข้าใจว่าเอนทิตีคืออะไร:
  • Unknown entity: hibernate.model.Category
    ทำไม Hibernate ถึงไม่เข้าใจว่าCategoryมันคือ อะไร entity? ประเด็นก็คือเอนทิตีต้องได้รับการอธิบายตามมาตรฐาน JPA
    คลาสเอนทิตีจะต้องมีคำอธิบายประกอบด้วยคำอธิบายประกอบ@Entityดังที่ระบุไว้ในบท "2.1 คลาสเอนทิตี" ของข้อกำหนด JPA

  • No identifier specified for entity: hibernate.model.Category
    เอนทิตีต้องมีตัวระบุเฉพาะที่สามารถใช้เพื่อแยกแยะระเบียนหนึ่งจากอีกระเบียนหนึ่งได้
    ตามบท "2.4 คีย์หลักและเอกลักษณ์เอนทิตี" ของข้อกำหนด JPA "ทุกเอนทิตีต้องมีคีย์หลัก" กล่าวคือ ทุกเอนทิตีต้องมี "คีย์หลัก" คีย์หลักดังกล่าวจะต้องระบุโดยคำอธิบายประกอบ@Id

  • ids for this class must be manually assigned before calling save()
    บัตรประจำตัวต้องมาจากที่ไหนสักแห่ง สามารถระบุได้ด้วยตนเองหรือสามารถรับได้โดยอัตโนมัติ
    ดังนั้น ตามที่ระบุในบท "11.2.3.3 GeneratedValue" และ "11.1.20 GeneratedValue Annotation" เราจึงสามารถระบุคำอธิบายประกอบ@GeneratedValueได้

ดังนั้นเพื่อให้คลาสหมวดหมู่กลายเป็นเอนทิตี เราต้องทำการเปลี่ยนแปลงต่อไปนี้:
@Entity
public class Category {
    @Id
    @GeneratedValue
    private Long id;
นอกจากนี้ คำอธิบายประกอบยัง ระบุ ว่า@Idควรใช้อันใด Access Typeคุณสามารถอ่านเพิ่มเติมเกี่ยวกับประเภทการเข้าถึงได้ในข้อกำหนด JPA ในหัวข้อ "2.3 ประเภทการเข้าถึง" สั้นๆ เลย เพราะ... เราระบุ@Idไว้เหนือฟิลด์ ( ) จาก นั้นfieldประเภทการเข้าถึงจะเป็นค่าเริ่มต้นfield-basedไม่ใช่ property-basedดังนั้นผู้ให้บริการ JPA จะอ่านและจัดเก็บค่าโดยตรงจากฟิลด์ หากเราวางไว้@Idเหนือทะเยอทะยานก็property-basedจะมีการใช้การเข้าถึงเช่น ผ่าน getter และ setter เมื่อรันการทดสอบ เรายังเห็นว่าคำขอใดบ้างที่ถูกส่งไปยังฐานข้อมูล (ขอบคุณตัวเลือกhibernate.show_sql) แต่เมื่อบันทึกแล้ว เราไม่เห็นinsert's เลย ปรากฎว่าเราไม่ได้บันทึกอะไรเลยจริง ๆ เหรอ? JPA ช่วยให้คุณสามารถซิงโครไนซ์บริบทการคงอยู่และฐานข้อมูลโดยใช้วิธีการflush:
entityManager.flush();
แต่ถ้าเราดำเนินการตอนนี้ เราจะได้รับข้อผิดพลาด: ไม่มีธุรกรรมอยู่ระหว่างดำเนินการ และตอนนี้ก็ถึงเวลาเรียนรู้ว่า JPA ใช้ธุรกรรมอย่างไร
JPA: เทคโนโลยีเบื้องต้น - 8

ธุรกรรม JPA

ดังที่เราจำได้ JPA มีพื้นฐานอยู่บนแนวคิดของบริบทการคงอยู่ นี่คือสถานที่ที่เอนทิตีอาศัยอยู่ และเราจัดการเอนทิตีEntityManagerผ่าน เมื่อเราดำเนินการคำสั่งpersistเราจะวางเอนทิตีไว้ในบริบท แม่นยำยิ่งขึ้น เราบอกEntityManagerว่าสิ่งนี้จำเป็นต้องทำ แต่บริบทนี้เป็นเพียงพื้นที่เก็บข้อมูลบางส่วนเท่านั้น บางครั้งเรียกว่า "แคชระดับแรก" ด้วยซ้ำ แต่จำเป็นต้องเชื่อมต่อกับฐานข้อมูล คำสั่งflushซึ่งก่อนหน้านี้ล้มเหลวโดยมีข้อผิดพลาด จะซิงโครไนซ์ข้อมูลจากบริบทการคงอยู่กับฐานข้อมูล แต่สิ่งนี้ต้องมีการขนส่งและการขนส่งนี้เป็นธุรกรรม ธุรกรรมใน JPA ได้รับการอธิบายไว้ในส่วน "7.5 ธุรกรรมการควบคุม" ของข้อกำหนด มี API พิเศษสำหรับการใช้ธุรกรรมใน JPA:
entityManager.getTransaction().begin();
entityManager.getTransaction().commit();
เราจำเป็นต้องเพิ่มการจัดการธุรกรรมให้กับโค้ดของเรา ซึ่งทำงานก่อนและหลังการทดสอบ:
@Before
public void init() {
	EntityManagerFactory emf = Persistence.createEntityManagerFactory( "JavaRush" );
	em = emf.createEntityManager();
	em.getTransaction().begin();
}
@After
public void close() {
	if (em.getTransaction().isActive()) {
		em.getTransaction().commit();
        }
	em.getEntityManagerFactory().close();
	em.close();
}
หลังจากเพิ่มแล้ว เราจะเห็นนิพจน์ใน SQL ที่ไม่เคยมีมาก่อนในบันทึกการแทรก:
JPA: เทคโนโลยีเบื้องต้น - 9
การเปลี่ยนแปลงที่สะสมในEntityManagerธุรกรรมได้รับการคอมมิต (ยืนยันและบันทึก) ในฐานข้อมูล ตอนนี้เราลองค้นหาแก่นแท้ของเรา มาสร้างการทดสอบเพื่อค้นหาเอนทิตีด้วย ID ของมัน:
@Test
public void shouldFindCategory() {
	Category cat = new Category();
	cat.setTitle("test");
	em.persist(cat);
	Category result = em.find(Category.class, 1L);
	assertNotNull(result);
}
ในกรณีนี้ เราจะได้รับเอนทิตีที่เราบันทึกไว้ก่อนหน้านี้ แต่เราจะไม่เห็นแบบสอบถาม SELECT ในบันทึก และทุกอย่างขึ้นอยู่กับสิ่งที่เราพูด: “ผู้จัดการเอนทิตี โปรดหาเอนทิตีหมวดหมู่ที่มี ID=1 ให้ฉันหน่อย” และผู้จัดการเอนทิตีจะดูในบริบทของมันก่อน (ใช้แคชประเภทหนึ่ง) และหากไม่พบก็จะเข้าไปดูในฐานข้อมูล ควรเปลี่ยน ID เป็น 2 (ไม่มีสิ่งนั้นเราบันทึกเพียง 1 อินสแตนซ์) และเราจะเห็นว่าSELECTคำขอปรากฏขึ้น เนื่องจากไม่พบเอนทิตีในบริบทและEntityManagerฐานข้อมูลพยายามค้นหาเอนทิตี มีคำสั่งต่าง ๆ ที่เราสามารถใช้เพื่อควบคุมสถานะของเอนทิตีในบริบท การเปลี่ยนแปลงของเอนทิตีจากสถานะหนึ่งไปอีกสถานะหนึ่งเรียกว่า วงจรชีวิตของเอนทิตี - lifecycle.
JPA: เทคโนโลยีเบื้องต้น - 10

วงจรชีวิตของเอนทิตี

วงจรชีวิตของเอนทิตีอธิบายไว้ในข้อกำหนด JPA ในบท "3.2 วงจรชีวิตของอินสแตนซ์เอนทิตี" เพราะ เอนทิตีอาศัยอยู่ในบริบทและถูกควบคุมโดยEntityManagerจากนั้นพวกเขาบอกว่าเอนทิตีถูกควบคุม กล่าวคือ จัดการ มาดูช่วงชีวิตของเอนทิตี:
// 1. New or Transient (временный)
Category cat = new Category();
cat.setTitle("new category");
// 2. Managed or Persistent
entityManager.persist(cat);
// 3. Транзакция завершена, все сущности в контексте detached
entityManager.getTransaction().begin();
entityManager.getTransaction().commit();
// 4. Сущность изымаем из контекста, она становится detached
entityManager.detach(cat);
// 5. Сущность из detached можно снова сделать managed
Category managed = entityManager.merge(cat);
// 6. И можно сделать Removed. Интересно, что cat всё равно detached
entityManager.remove(managed);
และนี่คือไดอะแกรมที่จะรวมเข้าด้วยกัน:
JPA: เทคโนโลยีเบื้องต้น - 11
JPA: เทคโนโลยีเบื้องต้น - 12

การทำแผนที่

ใน JPA เราสามารถอธิบายความสัมพันธ์ของเอนทิตีระหว่างกัน โปรดจำไว้ว่าเราได้ดูความสัมพันธ์ของเอนทิตีระหว่างกันแล้วเมื่อเราจัดการกับโมเดลโดเมนของเรา จากนั้นเราใช้ ทรัพยากร Quickdatabasediagrams.com :
JPA: เทคโนโลยีเบื้องต้น - 13
การสร้างการเชื่อมต่อระหว่างเอนทิตีเรียกว่าการแมปหรือการเชื่อมโยง (การแมปการเชื่อมโยง) ประเภทของสมาคมที่สามารถสร้างได้โดยใช้ JPA มีดังต่อไปนี้:
JPA : เทคโนโลยีเบื้องต้น - 14
ลองดูที่เอนทิตีTopicที่อธิบายหัวข้อ เราจะพูดอะไรเกี่ยวกับทัศนคติTopicต่อCategory? หลายคนTopicจะอยู่ในหมวดหมู่เดียว ManyToOneดังนั้น เราจึงจำเป็นต้องมีสมาคม มาแสดงความสัมพันธ์นี้ใน JPA:
@ManyToOne
@JoinColumn(name = "category_id")
private Category category;
หากต้องการจดจำคำอธิบายประกอบที่จะใส่ คุณสามารถจำไว้ว่าส่วนสุดท้ายมีหน้าที่รับผิดชอบในฟิลด์ที่ระบุคำอธิบายประกอบด้านบน ToOne- ตัวอย่างเฉพาะ ToMany- คอลเลกชัน ตอนนี้การเชื่อมต่อของเราเป็นแบบทางเดียว มาทำให้มันเป็นการสื่อสารสองทางกันเถอะ มาเพิ่มCategoryความรู้เกี่ยวกับทุกคนTopicที่อยู่ในหมวดหมู่นี้กันดีกว่า ต้องลงท้ายด้วยเพราะToManyเรามีรายการ Topicนั่นคือทัศนคติ "ต่อหลายหัวข้อ" คำถามยังคงอยู่ - OneToManyหรือManyToMany:
JPA: เทคโนโลยีเบื้องต้น - 15
คำตอบที่ดีในหัวข้อเดียวกันสามารถอ่านได้ที่นี่: " อธิบาย ORM oneToMany, manyToMany ความสัมพันธ์เหมือนฉันอายุห้าขวบ " หากหมวดหมู่มีความเกี่ยวข้องกับToManyหัวข้อ แต่ละหัวข้อเหล่านี้สามารถมีได้เพียงหมวดหมู่เดียวเท่านั้น ก็จะเป็นมิOneฉะนั้น Manyดังนั้นCategoryรายการหัวข้อทั้งหมดจะเป็นดังนี้:
@OneToMany(cascade = CascadeType.ALL)
@JoinColumn(name = "topic_id")
private Set<Topic> topics = new HashSet<>();
และอย่าลืมCategoryเขียน getter เพื่อรับรายการหัวข้อทั้งหมด:
public Set<Topic> getTopics() {
	return this.topics;
}
ความสัมพันธ์แบบสองทิศทางเป็นสิ่งที่ยากมากในการติดตามโดยอัตโนมัติ ดังนั้น JPA จึงส่งต่อความรับผิดชอบนี้ให้กับนักพัฒนา สิ่งนี้มีความหมายสำหรับเราคือ เมื่อเราสร้างTopicความสัมพันธ์เอนทิตีด้วยCategoryเราต้องตรวจสอบให้แน่ใจว่าข้อมูลมีความสอดคล้องกัน ทำได้ง่ายๆ:
public void setCategory(Category category) {
	category.getTopics().add(this);
	this.category = category;
}
มาเขียนการทดสอบง่ายๆ เพื่อตรวจสอบ:
@Test
public void shouldPersistCategoryAndTopics() {
	Category cat = new Category();
	cat.setTitle("test");
	Topic topic = new Topic();
	topic.setTitle("topic");
	topic.setCategory(cat);
 	em.persist(cat);
}
การทำแผนที่เป็นหัวข้อที่แยกจากกันทั้งหมด วัตถุประสงค์ของการทบทวนนี้คือเพื่อทำความเข้าใจวิธีการบรรลุผลดังกล่าว คุณสามารถอ่านเพิ่มเติมเกี่ยวกับการทำแผนที่ได้ที่นี่:
JPA : เทคโนโลยีเบื้องต้น - 16

เจพีคิวแอล

JPA แนะนำเครื่องมือที่น่าสนใจ - การสืบค้นในภาษา Java Persistence Query ภาษานี้คล้ายกับ SQL แต่ใช้โมเดลอ็อบเจ็กต์ Java แทนตาราง SQL ลองดูตัวอย่าง:
@Test
public void shouldPerformQuery() {
	Category cat = new Category();
	cat.setTitle("query");
	em.persist(cat);
	Query query = em.createQuery("SELECT c from Category c WHERE c.title = 'query'");
 	assertNotNull(query.getSingleResult());
}
ดังที่เราเห็น ในแบบสอบถาม เราใช้การอ้างอิงถึงเอนทิตีCategoryไม่ใช่ตาราง และในด้านของเอนทิตีนี้titleด้วย JPQL มีคุณสมบัติที่มีประโยชน์มากมายและสมควรได้รับบทความของตัวเอง รายละเอียดเพิ่มเติมสามารถพบได้ในการตรวจสอบ:
JPA : เทคโนโลยีเบื้องต้น - 17

API เกณฑ์

และสุดท้ายนี้ ฉันอยากจะพูดถึง Criteria API JPA แนะนำเครื่องมือสร้างแบบสอบถามแบบไดนามิก ตัวอย่างการใช้ Criteria API:
@Test
public void shouldFindWithCriteriaAPI() {
	Category cat = new Category();
	em.persist(cat);
	CriteriaBuilder cb = em.getCriteriaBuilder();
	CriteriaQuery<Category> query = cb.createQuery(Category.class);
	Root<Category> c = query.from(Category.class);
	query.select(c);
	List<Category> resultList = em.createQuery(query).getResultList();
	assertEquals(1, resultList.size());
}
ตัวอย่างนี้เทียบเท่ากับการดำเนินการตามคำขอ " SELECT c FROM Category c" Criteria APIเป็นเครื่องมือที่มีประสิทธิภาพ คุณสามารถอ่านเพิ่มเติมเกี่ยวกับเรื่องนี้ได้ที่นี่:

บทสรุป

ดังที่เราเห็น JPA มีคุณสมบัติและเครื่องมือมากมาย แต่ละคนต้องใช้ประสบการณ์และความรู้ แม้จะอยู่ในกรอบการทบทวน JPA ก็ไม่สามารถพูดถึงทุกสิ่งได้ ไม่ต้องพูดถึงการดำน้ำแบบละเอียด แต่ฉันหวังว่าหลังจากอ่านแล้ว มันชัดเจนมากขึ้นว่า ORM และ JPA คืออะไร ทำงานอย่างไร และทำอะไรได้บ้าง สำหรับของว่างฉันเสนอวัสดุต่างๆ: #เวียเชสลาฟ
ความคิดเห็น
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION