JPA คืออะไร? บทนำสู่ Java Persistence API

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

ด้วยตัวมันเอง JPA ไม่ใช่เครื่องมือหรือกรอบ แต่เป็นการกำหนดชุดของแนวคิดที่สามารถนำไปใช้โดยเครื่องมือหรือกรอบงานใดก็ได้ ในขณะที่แบบจำลองการทำแผนที่เชิงสัมพันธ์เชิงวัตถุ (ORM) ของ JPA เดิมมีพื้นฐานมาจาก Hibernate แต่ก็มีการพัฒนาตั้งแต่นั้นมา ในทำนองเดียวกันในขณะที่ JPA เดิมมีไว้สำหรับใช้กับฐานข้อมูลเชิงสัมพันธ์ / SQL การใช้งาน JPA บางส่วนได้รับการขยายเพื่อใช้กับที่เก็บข้อมูล NoSQL เฟรมเวิร์กยอดนิยมที่รองรับ JPA กับ NoSQL คือ EclipseLink ซึ่งเป็นการนำไปใช้อ้างอิงสำหรับ JPA 2.2

JPA 2.2 ในจาการ์ตา EE

Java Persistence API เปิดตัวครั้งแรกเป็นชุดย่อยของข้อกำหนด EJB 3.0 (JSR 220) ใน Java EE 5 ตั้งแต่นั้นมาได้มีการพัฒนาเป็นข้อมูลจำเพาะของตัวเองโดยเริ่มจากการเปิดตัว JPA 2.0 ใน Java EE 6 (JSR 317) ในขณะที่เขียนนี้ JPA 2.2 ได้ถูกนำมาใช้เพื่อดำเนินการต่อโดยเป็นส่วนหนึ่งของ Jakarta EE

JPA และ Hibernate

เนื่องจากประวัติศาสตร์ที่เกี่ยวพันกัน Hibernate และ JPA จึงถูกรวมเข้าด้วยกันบ่อยครั้ง อย่างไรก็ตามเช่นเดียวกับข้อกำหนด Java Servlet JPA ได้สร้างเครื่องมือและเฟรมเวิร์กที่เข้ากันได้มากมาย ไฮเบอร์เนตเป็นเพียงหนึ่งในนั้น

พัฒนาโดย Gavin King และเปิดตัวในต้นปี 2545 Hibernate เป็นไลบรารี ORM สำหรับ Java King พัฒนา Hibernate เพื่อเป็นทางเลือกให้กับถั่วเอนทิตีเพื่อการคงอยู่ เฟรมเวิร์กได้รับความนิยมอย่างมากและจำเป็นมากในเวลานั้นแนวคิดหลายอย่างถูกนำมาใช้และประมวลผลในข้อกำหนด JPA แรก

ปัจจุบัน Hibernate ORM เป็นหนึ่งในการใช้งาน JPA ที่เป็นผู้ใหญ่ที่สุดและยังคงเป็นตัวเลือกยอดนิยมสำหรับ ORM ใน Java ไฮเบอร์เนต ORM 5.3.8 (เวอร์ชันปัจจุบัน ณ การเขียนนี้) ใช้ JPA 2.2 นอกจากนี้กลุ่มเครื่องมือของ Hibernate ได้ขยายไปถึงเครื่องมือยอดนิยมเช่น Hibernate Search, Hibernate Validator และ Hibernate OGM ซึ่งรองรับการคงอยู่ของโมเดลโดเมนสำหรับ NoSQL

JPA และ EJB

ดังที่ระบุไว้ก่อนหน้า JPA ถูกนำมาใช้เป็นชุดย่อยของ EJB 3.0 แต่ได้มีการพัฒนาเป็นข้อกำหนดของตัวเอง EJB เป็นข้อกำหนดที่มีจุดเน้นแตกต่างจาก JPA และถูกนำไปใช้ในคอนเทนเนอร์ EJB คอนเทนเนอร์ EJB แต่ละตัวมีเลเยอร์การคงอยู่ซึ่งกำหนดโดยข้อกำหนดของ JPA

Java ORM คืออะไร?

แม้ว่าจะแตกต่างกันในการดำเนินการ แต่การใช้งาน JPA ทุกครั้งจะมีเลเยอร์ ORM บางประเภท เพื่อให้เข้าใจถึงเครื่องมือที่เข้ากันได้กับ JPA และ JPA คุณต้องมีความเข้าใจที่ดีเกี่ยวกับ ORM

