2011-02-25 11 views
5

से अधिक हो गया है, मैं एक सेवा विधि का परीक्षण करने की कोशिश कर रहा हूं जो असीमित रूप से चलाता है (@Async)। यहाँJUnit @transactional @Async विधि को कॉल करने का कारण बनता है लॉक प्रतीक्षा टाइमआउट

@Async 
@Transactional(propagation=Propagation.SUPPORTS, isolation = Isolation.READ_UNCOMMITTED) 
public Future<UserPrefs> checkLanguagePreference(long id) { 

    UserPrefs prefs = prefsDao.retrieveUserPreferences(id); 
    if(prefs == null || !StringUtils.hasLength(prefs.getLanguage())) { 
     //Save a new sms-command object 
     SmsBean command = SmsHelper.buildSmsCommand(); 
     if(! smsDao.checkSameCommandExists(id, command)) { 

      smsDao.saveSms(id, new SmsBean[] {command}); //Will wait until Lock wait timeout 
     } 
    } 
    return new AsyncResult<UserPrefs>(prefs); 
} 

और परीक्षा पद्धति async एक बुला है:

यहाँ async विधि है

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(location = "...") 
@TransactionConfiguration(transactionManager = "txManager", defaultRollback = false) 
@Transactional(isolation = Isolation.READ_UNCOMMITTED) 
@TestExecutionListeners({ DependencyInjectionTestExecutionListener.class, 
    DirtiesContextTestExecutionListener.class, 
    TransactionalTestExecutionListener.class }) 
public class MessagingServiceTest { 

    @Before 
    public void setUp() {   
    //Avant tout mettre tout les sms en lu 
    smsDao.deleteAllSms(1); 
    sessionFactory.getCurrentSession().flush(); 

    //On vérifie bien qu'il n y a plus de sms 
    List<SmsBean> list = smsDao.getNewSmsList(1); 
    assertEquals(0,list.size()); 
    } 

    @Test 
    public void checkLanguagePreferenceTest() throws InterruptedException, ExecutionException { 
    User user = (User) sessionFactory.getCurrentSession().load(User.class, new Long(1));//idUser = 1 
    // We explicitly blank the preference from db 
    prefsDao.saveLanguagePref(new UserPrefs("",user)); 

    Future<UserPrefs> prefs = messagingService.checkLanguagePreference(user.getId()); 
    System.out.println("wait completion of async task");   
    prefs.get(); 
    System.out.println("Async task has finished"); 
    } 
} 

जब prefs.get() निष्पादित किया जाता है, मैं इस त्रुटि है:

Caused by: org.springframework.orm.hibernate3.HibernateJdbcException: JDBC exception on Hibernate data access: SQLException for SQL [insert into SmsBean (destination, message, origin, sens, status, USER_ID) values (?, ?, ?, ?, ?, ?)]; SQL state [41000]; error code [1205]; could not insert: 

Caused by: java.sql.SQLException: Lock wait timeout exceeded; try restarting transaction 

    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1075) 
    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3562) 
    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3494) 
    at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1960) 
    at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2114) 
    at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2696) 
    at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:2105) 
    at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2398) 
    at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2316) 
    at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2301) 
    at org.apache.commons.dbcp.DelegatingPreparedStatement.executeUpdate(DelegatingPreparedStatement.java:101) 
    at org.hibernate.id.IdentityGenerator$GetGeneratedKeysDelegate.executeAndExtract(IdentityGenerator.java:94) 
    at org.hibernate.id.insert.AbstractReturningDelegate.performInsert(AbstractReturningDelegate.java:57) 
    ... 39 more 

ऐसा इसलिए होता है क्योंकि सेटअप में smsDao.deleteAllSms विधि है एसएमएस टेबल पर एक ताला lding।

मैं इस लॉक टाइमआउट से सही ढंग से कैसे बच सकता हूं और अपना परीक्षण सफलतापूर्वक चलाने में सक्षम हूं?

आपकी मदद के लिए धन्यवाद।

