3 בעיות נפוצות בביצועי שינה והדרך למצוא אותם בקובץ היומן שלך

1. הקדמה

בוודאי קראת חלק מהתלונות על ביצועים גרועים של מצב שינה או שאולי נאבקת בכמה מהן בעצמך. אני משתמש במצב שינה כבר יותר מ -15 שנה ונתקלתי ביותר מהבעיות האלה.

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

2. מצא ותקן בעיות ביצועים

2.1. רישום הצהרות SQL בייצור

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

כתיבת כמה הצהרות יומן לא נשמעת עניין גדול, ויש הרבה יישומים שעושים בדיוק את זה. אבל זה מאוד לא יעיל, במיוחד באמצעות System.out.println כפי שעושה זאת מצב שינה אם אתה מגדיר את show_sql בפרמטר בתרדמת שינה ל נָכוֹן:

מצב שינה: בחר order0_.id כ- id1_2_, order0_.orderNumber כמו orderNum2_2_, order0_.version כגרסה 3_2_ מהרכישה סדר הזמנה0_ שינה: בחר פריטים0_.order_id כ- order_id4_0_0_, פריטים0_id כמו id1_0_0_, פריטים0_id, id_0_id, id_0 פריטים0_.product_id כמוצר_5_0_1_, פריטים0_.כמות כמות2_0_1_, פריטים0_.הפוך כגרסה 3_0_1_ מתוך פריטים של OrderItem0_ איפה פריטים0_.order_id =? מצב שינה: בחר פריטים0_.order_id כ- order_id4_0_0_, items0_.id כ- id1_0_0_, items0_id כ id1_0_1_, items0_.order_id כ- order_id4_0_1_, פריטים0_.product_id כמוצר_5_0_1_, פריטים0_.כמות כמספר_0___. order_id =? מצב שינה: בחר פריטים order_id =?

באחד הפרויקטים שלי שיפרתי את הביצועים ב -20% תוך מספר דקות על ידי הגדרה show_sql ל שֶׁקֶר. זה סוג ההישגים שאתה אוהב לדווח עליו בפגישת הסטנד-אפ הבאה 🙂

זה די ברור איך אתה יכול לתקן את בעיית הביצועים הזו. פשוט פתח את התצורה שלך (למשל קובץ persistence.xml) והגדר את show_sql פרמטר ל שֶׁקֶר. אינך זקוק למידע זה בייצור בכל מקרה.

אבל אולי תזדקק להם במהלך הפיתוח. אם לא, אתה משתמש בשתי תצורות שינה שונות (שלא כדאי לך) השבתת גם את רישום הצהרות SQL שם. הפיתרון לכך הוא להשתמש בשתי תצורות יומן שונות לפיתוח וייצור המותאמות לדרישות הספציפיות של סביבת זמן הריצה.

תצורת פיתוח

תצורת הפיתוח אמורה לספק כמה שיותר מידע שימושי כדי שתוכלו לראות כיצד מצב שינה במצב אינטראקציה עם מסד הנתונים. לכן עליכם לפחות לרשום את הצהרות ה- SQL שנוצרו בתצורת הפיתוח שלכם. אתה יכול לעשות זאת על ידי הפעלה לנפות הודעה עבור org.hibernate.SQL קטגוריה. אם אתה רוצה לראות גם את הערכים של פרמטרי הקישור שלך, עליך להגדיר את רמת היומן של org.hibernate.type.descriptor.sql ל זֵכֶר:

log4j.appender.stdout = org.apache.log4j.ConsoleAppender log4j.appender.stdout.Target = System.out log4j.appender.stdout.layout = org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern =% d {HH: mm: ss, SSS}% -5p [% c] -% m% n log4j.rootLogger = מידע, stdout # רמת יומן בסיסית לכל ההודעות log4j.logger.org.hibernate = מידע # משפטים ופרמטרים SQL log4j.logger.org.hibernate.SQL = ניפוי באגים log4j.logger.org.hibernate.type.descriptor.sql = עקוב

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

