2009-12-24 18 views
9

मैं डेटाबेस में एक ही पंक्ति में 2 समवर्ती अद्यतन अनुकरण करने की कोशिश कर, हाइबरनेट का उपयोग कर रहा हूं।हाइबरनेट लॉक प्रतीक्षा टाइमआउट पार हो गया;

संपादित करें: मैंने em1.getTransaction() को स्थानांतरित किया है। Em1.flush() के बाद सही होने के लिए प्रतिबद्ध है; मुझे कोई StaleObjectException नहीं मिल रहा है, दो लेनदेन सफलतापूर्वक किए गए हैं।

Session em1=Manager.sessionFactory.openSession(); 
Session em2=Manager.sessionFactory.openSession(); 

em1.getTransaction().begin(); 
em2.getTransaction().begin(); 

UserAccount c1 = (UserAccount)em1.get(UserAccount.class, "root"); 
UserAccount c2 = (UserAccount)em2.get(UserAccount.class, "root"); 

c1.setBalance(c1.getBalance() -1); 
em1.flush(); 
System.out.println("balance1 is "+c2.getBalance()); 
c2.setBalance(c2.getBalance() -1); 
em2.flush(); // fail 

em1.getTransaction().commit(); 
em2.getTransaction().commit(); 

System.out.println("balance2 is "+c2.getBalance()); 

मुझे em2.flush() पर निम्नलिखित अपवाद मिल रहा है। क्यूं कर?

2009-12-23 21:48:37,648 WARN JDBCExceptionReporter:100 - SQL Error: 1205, SQLState: 41000 
2009-12-23 21:48:37,649 ERROR JDBCExceptionReporter:101 - Lock wait timeout exceeded; try restarting transaction 
2009-12-23 21:48:37,650 ERROR AbstractFlushingEventListener:324 - Could not synchronize database state with session 
org.hibernate.exception.GenericJDBCException: Could not execute JDBC batch update 
    at org.hibernate.exception.SQLStateConverter.handledNonSpecificException(SQLStateConverter.java:126) 
    at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:114) 
    at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66) 
    at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:275) 
    at org.hibernate.persister.entity.AbstractEntityPersister.processGeneratedProperties(AbstractEntityPersister.java:3702) 
    at org.hibernate.persister.entity.AbstractEntityPersister.processUpdateGeneratedProperties(AbstractEntityPersister.java:3691) 
    at org.hibernate.action.EntityUpdateAction.execute(EntityUpdateAction.java:147) 
    at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:279) 
    at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:263) 
    at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:168) 
    at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321) 
    at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:50) 
    at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1028) 
    at com.ch.whoisserver.test.StressTest.main(StressTest.java:54) 
Caused by: java.sql.BatchUpdateException: Lock wait timeout exceeded; try restarting transaction 
    at com.mysql.jdbc.PreparedStatement.executeBatchSerially(PreparedStatement.java:1213) 
    at com.mysql.jdbc.PreparedStatement.executeBatch(PreparedStatement.java:912) 
    at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:70) 
    at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:268) 
    ... 10 more 

उत्तर

20

ठीक है, यदि आप एक गतिरोध में पाने के लिए कोशिश कर रहे हैं और आप सफल हो रहे हैं :-)

  1. Transaction1 शुरू होता है, अद्यतन (और ताले) अपने संस्था के साथ पंक्ति।
  2. लेनदेन 2 ऐसा करने का प्रयास करता है लेकिन ऐसा नहीं कर सकता क्योंकि पंक्ति अभी भी बंद है। तो यह इंतजार कर रहा है (और इंतजार करता है, और प्रतीक्षा करता है), जब तक समय समाप्त पार हो गई है

वास्तविक जीवन सिमुलेशन अलग धागे में 1 और 2 इकाई प्रबंधक प्लस उचित अपडेट/लेनदेन होगा। इस तरह आपके पास होगा:

  1. लेनदेन 1 आपकी इकाई के साथ पंक्ति, अद्यतन (और ताले) पंक्ति शुरू होता है।
  2. लेनदेन 2 ऐसा करने का प्रयास करता है लेकिन ऐसा नहीं कर सकता क्योंकि पंक्ति अभी भी बंद है। तो यह इंतजार कर रहा है (और इंतजार करता है, और प्रतीक्षा करता है) ...
  3. इस बीच Transaction1 लिए प्रतिबद्ध है और लॉक जारी की है
  4. Transaction2 अब आगे बढ़ सकते हैं

ध्यान दें कि उस बिंदु (# 4 ऊपर) पर आप चाहते लेनदेन 1 द्वारा किए गए परिवर्तनों को ओवरराइट करना। होने से रोकने के लिए हाइबरनेट optimistic locking के साथ-साथ pessimistic locking का उपयोग कर सकते हैं।

अद्यतन (टिप्पणी के आधार पर):

इकाई संस्करणीकृत है, तो Transaction2 (# 4 ऊपर) असफल हो जायेगी। हालांकि, पोस्ट के रूप में आपका कोड उस बिंदु पर नहीं पहुंचता है क्योंकि ऊपर वर्णित अनुसार लेनदेन 2 लॉक प्राप्त नहीं कर सकता है। आप विशेष रूप से है कि आशावादी संस्करण नियंत्रण परीक्षण करना चाहते हैं तो आप निम्न कर सकते हैं काम कर रहा है:

  1. em1 प्राप्त, लेन-देन शुरू करते हैं, तो अपनी इकाई मिलता है, लेन-देन, पास em1 प्रतिबद्ध।
  2. em2 प्राप्त करें, लेनदेन शुरू करें, अपनी इकाई प्राप्त करें, अपनी इकाई अपडेट करें, लेनदेन करें, बंद करें em2।
  3. em3 प्राप्त करें, लेनदेन शुरू करें, चरण 1 में लोड की गई इकाई को अपडेट करने का प्रयास करें - परीक्षण यहां विफल होना चाहिए।
+0

मैं वास्तव में एक परीक्षण केस लिखने की कोशिश कर रहा हूं यह देखने के लिए कि क्या आशावादी लॉकिंग काम करता है, ऑब्जेक्ट उपयोगकर्ता खाता प्रश्न में उपयोग कर रहा है, कृपया इस प्रश्न को विस्तार से देखें http://stackoverflow.com/questions/1938671/concurrency- इन-हाइबरनेट, इस मामले में दो थ्रेड्स के साथ लेनदेन 2 अंतर्निहित डेटा में बदलाव का पता लगाने के लिए एक staledObjectException प्राप्त करें? – user217631

+0

@ अज्ञात हां, यह होगा। – KLE

+0

मैंने ऊपर अपना उत्तर अपडेट किया है - दो धागे का उपयोग करना ** ** विशेष रूप से ** आशावादी लॉकिंग (अप्रत्याशित होने के कारण) – ChssPly76

संबंधित मुद्दे