חריג למצב שינה: אין מושב שינה שמתחבר לשרשור בתרדמת שינה 3

עליון התמדה

רק הכרזתי על החדש למד אביב קורס, המתמקד ביסודות האביב 5 ומגף האביב 2:

>> בדוק את הקורס

1. הקדמה

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

אנו נתמקד כאן בשני תרחישים שונים:

  1. משתמש ב LocalSessionFactoryBean
  2. משתמש ב AnnotationSessionFactoryBean

2. הסיבה

עם גרסה 3, ה- Hibernate הציג את הרעיון של ההפעלה ההקשרית וה- getCurrentSession () השיטה נוספה ל SessionFactory מעמד. מידע נוסף על הפגישה בהקשר ניתן למצוא כאן.

לאביב יש יישום משלה של org.hibernate.context.CurrentSessionContext ממשק - org.springframework.orm.hibernate3.SpringSessionContext (במקרה של Spring Hibernate 3). יישום זה מחייב את ההפעלה להיות קשורה לעסקה.

מטבע הדברים שיעורים שמתקשרים getCurrentSession () יש להוסיף הערה לשיטה @ Transactional או ברמת הכיתה או ברמת השיטה. אם לא, org.hibernate.HibernateException: אין מושב שינה שינה קשור בחוט ייזרק.

בואו נסתכל במהירות על דוגמא.

3. LocalFactorySessionBean

הוא התרחיש הראשון שנבחן במאמר זה.

נגדיר שיעור תצורה של Java Spring עם LocalSessionFactoryBean:

