שימוש בפרמטרים של שאילתת JPA

1. הקדמה

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

אחד הדברים האלה הוא פרמטרים של שאילתת JPA, ועל זה אנחנו הולכים לדבר.

2. מהם פרמטרים של שאילתות?

נתחיל בהסבר מהם פרמטרי השאילתה.

פרמטרים של שאילתות הם דרך לבנות ולבצע שאילתות עם פרמטרים. אז במקום:

בחר * מעובדים e WHERE e.emp_number = '123';

היינו עושים:

בחר * מעובדים e WHERE e.emp_number =?;

על ידי שימוש בהצהרה מוכנה של JDBC, עלינו להגדיר את הפרמטר לפני ביצוע השאילתה:

pStatement.setString (1, 123);

3. מדוע עלינו להשתמש בפרמטרים של שאילתות?

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

בואו נכתוב מחדש את השאילתה הקודמת בכדי להשיג עובדים emp_number באמצעות JPA API, אך במקום להשתמש בפרמטר נשתמש במילולית כדי שנוכל להמחיש בבירור את המצב:

מחרוזת empNumber = "A123"; TypedQuery שאילתה = em.createQuery ("בחר E מתוך עובד e WHERE e.empNumber = '" + empNumber + "'", שכיר עובד); עובד שכיר = query.getSingleResult ();

לגישה זו יש כמה חסרונות:

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

4. פרמטרים של שאילתת JPA

בדומה לפרמטרי הצהרה מוכנים של JDBC, JPA מציין שתי דרכים שונות לכתוב שאילתות עם פרמטרים באמצעות:

  • פרמטרים מיקוםיים
  • פרמטרים בשם

אנו עשויים להשתמש בפרמטרים של מיקום או עם שם, אך אסור לנו לערבב אותם בתוך אותה שאילתה.

4.1. פרמטרים מיקום

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

בואו נראה איך נכתוב שאילתה כזו בעזרת פרמטרים מיקוםיים:

שאילתת TypedQuery = em.createQuery ("בחר E מתוך עובד e WHERE e.empNumber =? 1", שכיר עובד); מחרוזת empNumber = "A123"; עובד שכיר = query.setParameter (1, empNumber) .getSingleResult ();

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

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

מספור פרמטרים הוא תכונה שימושית מאוד מכיוון שהוא משפר את השימושיות, את הקריאה ואת התחזוקה.

ראוי להזכיר זאת קשירת פרמטר מיקום נתמכת גם על ידי שאילתות SQL מקוריות.

4.2. פרמטרים מיקוםיים המוערכים באוסף

כאמור, אנו עשויים להשתמש גם בפרמטרים המוערכים באוסף:

שאילתת TypedQuery = entityManager.createQuery ("בחר e מבין עובד e WHERE e.empNumber IN (? 1)", שכיר עובד); רשימת empNumbers = Arrays.asList ("A123", "A124"); רשימת עובדים = query.setParameter (1, empNumbers) .getResultList ();

4.3. פרמטרים בשם

פרמטרים בשם דומים למדי לפרמטרים מיקוםיים; עם זאת, באמצעותם אנו הופכים את הפרמטרים למפורשים יותר והשאילתה הופכת לקריאה יותר:

TypedQuery query = em.createQuery ("בחר e מ- עובד e WHERE e.empNumber =: number", Employee.class); מחרוזת empNumber = "A123"; עובד שכיר = query.setParameter ("מספר", empNumber) .getSingleResult ();

שאילתת הדוגמה הקודמת זהה לזו הראשונה אך השתמשנו בה :מספר, פרמטר בשם, במקום ?1.

אנו יכולים לראות שהכרזנו על הפרמטר עם נקודתיים ולאחריו מזהה מחרוזת (מזהה JPQL) שהוא מציין מיקום עבור הערך בפועל שיוגדר בזמן הריצה. לפני ביצוע השאילתה, יש להגדיר את הפרמטר או הפרמטרים על ידי הנפקת ה- setParameter שיטה.

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

בואו ונפתח וריאציה של השאילתה הקודמת באמצעות שני פרמטרים בשם כדי להמחיש את שרשור השיטות:

שאילתת TypedQuery = em.createQuery ("בחר E מתוך עובד e WHERE e.name =: name AND e.age =: empAge", Employee.class); מחרוזת empName = "ג'ון דו"; int empAge = 55; רשימת עובדים = שאילתה .setParameter ("שם", empName) .setParameter ("empAge", empAge) .getResultList ();

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

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

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

4.4. פרמטרים בעלי ערך אוסף

לשם הבהרה, בואו נדגים כיצד זה עובד עם פרמטרים המוערכים באוסף:

שאילתת TypedQuery = entityManager.createQuery ("בחר e מעובד e WHERE e.empNumber IN (: numbers)", שכיר עובד); רשימת empNumbers = Arrays.asList ("A123", "A124"); רשימת עובדים = query.setParameter ("numbers", empNumbers) .getResultList ();

כפי שאנו רואים, זה עובד בצורה דומה לפרמטרים מיקוםיים.

5. פרמטרים של שאילתת קריטריונים

ניתן לבנות שאילתת JPA באמצעות ה- JPA Criteria API, אשר התיעוד הרשמי של Hibernate מסביר בפירוט רב.

בסוג זה של שאילתות, אנו מייצגים פרמטרים על ידי שימוש באובייקטים במקום בשמות או במדדים.

בואו נבנה את אותה שאילתה שוב, אך הפעם נשתמש ב- Criteria API כדי להדגים כיצד לטפל בפרמטרים של שאילתות בעת התמודדות CriteriaQuery:

CriteriaBuilder cb = em.getCriteriaBuilder (); CriteriaQuery cQuery = cb.createQuery (שכיר עובד); שורש c = cQuery.from (שכיר עובד); ParameterExpression paramEmpNumber = cb.parameter (String.class); cQuery.select (c) .where (cb.equal (c.get (Employee_.empNumber), paramEmpNumber)); שאילתת TypedQuery = em.createQuery (cQuery); מחרוזת empNumber = "A123"; query.setParameter (paramEmpNumber, empNumber); עובד שכיר = query.getResultList ();

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

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

6. מסקנה

במאמר זה התמקדנו במכניקה של שאילתות בנייה באמצעות פרמטרי שאילתת JPA או פרמטרי קלט.

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

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

קוד המקור של הדרכה זו, כרגיל, זמין ב- GitHub.