FYI करें, यहाँ कुछ सांत्वना उत्पादन होता है:

 
DEBUG - Adding transactional method 'checkLanguagePreferenceTest' with attribute: PROPAGATION_REQUIRED,ISOLATION_READ_COMMITTED; '' 
DEBUG - Explicit transaction definition [PROPAGATION_REQUIRED,ISOLATION_READ_COMMITTED; ''] found for test context [[[email protected] testClass = MessagingServiceTest, locations = array['file:src/main/resources/myapp-context.xml', 'file:src/main/resources/myapp-data.xml', 'file:src/main/resources/myapp-services.xml'], testInstance = [email protected], testMethod = [email protected], testException = [null]]] 
DEBUG - Retrieved @TransactionConfiguration [@org.springframework.test.context.transaction.Tran sactionConfiguration(defaultRollback=false, transactionManager=txManager)] for test class [class fr.myapp.service.MessagingServiceTest] 
DEBUG - Retrieved TransactionConfigurationAttributes [[[email protected] transactionManagerName = 'txManager', defaultRollback = false]] for class [class fr.myapp.service.MessagingServiceTest] 
DEBUG - Returning cached instance of singleton bean 'txManager' 
DEBUG - Creating new transaction with name [checkLanguagePreferenceTest]: PROPAGATION_REQUIRED,ISOLATION_READ_COMMITTED; '' 
DEBUG - Opened new Session [[email protected]] for Hibernate transaction 
DEBUG - Preparing JDBC Connection of Hibernate Session [[email protected]] 
DEBUG - Changing isolation level of JDBC Connection [[email protected]] to 2 
DEBUG - Exposing Hibernate transaction as JDBC transaction [[email protected]] 
DEBUG - No method-level @Rollback override: using default rollback [false] for test context [[[email protected] testClass = MessagingServiceTest, locations = array['file:src/main/resources/myapp-context.xml', 'file:src/main/resources/myapp-data.xml', 'file:src/main/resources/myapp-services.xml'], testInstance = [email protected], testMethod = [email protected], testException = [null]]] 
INFO - Began transaction (1): transaction manager [org.springframework.orm.hibernate3.HibernateTransa [email protected]]; rollback [false] 
Hibernate: delete from SmsBean where USER_ID=? 
Hibernate: select user0_.id as id3_1_, user0_.email as email3_1_, user0_.login as login3_1_, user0_.passwd as passwd3_1_, smsbeans1_.USER_ID as USER7_3_3_, smsbeans1_.id as id3_, smsbeans1_.id as id0_0_, smsbeans1_.destination as destinat2_0_0_, smsbeans1_.message as message0_0_, smsbeans1_.origin as origin0_0_, smsbeans1_.sens as sens0_0_, smsbeans1_.status as status0_0_, smsbeans1_.USER_ID as USER7_0_0_ from User user0_ left outer join SmsBean smsbeans1_ on user0_.id=smsbeans1_.USER_ID where user0_.id=? 
Hibernate: select user0_.id as id3_, user0_.email as email3_, user0_.login as login3_, user0_.passwd as passwd3_ from User user0_ where user0_.login=? 
Hibernate: select userprefs0_.id as id2_, userprefs0_.language as language2_, userprefs0_.USER_ID as USER3_2_ from user_prefs userprefs0_ where userprefs0_.USER_ID=? 
wait completion of async task 
DEBUG - Returning cached instance of singleton bean 'txManager' 
INFO - Ener dans checkLanguagePreference(1) 
DEBUG - Opening Hibernate Session 
DEBUG - Registering Spring transaction synchronization for new Hibernate Session 
Hibernate: select userprefs0_.id as id2_, userprefs0_.language as language2_, userprefs0_.USER_ID as USER3_2_ from user_prefs userprefs0_ where userprefs0_.USER_ID=? 
Hibernate: select user0_.id as id3_1_, user0_.email as email3_1_, user0_.login as login3_1_, user0_.passwd as passwd3_1_, smsbeans1_.USER_ID as USER7_3_3_, smsbeans1_.id as id3_, smsbeans1_.id as id0_0_, smsbeans1_.destination as destinat2_0_0_, smsbeans1_.message as message0_0_, smsbeans1_.origin as origin0_0_, smsbeans1_.sens as sens0_0_, smsbeans1_.status as status0_0_, smsbeans1_.USER_ID as USER7_0_0_ from User user0_ left outer join SmsBean smsbeans1_ on user0_.id=smsbeans1_.USER_ID where user0_.id=? 
INFO - Checking if same sms command already exist 
Hibernate: select * from smsbean S where S.USER_ID=? and S.status=? and S.message=? 
DEBUG - Flushing Hibernate Session on transaction synchronization 