@Configuration @EnableTransactionManagement @PropertySource ({"classpath: persistence-h2.properties"}) @ComponentScan ({"com.baeldung.persistence.dao", "com.baeldung.persistence.service"}) מעמד ציבורי PersistenceConfigHibernate3 {// ... @ שעועית ציבורית LocalSessionFactoryBean sessionFactory () {LocalSessionFactoryBean sessionFactory = LocalSessionFactoryBean חדש (); תצורת משאבים = ClassPathResource חדש ("exceptionDemo.cfg.xml"); sessionFactory.setDataSource (dataSource ()); sessionFactory.setConfigLocation (config); sessionFactory.setHibernateProperties (hibernateProperties ()); מפגש חזרה מפעל; } // ...}

שים לב שאנחנו משתמשים בקובץ תצורה של מצב שינה (exceptionDemo.cfg.xml) כאן על מנת למפות את מחלקת הדוגמניות. זה בגלל ש ה org.springframework.orm.hibernate3.LocalSessionFactoryBean אינו מספק את הנכס חבילות ToScan, למיפוי שיעורי מודלים.

הנה השירות הפשוט שלנו:

@Service @Transactional class public EventService {@ IEventDao dao פרטי; בטל ציבורי ליצור (ישות אירוע) {dao.create (ישות); }}
@Entity @Table (name = "EVENTS") מעמד ציבורי אירועים מיישמים ניתן לסידור {@Id @GeneratedValue פרטי מזהה ארוך; תיאור מחרוזת פרטי; // ...}

כפי שניתן לראות בקטע הקוד שלמטה, ה- getCurrentSession () שיטת ה- SessionFactory הכיתה משמשת להשגת מפגש שינה:

שיעור מופשט ציבורי AbstractHibernateDao מיישם IOperations {קלאסי כיתתי פרטי; @ SessionFactory פרטית אוטומטית sessionFactory; // ... @ ביטול חלל ציבורי ליצור (ישות T) {Preconditions.checkNotNull (ישות); getCurrentSession (). persist (ישות); } מושב מוגן getCurrentSession () {return sessionFactory.getCurrentSession (); }}

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

@RunWith (SpringJUnit4ClassRunner.class) @ContextConfiguration (classes = {PersistenceConfigHibernate3.class}, loader = AnnotationConfigContextLoader.class) שירות ציבורי HibernateExceptionScen1MainIntegrationTest {@Autowired EventService; @ כלל ציבורי ExpectedException expectEx = ExpectedException.none (); @ מבחן ציבורי בטל כאשר NoTransBoundToSession_thenException () {expectEx.expectCause (IsInstanceOf.instanceOf (HibernateException.class)); expectEx.expectMessage ("אין מושב תרדמה קשור לשרשור," + "והתצורה אינם מאפשרים ליצור" + "של פעילות לא עסקית כאן"); service.create (אירוע חדש ("מ- LocalSessionFactoryBean")); }}

בדיקה זו מראה כיצד שיטת השירות מבוצעת בהצלחה כאשר ה- שירות אירועים המחזור מסומן עם @ Transactional ביאור:

@RunWith (SpringJUnit4ClassRunner.class) @ContextConfiguration (classes = {PersistenceConfigHibernate3.class}, loader = AnnotationConfigContextLoader.class) שירות ציבורי HibernateExceptionScen1MainIntegrationTest {@Autowired EventService; @ כלל ציבורי ExpectedException expectEx = ExpectedException.none (); @ מבחן ציבורי בטל כאשרEntityIsCreated_thenNoExceptions () {service.create (אירוע חדש ("מ- LocalSessionFactoryBean")); רשימת אירועים = service.findAll (); }}

4. AnnotationSessionFactoryBean

חריג זה יכול להתרחש גם כאשר אנו משתמשים ב- org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean ליצור את SessionFactory ביישום האביב שלנו.

בואו נסתכל על קוד לדוגמא המדגים זאת. במידה זו אנו מגדירים מחלקת תצורה של Java Spring עם AnnotationSessionFactoryBean:

@Configuration @EnableTransactionManagement @PropertySource ({"classpath: persistence-h2.properties"}) @ComponentScan ({"com.baeldung.persistence.dao", "com.baeldung.persistence.service"}) מעמד ציבורי PersistenceConfig {// ... @Bean Public AnnotationSessionFactoryBean sessionFactory () {AnnotationSessionFactoryBean sessionFactory = חדש AnnotationSessionFactoryBean (); sessionFactory.setDataSource (dataSource ()); sessionFactory.setPackagesToScan (מחרוזת חדשה [] {"com.baeldung.persistence.model"}); sessionFactory.setHibernateProperties (hibernateProperties ()); מפגש חזרה מפעל; } // ...}

עם אותה קבוצה של שיעורי DAO, Service ו- Model מהסעיף הקודם, אנו נתקלים בחריג המתואר לעיל:

@RunWith (SpringJUnit4ClassRunner.class) @ContextConfiguration (classes = {PersistenceConfig.class}, loader = AnnotationConfigContextLoader.class) שירות ציבורי בכיתה HibernateExceptionScen2MainIntegrationTest {@Autowired EventService; @ כלל ציבורי ExpectedException expectEx = ExpectedException.none (); @ מבחן ציבורי בטל כאשר NoTransBoundToSession_thenException () {expectEx.expectCause (IsInstanceOf.instanceOf (HibernateException.class)); expectEx.expectMessage ("אין מושב תרדמה קשור לשרשור," + "והתצורה אינם מאפשרים ליצור" + "של פעילות שאינה עסקה כאן"); service.create (אירוע חדש ("מאת AnnotationSessionFactoryBean")); }}

אם אנו מציינים את כיתת השירות עם @ Transactional ביאור, שיטת השירות עובדת כצפוי והבדיקה המוצגת להלן עוברת:

@RunWith (SpringJUnit4ClassRunner.class) @ContextConfiguration (classes = {PersistenceConfig.class}, loader = AnnotationConfigContextLoader.class) שירות ציבורי בכיתה HibernateExceptionScen2MainIntegrationTest {@Autowired EventService; @ כלל ציבורי ExpectedException expectEx = ExpectedException.none (); @ מבחן ציבורי בטל כאשרEntityIsCreated_thenNoExceptions () {service.create (אירוע חדש ("מ- AnnotationSessionFactoryBean")); רשימת אירועים = service.findAll (); }}

5. הפיתרון

ברור כי getCurrentSession () שיטת ה- SessionFactory המתקבל מאביב צריך להתקשר מתוך עסקה פתוחה. לָכֵן, הפתרון הוא להבטיח ש- DAO / שיטות השירות / המחלקות שלנו יאושרו כהלכה עם ה- @ Transactional ביאור.

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

יש עוד נקודה חשובה. ביחד איתי org.hibernate.context.CurrentSessionContext ממשק, ה- Hibernate הציג נכס hibernate.current_session_context_class שניתן להגדיר למחלקה המיישמת את הקשר ההפעלה הנוכחי.

כאמור, אביב מגיע עם יישום משלה של ממשק זה: SpringSessionContext. כברירת מחדל הוא מגדיר את hibernate.current_session_context_class רכוש השווה למחלקה זו.

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

לסיכום, חשוב לזכור כי אנחנו לא צריכים להגדיר את hibernate.current_session_context_class במפורש כאשר אנו משתמשים באביב כדי לנהל את מושב החורף.

6. מסקנה

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

הקוד למאמר זה ניתן למצוא באתר Github.

תחתית התמדה

רק הכרזתי על החדש למד אביב קורס, המתמקד ביסודות האביב 5 ומגף האביב 2:

>> בדוק את הקורס

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