מה זה JPA? מבוא ל- Java Persistence API

כמפרט, ה- Java Persistence API עוסק בהתמדה , שמשמעותה באופן רופף כל מנגנון שבאמצעותו Java אובייקטים מתארכים בתהליך היישום שיצר אותם. לא כל אובייקטים של Java צריכים להיות קבועים, אך רוב היישומים נמשכים אובייקטים עסקיים מרכזיים. מפרט ה- JPA מאפשר לך להגדיר אילו אובייקטים צריכים להתמיד, וכיצד יש להחזיק אובייקטים אלה ביישומי Java שלך.

כשלעצמו, JPA אינו כלי או מסגרת; במקום זאת, הוא מגדיר מערך מושגים שניתן ליישם בכל כלי או מסגרת. בעוד שמודל מיפוי האובייקטים (ORM) של JPA התבסס במקור על מצב שינה, הוא התפתח מאז. כמו כן, בעוד ש- JPA נועדה במקור לשימוש עם מסדי נתונים יחסיים / SQL, כמה יישומי JPA הורחבו לשימוש עם מאגרי נתונים NoSQL. מסגרת פופולרית התומכת ב- JPA עם NoSQL היא EclipseLink, יישום ההפניה ל- JPA 2.2.

JPA 2.2 בג'קרטה EE

ה- API של התמדה של Java שוחרר לראשונה כתת-קבוצה של מפרט EJB 3.0 (JSR 220) ב- Java EE 5. מאז התפתח כמפרט משלו, החל עם שחרורו של JPA 2.0 ב- Java EE 6 (JSR 317). נכון לכתיבת שורות אלה, JPA 2.2 אומץ להמשך כחלק מג'קרטה EE.

JPA ו- Hibernate

בגלל ההיסטוריה השזורה ביניהם, מצב שינה ו- JPA מרוכזים לעתים קרובות. עם זאת, בדומה למפרט Java Servlet, JPA הולידה כלים ומסגרות תואמים רבים; מצב שינה הוא רק אחד מהם.

פותח על ידי Gavin King ושוחרר בתחילת 2002, Hibernate היא ספריית ORM עבור Java. קינג פיתח את שנת שינה כאלטרנטיבה לפולי ישות להתמדה. המסגרת הייתה כה פופולרית, והייתה כה נחוצה באותה תקופה, שרבים מרעיונותיה אומצו וקודדו במפרט ה- JPA הראשון.

כיום, ORM Hibernate הוא אחד מהיישומי ה- JPA הבוגרים ביותר, ועדיין אפשרות פופולרית עבור ORM בג'אווה. תרדמת ORM 5.3.8 (הגרסה הנוכחית נכון לכתיבת שורות אלה) מיישמת את JPA 2.2. בנוסף, משפחת הכלים של Hibernate התרחבה וכללה כלים פופולאריים כמו חיפוש שינה, תקן אימות ו- OGM, אשר תומך בהתמדה של מודל תחום עבור NoSQL.

JPA ו- EJB

כפי שצוין קודם לכן, JPA הוצגה כקבוצת משנה של EJB 3.0, אך מאז התפתחה כמפרט משלה. EJB הוא מפרט עם התמקדות שונה מ- JPA, ומיושם במיכל EJB. כל מיכל EJB כולל שכבת התמדה, המוגדרת על ידי מפרט JPA.

מה זה Java ORM?

הם אמנם שונים זה מזה בביצוע, אך כל יישום JPA מספק שכבת ORM כלשהי. על מנת להבין כלים תואמי JPA ו- JPA, עליך להבין היטב על ORM.

מיפוי יחסי אובייקט הוא משימה - למפתחים יש סיבה טובה להימנע מביצוע ידני. מסגרת כמו ORM ב- Hibernate או EclipseLink מקודדת את המשימה לספריה או למסגרת, שכבת ORM . כחלק מארכיטקטורת היישומים, שכבת ה- ORM אחראית על ניהול ההמרה של אובייקטי תוכנה לאינטראקציה עם הטבלאות והעמודות במסד נתונים יחסי. ב- Java, שכבת ה- ORM ממירה שיעורי ואובייקטים של Java, כך שאפשר לאחסן ולנהל אותם במסד נתונים יחסי.

כברירת מחדל, שם האובייקט המתמשך הופך לשם הטבלה והשדות הופכים לעמודות. לאחר הגדרת הטבלה, כל שורת טבלה מתאימה לאובייקט ביישום. ניתן להגדיר מיפוי אובייקטים, אך ברירות המחדל נוטות לעבוד היטב.

JPA עם NoSQL

עד לא מזמן, מאגרי מידע לא-קשורים היו קוריוזים נדירים. תנועת ה- NoSQL שינתה את כל זה, וכעת מגוון מאגרי מידע של NoSQL זמינים למפתחי Java. כמה יישומי JPA התפתחו לאמץ NoSQL, כולל OGM Hibernate ו- EclipseLink.

איור 1 ממחיש את התפקיד של JPA ושכבת ORM בפיתוח אפליקציות.