การทำแผนที่เชิงสัมพันธ์กับวัตถุเป็นงานที่นักพัฒนามีเหตุผลที่ดีที่จะหลีกเลี่ยงการทำด้วยตนเอง กรอบเช่น Hibernate ออมหรือ EclipseLink codifies งานที่เข้ามาในห้องสมุดหรือกรอบการชั้นออม ในฐานะส่วนหนึ่งของสถาปัตยกรรมแอ็พพลิเคชันเลเยอร์ ORM มีหน้าที่จัดการการแปลงอ็อบเจ็กต์ซอฟต์แวร์เพื่อโต้ตอบกับตารางและคอลัมน์ในฐานข้อมูลเชิงสัมพันธ์ ใน Java เลเยอร์ ORM จะแปลงคลาส Java และอ็อบเจ็กต์เพื่อให้สามารถจัดเก็บและจัดการในฐานข้อมูลเชิงสัมพันธ์ได้

ตามค่าเริ่มต้นชื่อของวัตถุที่ยังคงอยู่จะกลายเป็นชื่อของตารางและเขตข้อมูลจะกลายเป็นคอลัมน์ เมื่อตั้งค่าตารางแล้วแต่ละแถวของตารางจะสอดคล้องกับวัตถุในแอปพลิเคชัน การแมปวัตถุสามารถกำหนดค่าได้ แต่ค่าเริ่มต้นมักจะทำงานได้ดี

JPA กับ NoSQL

จนกระทั่งเมื่อไม่นานมานี้ฐานข้อมูลที่ไม่ใช่เชิงสัมพันธ์เป็นสิ่งที่ไม่ธรรมดา การเคลื่อนไหวของ NoSQL เปลี่ยนไปทั้งหมดและตอนนี้นักพัฒนา Java มีฐานข้อมูล NoSQL ที่หลากหลาย การใช้งาน JPA บางอย่างได้รับการพัฒนาเพื่อรองรับ NoSQL รวมถึง Hibernate OGM และ EclipseLink

รูปที่ 1 แสดงให้เห็นถึงบทบาทของ JPA และเลเยอร์ ORM ในการพัฒนาแอปพลิเคชัน

JavaWorld /

การกำหนดค่าเลเยอร์ Java ORM

เมื่อคุณตั้งค่าโปรเจ็กต์ใหม่เพื่อใช้ JPA คุณจะต้องกำหนดค่าผู้ให้บริการข้อมูลและ JPA คุณจะกำหนดค่าตัวเชื่อมต่อที่เก็บข้อมูลเพื่อเชื่อมต่อกับฐานข้อมูลที่คุณเลือก (SQL หรือ NoSQL) คุณจะรวมและกำหนดค่าผู้ให้บริการ JPAซึ่งเป็นเฟรมเวิร์กเช่น Hibernate หรือ EclipseLink แม้ว่าคุณจะสามารถกำหนดค่า JPA ได้ด้วยตนเอง แต่นักพัฒนาหลายคนก็เลือกใช้การสนับสนุนแบบสำเร็จรูปของ Spring โปรดดู " การติดตั้งและการตั้งค่า JPA " ด้านล่างสำหรับการสาธิตการติดตั้งและการตั้งค่า JPA ทั้งแบบแมนนวลและแบบสปริง

Java Data Objects

Java Data Objects เป็นเฟรมเวิร์กการคงอยู่ที่เป็นมาตรฐานซึ่งแตกต่างจาก JPA เป็นหลักโดยการสนับสนุนตรรกะการคงอยู่ในออบเจ็กต์และด้วยการสนับสนุนที่ยาวนานสำหรับการทำงานกับที่เก็บข้อมูลที่ไม่ใช่เชิงสัมพันธ์ JPA และ JDO มีความคล้ายคลึงกันเพียงพอที่ผู้ให้บริการ JDO มักสนับสนุน JPA ดู Apache JDO Project เพื่อเรียนรู้เพิ่มเติมเกี่ยวกับ JDO ที่เกี่ยวข้องกับมาตรฐานการคงอยู่อื่น ๆ เช่น JPA และ JDBC

การคงอยู่ของข้อมูลใน Java

จากมุมมองของการเขียนโปรแกรมเลเยอร์ ORM เป็นเลเยอร์อะแด็ปเตอร์ : ปรับภาษาของกราฟออบเจ็กต์เป็นภาษาของ SQL และตารางเชิงสัมพันธ์ เลเยอร์ ORM ช่วยให้นักพัฒนาเชิงวัตถุสามารถสร้างซอฟต์แวร์ที่เก็บข้อมูลไว้ได้โดยไม่ต้องออกจากกระบวนทัศน์เชิงวัตถุ

เมื่อคุณใช้ JPA คุณจะสร้างแผนที่จากที่เก็บข้อมูลไปยังวัตถุโมเดลข้อมูลของแอปพลิเคชันของคุณ แทนที่จะกำหนดวิธีการบันทึกและเรียกใช้อ็อบเจ็กต์คุณกำหนดการแม็ประหว่างอ็อบเจ็กต์และฐานข้อมูลของคุณจากนั้นเรียกใช้ JPA เพื่อคงอยู่ หากคุณใช้ฐานข้อมูลเชิงสัมพันธ์การเชื่อมต่อจริงส่วนใหญ่ระหว่างรหัสแอปพลิเคชันของคุณและฐานข้อมูลจะถูกจัดการโดย JDBC, Java Database Connectivity API