23: 03: 22,246 DEBUG SQL: 92 - בחר order0_.id כ id1_2_, order0_.orderNumber כ orderNum2_2_, order0_.version כגרסה 3_2_ מהרכישה הזמנת order0_ כאשר order0_.id = 1 23: 03: 22,254 TRACE BasicExtractor: 61 - ערך חילוץ ( [id1_2_]: [BIGINT]) - [1] 23: 03: 22,261 TRACE BasicExtractor: 61 - ערך חילוץ ([orderNum2_2_]: [VARCHAR]) - [order1] 23: 03: 22,263 TRACE BasicExtractor: 61 - ערך חילוץ ( [version3_2_]: [INTEGER]) - [0]

Hibernate מספק לך מידע רב יותר פנימי על א מוֹשָׁב אם אתה מפעיל את הסטטיסטיקה של מצב שינה. אתה יכול לעשות זאת על ידי הגדרת מאפיין המערכת hibernate.generate_statistics לאמיתי.

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

תוכל לראות כמה דוגמאות לסטטיסטיקה בקטע הקוד הבא:

23: 04: 12,123 INFO StatisticalLoggingSessionEventListener: 258 - מדדי מושב {23793 שני ננו שניות הושקעו ברכישת חיבורי JDBC 1; 0 ננו שניות שהוצאו בשחרור 0 חיבורי JDBC; 394686 שננו שניות השקיעו בהכנת 4 הצהרות JDBC; 2528603 ננו שניות השקיעו בביצוע 4 הצהרות JDBC; 0 ננו שניות שהוצאו לביצוע 0 קבוצות JDBC; 0 ננו שניות שהוצאו לביצוע 0 מכני L2C; 0 ננו שניות שהוצאו לביצוע 0 להיטים L2C; 0 ננו שניות שהוצאו לביצוע 0 החמצות L2C; 9700599 שננו שניות השקיעו בביצוע 1 שטיפות (שטיפה בסך הכל 9 ישויות ו -3 אוספים); 42921 שננו שניות השקיעו בביצוע שטיפות חלקיות אחת (שטיפה בסך הכל 0 ישויות ו -0 אוספים)}

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

שורות 2 עד 5 מראות לך כמה חיבורי JDBC והצהרות השתמשה ב- Hibernate במהלך הפגישה הזו וכמה זמן היא השקיעה עליה. אתה צריך תמיד להסתכל על הערכים האלה ולהשוות אותם עם הציפיות שלך.

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

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

תצורת ייצור

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

אם אתה משתמש ב- Log4j, תוכל להשיג זאת בתצורה הבאה:

log4j.appender.stdout = org.apache.log4j.ConsoleAppender log4j.appender.stdout.Target = System.out log4j.appender.stdout.layout = org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern =% d {HH: mm: ss, SSS}% -5p [% c] -% m% n log4j.rootLogger = מידע, stdout # רמת יומן בסיסית לכל ההודעות log4j.logger.org.hibernate = שגיאה

2.2. N + 1 בחר נושא

כפי שכבר הסברתי, נושא הבחירה n + 1 הוא בעיית הביצועים הנפוצה ביותר. הרבה מפתחים מאשימים את הרעיון של OR-Mapping בנושא זה, והם לא טועים לחלוטין. אבל אתה יכול להימנע מכך בקלות אם אתה מבין כיצד שינה מתייחס למערכות יחסים עצלות. לפיכך, היזם אשם גם מכיוון שאחריותו להימנע מבעיות מסוג זה. אז תן לי להסביר קודם מדוע נושא זה קיים ואז להראות לך דרך קלה למנוע זאת. אם אתה כבר מכיר את הבעיות הנבחרות n + 1, אתה יכול לקפוץ ישירות לפיתרון.

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

@Entity @Table (name = "purchaseOrder") מחלקה ציבורית הזמנת יישומים ניתנת לסידור {@OneToMany (mappedBy = "order", fetch = FetchType.LAZY) פריטי קבוצה פרטיים = HashSet חדש (); ...}

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

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