//Deadlock here : 
Hibernate: insert into SmsBean (destination, message, origin, sens, status, USER_ID) values (?, ?, ?, ?, ?, ?) 
DEBUG - Closing Hibernate Session 
58799 [SimpleAsyncTaskExecutor-1] WARN org.hibernate.util.JDBCExceptionReporter - SQL Error: 1205, SQLState: 41000 
58799 [SimpleAsyncTaskExecutor-1] ERROR org.hibernate.util.JDBCExceptionReporter - Lock wait timeout exceeded; try restarting transaction 

हल है, लेकिन FYI करें, मैं पहले के बारे में कारण है कि मैं देखने के डीबीएमएस दृष्टिकोण से इस गतिरोध हो रही थी MySQL के मंच पर एक धागा बनाने के बाद,। यहाँ (ठीक है यह भी बताया) लिंक है:

http://forums.mysql.com/read.php?97,409237,409237#msg-409237

उत्तर

4

के बाद से अपने परीक्षण @Transactional के रूप में घोषित किया जाता है, तो आप एक बड़ा लेन-देन है कि setUp विधि के निष्पादन और अपने परीक्षा पद्धति में फैला है। यह ट्रांजैक्शन डेडलॉक्स एक और लेनदेन के साथ एसिंक एक्शन में शुरू हुआ (एसिंक एक्शन मुख्य लेनदेन द्वारा अधिग्रहित ताले के रिलीज के लिए इंतजार कर रहा है, मुख्य लेनदेन एसिंक एक्शन के पूरा होने की प्रतीक्षा करता है)।

आप कई अलग लेन-देन में मुख्य लेन-देन को तोड़कर इसे हल कर सकते हैं:

@Before 
@Transactional // separate transaction for setUp 
public void setUp() {   
    //Avant tout mettre tout les sms en lu 
    smsDao.deleteAllSms(1); 
    sessionFactory.getCurrentSession().flush(); 

    //On vérifie bien qu'il n y a plus de sms 
    List<SmsBean> list = smsDao.getNewSmsList(1); 
    assertEquals(0,list.size()); 
} 

@Test 
@Transactional(propagation = NEVER) // Disable main transaction 
public void checkLanguagePreferenceTest() throws InterruptedException, ExecutionException { 

    // Programmatic transaction for test preparation 
    User user = tx.execute(new TransactionCallback<User>() { 
     public User doInTransaction(TransactionStatus status) { 
      User user = (User) sessionFactory.getCurrentSession().load(User.class, new Long(1));//idUser = 1 
      // We explicitly blank the preference from db 
      prefsDao.saveLanguagePref(new UserPrefs("",user));  
      return user; 
     } 
    }); 

    Future<UserPrefs> prefs = messagingService.checkLanguagePreference(user.getId()); 
    System.out.println("wait completion of async task");    
    prefs.get(); 
    System.out.println("Async task has finished"); 
} 

private TransactionTemplate tx; 

@Autowired 
public void setPtm(PlatformTransactionManager ptm) { 
    tx = new TransactionTemplate(ptm); 
} 
+1

धन्यवाद। उत्तम! – redochka

0

आप भी एक परीक्षण संदर्भ एक अपने थ्रेडेड साथियों के बजाय एक SyncTaskExecutor का उपयोग करता है कॉन्फ़िगर कर सकते हैं आप अपने परीक्षण के लिए तुल्यकालिक निष्पादन को बर्दाश्त कर सकते हैं ।

दूसरे शब्दों में:

<bean id="myExecutor" class="org.springframework.core.task.SyncTaskExecutor"/> 

के बजाय:

<task:executor id="myExecutor" pool-size="5"/> 

फिर सब कुछ एक ही धागे में चलता है और आप प्रतिस्पर्धा लेनदेन की वजह से डेटाबेस ताला लगा मुद्दों से निपटने की जरूरत नहीं है।

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