ตามข้อมูลจำเพาะ JPA จัดเตรียมคำอธิบายประกอบข้อมูลเมตาซึ่งคุณใช้กำหนดการแมประหว่างอ็อบเจ็กต์และฐานข้อมูล การใช้งาน JPA แต่ละครั้งจะมีเครื่องมือของตัวเองสำหรับคำอธิบายประกอบ JPA ข้อมูลจำเพาะ JPA ยังให้PersistanceManagerหรือEntityManagerซึ่งเป็นจุดสำคัญในการติดต่อกับระบบ JPA (โดยรหัสตรรกะทางธุรกิจของคุณจะบอกระบบว่าจะทำอย่างไรกับวัตถุที่แมป)

เพื่อให้ทั้งหมดนี้เป็นรูปธรรมมากขึ้นให้พิจารณา Listing 1 ซึ่งเป็นคลาสข้อมูลง่ายๆสำหรับการสร้างโมเดลนักดนตรี

รายการ 1. คลาสข้อมูลอย่างง่ายใน Java

 public class Musician { private Long id; private String name; private Instrument mainInstrument; private ArrayList performances = new ArrayList(); public Musician( Long id, String name){ /* constructor setters... */ } public void setName(String name){ this.name = name; } public String getName(){ return this.name; } public void setMainInstrument(Instrument instr){ this.instrument = instr; } public Instrument getMainInstrument(){ return this.instrument; } // ...Other getters and setters... } 

Musicianเรียนในรายการที่ 1 จะใช้ในการรักษาข้อมูล สามารถมีข้อมูลดั้งเดิมเช่นฟิลด์ชื่อ นอกจากนี้ยังสามารถเก็บความสัมพันธ์จากการเรียนอื่น ๆ เช่นและmainInstrumentperformances

Musician's เหตุผลสำหรับความเป็นอยู่คือการประกอบด้วยข้อมูล ประเภทของชั้นนี้บางครั้งก็เป็นที่รู้จักกัน DTO หรือวัตถุการถ่ายโอนข้อมูล DTO เป็นคุณสมบัติทั่วไปของการพัฒนาซอฟต์แวร์ แม้ว่าจะมีข้อมูลหลายประเภท แต่ก็ไม่มีตรรกะทางธุรกิจใด ๆ วัตถุข้อมูลที่คงอยู่เป็นความท้าทายที่แพร่หลายในการพัฒนาซอฟต์แวร์

การคงอยู่ของข้อมูลด้วย JDBC

วิธีหนึ่งในการบันทึกอินสแตนซ์ของMusicianคลาสลงในฐานข้อมูลเชิงสัมพันธ์คือการใช้ไลบรารี JDBC JDBC เป็นชั้นของนามธรรมที่ช่วยให้แอปพลิเคชันออกคำสั่ง SQL โดยไม่ต้องคิดถึงการใช้ฐานข้อมูลพื้นฐาน

รายการ 2 แสดงให้เห็นว่าคุณสามารถคงMusicianคลาสโดยใช้ JDBC ได้อย่างไร

รายการ 2. JDBC การแทรกเร็กคอร์ด

 Musician georgeHarrison = new Musician(0, "George Harrison"); String myDriver = "org.gjt.mm.mysql.Driver"; String myUrl = "jdbc:mysql://localhost/test"; Class.forName(myDriver); Connection conn = DriverManager.getConnection(myUrl, "root", ""); String query = " insert into users (id, name) values (?, ?)"; PreparedStatement preparedStmt = conn.prepareStatement(query); preparedStmt.setInt (1, 0); preparedStmt.setString (2, "George Harrison"); preparedStmt.setString (2, "Rubble"); preparedStmt.execute(); conn.close(); // Error handling removed for brevity 

รหัสในรายการที่ 2 เป็นเอกสารในตัวเองอย่างเป็นธรรม georgeHarrisonวัตถุอาจจะมาจากที่ใดก็ได้ (Front-end ส่งบริการภายนอกอื่น ๆ ) และมี ID และเขตข้อมูลชื่อชุด จากนั้นฟิลด์บนอ็อบเจ็กต์จะถูกใช้เพื่อจัดหาค่าของinsertคำสั่งSQL ( PreparedStatementคลาสเป็นส่วนหนึ่งของ JDBC ซึ่งนำเสนอวิธีการนำค่าไปใช้กับแบบสอบถาม SQL อย่างปลอดภัย)

แม้ว่า JDBC จะอนุญาตให้มีการควบคุมที่มาพร้อมกับการกำหนดค่าด้วยตนเอง แต่ก็ยุ่งยากเมื่อเทียบกับ JPA ในการแก้ไขฐานข้อมูลก่อนอื่นคุณต้องสร้างแบบสอบถาม SQL ที่แมปจากวัตถุ Java ของคุณไปยังตารางในฐานข้อมูลเชิงสัมพันธ์ จากนั้นคุณต้องแก้ไข SQL เมื่อใดก็ตามที่ลายเซ็นของวัตถุเปลี่ยนแปลง ด้วย JDBC การดูแล SQL จะกลายเป็นงานในตัวเอง

การคงอยู่ของข้อมูลด้วย JPA

ตอนนี้ให้พิจารณา Listing 3 ซึ่งเราคงอยู่ในMusicianชั้นเรียนโดยใช้ JPA

Listing 3. Persisting George Harrison with JPA

 Musician georgeHarrison = new Musician(0, "George Harrison"); musicianManager.save(georgeHarrison); 

Listing 3 replaces the manual SQL from Listing 2 with a single line, session.save(), which instructs JPA to persist the object. From then on, the SQL conversion is handled by the framework, so you never have to leave the object-oriented paradigm.

Metadata annotations in JPA

The magic in Listing 3 is the result of a configuration, which is created using JPA's annotations. Developers use annotations to inform JPA which objects should be persisted, and how they should be persisted.

Listing 4 shows the Musician class with a single JPA annotation.

Listing 4. JPA's @Entity annotation

 @Entity public class Musician { // ..class body } 

Persistent objects are sometimes called entities. Attaching @Entity to a class like Musician informs JPA that this class and its objects should be persisted.

XML vs. annotation-based configuration

JPA also supports using external XML files, instead of annotations, to define class metadata. But why would you do that to yourself?

Configuring JPA

Like most modern frameworks, JPA embraces coding by convention (also known as convention over configuration), in which the framework provides a default configuration based on industry best practices. As one example, a class named Musician would be mapped by default to a database table called Musician.

The conventional configuration is a timesaver, and in many cases it works well enough. It is also possible to customize your JPA configuration. As an example, you could use JPA's @Table annotation to specify the table where the Musician class should be stored.

Listing 5. JPA's @Table annotation

 @Entity @Table(name="musician") public class Musician { // ..class body } 

Listing 5 tells JPA to persist the entity (Musician class) to the musician table.

Primary key

In JPA, the primary key is the field used to uniquely identify each object in the database. The primary key is useful for referencing and relating objects to other entities. Whenever you store an object in a table, you will also specify the field to use as its primary key.

In Listing 6, we tell JPA what field to use as Musician's primary key.

Listing 6. Specifying the primary key

 @Entity public class Musician { @Id private Long id; 

In this case, we've used JPA's @Id annotation to specify the id field as Musician's primary key. By default, this configuration assumes the primary key will be set by the database--for instance, when the field is set to auto-increment on the table.

JPA supports other strategies for generating an object's primary key. It also has annotations for changing individual field names. In general, JPA is flexible enough to adapt to any persistence mapping you might need.

CRUD operations

Once you've mapped a class to a database table and established its primary key, you have everything you need to create, retrieve, delete, and update that class in the database. Calling session.save() will create or update the specified class, depending on whether the primary-key field is null or applies to en existing entity. Calling entityManager.remove() will delete the specified class.

Entity relationships in JPA

Simply persisting an object with a primitive field is only half the equation. JPA also has the capability to manage entities in relation to one another. Four kinds of entity relationships are possible in both tables and objects:

    1. One-to-many
    2. Many-to-one
    3. Many-to-many
    4. One-to-one

Each type of relationship describes how an entity relates to other entities. For example, the Musician entity could have a one-to-many relationship with Performance, an entity represented by a collection such as List or Set.

If the Musician included a Band field, the relationship between these entities could be many-to-one, implying collection of Musicians on the single Band class. (Assuming each musician only performs in a single band.)

If Musician included a BandMates field, that could represent a many-to-many relationship with other Musician entities.

สุดท้ายMusicianอาจจะมีความสัมพันธ์แบบหนึ่งต่อหนึ่งกับนิติบุคคลที่ใช้ในการเป็นตัวแทนของการพูดที่มีชื่อเสียง:QuoteQuote famousQuote = new Quote()

การกำหนดประเภทความสัมพันธ์

JPA มีคำอธิบายประกอบสำหรับประเภทการแมปความสัมพันธ์แต่ละประเภท รายการ 7 แสดงให้เห็นว่าคุณสามารถใส่คำอธิบายประกอบความสัมพันธ์แบบหนึ่งต่อกลุ่มระหว่างMusicianและPerformances ได้อย่างไร

รายการ 7. การอธิบายความสัมพันธ์แบบหนึ่งต่อกลุ่ม