רשימת הזמנות = em.createQuery ("בחר O מתוך הזמנה o"). GetResultList (); עבור (הזמנת הזמנה: הזמנות) {log.info ("הזמנה:" + order.getOrderNumber ()); log.info ("מספר הפריטים:" + order.getItems (). size ()); }

סביר להניח שלא הייתם מצפים שמספר שורות קוד אלה יכולות ליצור מאות ואף אלפי שאילתות בסיס נתונים. אבל זה קורה אם אתה משתמש FetchType.LAZY למערכת היחסים עם הזמן פריט יֵשׁוּת:

22: 47: 30,065 DEBUG SQL: 92 - בחר order0_.id כ id1_2_, order0_.orderNumber כ orderNum2_2_, order0_.version כגרסה 3_2_ מהרכישה הזמנת order0_ 22: 47: 30,136 INFO NamedEntityGraphTest: 58 - סדר: order1 22: 47: 30,140 DEBUG SQL: 92 - בחר פריטים0_.order_id כ- order_id4_0_0_, items0_.id כ- id1_0_0_, items0_id כ id1_0_1_, items0_.order_id כ- order_id4_0_1_, items0_.product_id כמוצר_5_0_1_, פריטים0_.כמות כמות_פריטים_0___1 items0_.order_id =? 22: 47: 30,171 INFO NamedEntityGraphTest: 59 - מספר הפריטים: 2 22: 47: 30,171 INFO NamedEntityGraphTest: 58 - סדר: סדר2 22: 47: 30,172 DEBUG SQL: 92 - בחר פריטים0_.order_id כסדר_יד 4_0_0_, פריטים0_.id כ id__ , items0_.id כמו id1_0_1_, items0_.order_id כמו order_id4_0_1_, items0_.product_id כמוצר_5_0_1_, פריטים0_.כמות כמות2_0_1_, items0_.version כגרסה 3_0_1_ מתוך פריטי Order0_ איפה פריטים0_.order_id =? 22: 47: 30,174 INFO NamedEntityGraphTest: 59 - מספר הפריטים: 2 22: 47: 30,174 INFO NamedEntityGraphTest: 58 - סדר: order3 22: 47: 30,174 DEBUG SQL: 92 - בחר פריטים0_.order_id כסדר_יד 4_0_0_, פריטים0_.id כ id1_ , items0_.id בתור id1_0_1_, items0_.order_id כ order_id4_0_1_, items0_.product_id כמוצר_5_0_1_, items0_. כמות כמות2_0_1_, items0_.version כגרסה 3_0_1_ מתוך פריטי OrderItem0_ איפה פריטים0_.order_id =? 22: 47: 30,176 INFO NamedEntityGraphTest: 59 - מספר הפריטים: 2

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

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

אמרתי קודם שאתה יכול בקלות להימנע מבעיות אלה. וזה נכון. אתה רק צריך לאתחל את מערכת היחסים עם OrderItem כאשר אתה בוחר את ה- להזמין ישויות ממאגר המידע.

אבל בבקשה, עשה זאת רק אם אתה משתמש בקשר בקוד העסקי שלך ולא משתמש FetchType.EAGER להביא תמיד את הישויות הקשורות. זה רק מחליף את נושא ה- n + 1 שלך בבעיית ביצועים אחרת.

ראשית קשר עם א @NamedEntityGraph

ישנן מספר אפשרויות שונות לאתחל מערכות יחסים. אני מעדיף להשתמש ב- @NamedEntityGraph שהיא אחת התכונות המועדפות עלי שהוצגה ב- JPA 2.1. הוא מספק דרך עצמאית לשאילתה לציין גרף של ישויות ש- Hibernate יביא ממסד הנתונים. בקטע הקוד הבא תוכלו לראות דוגמא לגרף פשוט המאפשר למצב שינה להביא בשקיקה את מאפיין הפריטים של ישות:

@Entity @Table (name = "purchase_order") @NameEntityGraph (name = "graph.Order.items", attributeNodes = @NamedAttributeNode ("פריטים")) מחלקה ציבורית סדר יישומי ניתן להתבצע באמצעות סדר ...

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