JavaWorld /

קביעת תצורה של שכבת Java ORM

כאשר אתה מגדיר פרויקט חדש לשימוש ב- JPA, יהיה עליך להגדיר את חנות הנתונים ואת ספק ה- JPA. תגדיר מחבר מאגר נתונים כדי להתחבר למסד הנתונים שבחרת (SQL או NoSQL). תוכלו גם לכלול ולהגדיר את ספק JPA , המהווה מסגרת כמו Hibernate או EclipseLink. אמנם אתה יכול להגדיר את JPA באופן ידני, אך מפתחים רבים בוחרים להשתמש בתמיכה של Spring מהקופסה. ראה " התקנה והתקנה של JPA " להלן כדי להדגים התקנה והתקנה ידנית של JPA הן על ידי אביב.

אובייקטים נתונים של Java

אובייקטים של ג'אווה נתונים היא מסגרת התמדה סטנדרטית השונה מ- JPA בעיקר על ידי תמיכה בלוגיקת ההתמדה באובייקט, ועל ידי התמיכה הוותיקה שלה בעבודה עם מאגרי נתונים שאינם יחסיים. JPA ו- JDO דומים מספיק כדי שספקי JDO תומכים לעתים קרובות גם ב- JPA. עיין בפרויקט Apache JDO למידע נוסף על JDO ביחס לתקני התמדה אחרים כמו JPA ו- JDBC.

התמדה של נתונים בג'אווה

מנקודת מבט תכנותית, שכבת ה- ORM היא שכבת מתאם : היא מתאימה את שפת גרפי האובייקטים לשפה של SQL וטבלאות יחס. שכבת ה- ORM מאפשרת למפתחים מונחי עצמים לבנות תוכנה המתמשכת בנתונים מבלי לעזוב את הפרדיגמה מונחית האובייקטים.

כאשר אתה משתמש ב- JPA, אתה יוצר מפה מאחסון הנתונים לאובייקטים של מודל הנתונים של היישום שלך. במקום להגדיר כיצד נשמרים ואוחזרים אובייקטים, אתה מגדיר את המיפוי בין אובייקטים למסד הנתונים שלך, ואז קורא ל- JPA כדי להתמיד בהם. אם אתה משתמש במסד נתונים יחסי, חלק ניכר מהחיבור האמיתי בין קוד היישום שלך למסד הנתונים יטופל על ידי JDBC, ממשק ה- API של קישוריות Java Database.

כמפרט, JPA מספק הערות מטא-נתונים , בהן אתה מגדיר את המיפוי בין אובייקטים למסד הנתונים. כל יישום JPA מספק מנוע משלו להערות JPA. מפרט ה- JPA מספק גם את PersistanceManagerאו EntityManager, שהן נקודות המפתח העיקריות למערכת JPA (בה קוד הלוגיקה העסקית שלך אומר למערכת מה לעשות עם האובייקטים הממופים).

כדי להפוך את כל זה לקונקרטי יותר, שקול את Listing 1, שהוא כיתת נתונים פשוטה לדוגמנות מוזיקאי.

רישום 1. מחלקת נתונים פשוטה בג'אווה

 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בכיתה ב Listing 1 משמשת לנתונים לעצור. הוא יכול להכיל נתונים פרימיטיביים כגון שדה השם . זה יכול גם לקיים יחסים למעמדות אחרים כגון mainInstrumentו performances.

Musicianים" טעם קיומנו הוא להכיל נתונים. סוג זה של מחלקות מכונה לעיתים אובייקט DTO, או אובייקט העברת נתונים . DTOs הם תכונה נפוצה של פיתוח תוכנה. הם אמנם מחזיקים סוגים רבים של נתונים, אך הם אינם מכילים שום היגיון עסקי. התמידות באובייקטים של נתונים היא אתגר בכל מקום בפיתוח תוכנה.

התמדה של נתונים עם 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 

The code in Listing 2 is fairly self-documenting. The georgeHarrison object could come from anywhere (front-end submit, external service, etc.), and has its ID and name fields set. The fields on the object are then used to supply the values of an SQL insert statement. (The PreparedStatement class is part of JDBC, offering a way to safely apply values to an SQL query.)

While JDBC allows the control that comes with manual configuration, it is cumbersome compared to JPA. In order to modify the database, you first need to create an SQL query that maps from your Java object to the tables in a relational database. You then have to modify the SQL whenever an object signature change. With JDBC, maintaining the SQL becomes a task in itself.

Data persistence with JPA

Now consider Listing 3, where we persist the Musician class using 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אולי יש קשר אחד-לאחד עם Quoteישות, המשמש לייצוג ציטוט מפורסם: Quote famousQuote = new Quote().

הגדרת סוגי מערכות יחסים

ל- JPA יש הערות לכל אחד מסוגי מיפוי היחסים שלה. Listing 7 מציג את אופן ויסמן את אחד-לרבי היחסים בין Musicianלבין Performanceהים.

רישום 7. ביאור ליחסים של אחד לרבים