עכשיו אתה יכול להשתמש בגרף הישות כדי לשלוט בהתנהגות האחזור או בשאילתה ספציפית. עליכם, אם כן, ליצור אינסטינציה EntityGraph מבוסס על ה @NamedEntityGraph להגדיר ולספק אותה כרמז ל- EntityManager.find () השיטה או השאילתה שלך. אני עושה זאת בקטע הקוד הבא שבו אני בוחר את להזמין ישות עם מזהה 1 ממסד הנתונים:

גרף EntityGraph = this.em.getEntityGraph ("גרף.סדר.פריטים"); רמזים למפות = HashMap חדש (); hints.put ("גרף javax.persistence.fetchgraph"); להחזיר this.em.find (סדר.קלאס, 1 ליטר, רמזים);

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

17: 34: 51,310 DEBUG [org.hibernate.loader.plan.build.spi.LoadPlanTreePrinter] (pool-2-thread-1) LoadPlan (entity = blog. Thoughts.on.java.jpa21.entity.graph.model. סדר) - מחזיר - EntityReturnImpl (ישות = blog.thoughts.on.java.jpa21.entity.graph.model.Order, querySpaceUid =, path = blog. Thoughts.on.java.jpa21.entity.graph.model.Order) - CollectionAttributeFetchImpl (collection = blog.thoughts.on.java.jpa21.entity.graph.model.Order.items, querySpaceUid =, path = blog.thoughts.on.java.jpa21.entity.graph.model.Order.items) - (אלמנט אוסף) CollectionFetchableElementEntityGraph (ישות = blog.thoughts.on.java.jpa21.entity.graph.model.OrderItem, querySpaceUid =, path = blog. Thoughts.on.java.jpa21.entity.graph.model.Order. פריטים.) - EntityAttributeFetchImpl (entity = blog.thoughts.on.java.jpa21.entity.graph.model.Product, querySpaceUid =, path = blog.thoughts.on.java.jpa21.entity.graph.model.Order.items ..product) - QuerySpaces - EntityQuerySpaceImpl (uid =, entity = blog.thoughts.on.java.jpa21.entity.graph.model .הזמנה) - מיפוי כינוי בטבלת SQL - order0_ - סיומת כינוי - 0_ - עמודות מפתח בסיומת - {id1_2_0_} - JOIN (JoinDefinedByMetadata (פריטים)): -> - CollectionQuerySpaceImpl (uid =, collection = blog.thoughts.on.java. jpa21.entity.graph.model.Order.items) - מיפוי כינוי של טבלת SQL - פריטים 1_ - סיומת כינוי - 1_ - עמודות מפתח בסיומת - {order_id4_2_1_} - סיומת כינוי אלמנט-ישות - 2_ - 2_entity- רכיב עמודות מפתח בסיומת - id1_0_2_ - הצטרף (JoinDefinedByMetadata (אלמנטים)): -> - EntityQuerySpaceImpl (uid =, entity = blog. Thoughts.on.java.jpa21.entity.graph.model.OrderItem) - מיפוי כינוי בטבלת SQL - פריטים 1_ - סיומת כינוי - 2_ - סיומת עמודות מפתח - {id1_0_2_} - JOIN (JoinDefinedByMetadata (product)): -> - EntityQuerySpaceImpl (uid =, entity = blog.thoughts.on.java.jpa21.entity.graph.model.Product) - מיפוי כינוי בטבלת SQL - product2_ - סיומת כינוי - 3_ - עמודות מפתח בסיומת - {id1_1_3_} 17: 34: 51,311 DEBUG [org.hibernate.loader.entity.plan.EntityLoader] (בריכה-2-שרשור -1) בחר סטטי f או blog.thoughts.on.java.jpa21.entity.graph.model. Order [NONE: -1]: בחר order0_.id כ- id1_2_0_, order0_.orderNumber כ- orderNum2_2_0_, order0_.version כגרסה 3_2_0_, items1_.order_id כ- order_id4_2_1_ , items1_.id כמו id1_0_1_, items1_.id כמו id1_0_2_, items1_.order_id כמו order_id4_0_2_, items1_.product_id כמוצר_5_0_2_, items1_.quantity כמו כמות2_0_2_, items1_.version כמו גרסה3_0_2_, product2_.id כ- product2_3, שם מוצר_3. .version כגרסה3_1_3_ מהזמנת רכש_הזמנה0_ הצטרפות חיצונית שמאלית OrderItem פריטים1_ בהזמנה0_id = פריטים1_.הזמנה_יד הצטרף החיצוני השמאלי מוצר מוצר2_ במוצרים1_.product_id = product2_.id איפה order0_.id =?

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

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

@Entity @Table (name = "order_order") @NamedEntityGraph (name = "graph.Order.items", attributeNodes = @NamedAttributeNode (value = "items", subgraph = "items"), subgraphs = @NamedSubgraph (name = " פריטים ", attributeNodes = @NamedAttributeNode (" מוצר "))) מחלקה ציבורית מימדי הזמנת סדר {...}

כפי שאתה יכול לראות, ההגדרה של @NamedSubGraph דומה מאוד להגדרת תשחץ @NamedEntityGraph. לאחר מכן תוכל להתייחס לתצלום זה ב @NamedAttributeNode ביאור להגדרת התנהגות האחזור למאפיין ספציפי זה.

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

2.3. עדכן ישויות אחת אחת

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

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

22: 58: 05,829 DEBUG SQL: 92 - בחר product0_.id כ- id1_1_, product0_.name כשם2_1_, product0_.מחיר price3_1_, product0_.version כגרסה 4_1_ ממוצר מוצר0_ 22: 58: 05,883 DEBUG SQL: 92 - עדכון סט מוצרים שם = ?, מחיר = ?, גרסה =? איפה id =? וגרסה =? 22: 58: 05,889 DEBUG SQL: 92 - עדכן שם קבוצת המוצרים = ?, price = ?, version =? איפה id =? וגרסה =? 22: 58: 05,891 DEBUG SQL: 92 - עדכון שם קבוצת המוצרים = ?, price = ?, version =? איפה id =? וגרסה =? 22: 58: 05,893 DEBUG SQL: 92 - עדכון שם קבוצת המוצרים = ?, price = ?, version =? איפה id =? וגרסה =? 22: 58: 05,900 DEBUG SQL: 92 - עדכון שם קבוצת המוצרים = ?, price = ?, version =? איפה id =? וגרסה =?

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

אתה יכול לעשות את אותו הדבר עם מצב שינה אם אתה משתמש ב- JPQL, SQL מקורי או ממשק ה- API של CriteriaUpdate. כולם 3 דומים מאוד, אז בואו נשתמש ב- JPQL בדוגמה זו.

אתה יכול להגדיר משפט JPQL UPDATE בצורה דומה כמו שאתה מכיר אותו מ- SQL. אתה פשוט מגדיר איזו ישות ברצונך לעדכן, כיצד לשנות את ערכי התכונות שלה ולהגביל את הישויות המושפעות בהצהרת WHERE.

תוכל לראות דוגמה לכך בקטע הקוד הבא, בו אני מעלה את מחיר כל המוצרים ב -10%:

em.createQuery ("UPDATE מוצר p SET p.price = p.price * 0.1"). executeUpdate ();

Hibernate יוצר משפט SQL UPDATE המבוסס על הצהרת JPQL ושולח אותו למסד הנתונים שמבצע את פעולת העדכון.

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

3. סיכום

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

2 מהן נגרמו על ידי מספר עצום של הצהרות SQL. זו סיבה נפוצה לבעיות ביצועים אם אתה עובד עם מצב שינה. מצב שינה מסתיר את הגישה למסד הנתונים שמאחורי ה- API שלו וזה מקשה לרוב לנחש את מספר הצהרות ה- SQL בפועל. לכן עליך לבדוק תמיד את הצהרות ה- SQL שבוצעו כאשר אתה מבצע שינוי בדרגת ההתמדה שלך.


$config[zx-auto] not found$config[zx-overlay] not found