Обновление логики для объектов JPA завершается ошибкой при использовании DBUnit и Spring - PullRequest
2 голосов
/ 17 января 2012

В настоящее время я использую DBUnit в сочетании с Spring для модульного тестирования моего приложения, но столкнулся с проблемой, когда мой тест обновления логики всегда терпит неудачу, потому что в базе данных возникает тупик, и я не могу понять, почему это так , Обратите внимание, что мне удалось обойти эту проблему, удалив метод, аннотированный @After, который на самом деле не нужен, потому что я использую аннотацию @TransactionConfiguration, но меня беспокоит, что я что-то неправильно понимаю относительно того, как обработка транзакций работает, и поэтому я надеюсь, что кто-то может указать, почему я всегда получаю следующее исключение при запуске моего метода updateTerritory.

java.sql.SQLTransactionRollbackException: A lock could not be obtained within the time requested

Одна вещь, на которую стоит обратить внимание, - это то, что я могу выполнять другие действия, такие как запрос к базе данных и вставка новых записей без ошибок блокировки. Кроме того, я использую OpenJPA, а Spring впрыскивает PersistenceUnit в мой DAO. Я предполагаю, что смешивание использования PersistenceUnit и прямого использования источника данных в моем коде установки DBUnit (testSetup и testTeardown) может быть частью проблемы. В настоящее время я использую Derby в качестве базы данных.

Мой код указан ниже:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "/applicationContext.xml")
@TransactionConfiguration(defaultRollback = true)
public class TerritoryZoneManagerTest {

@Autowired
private DataSource unitTestingDataSource;

@Autowired
private ITerritoryZoneDaoManager mgr;

@Before
public void testSetup() throws DatabaseUnitException, SQLException,
        FileNotFoundException {
    Connection con = DataSourceUtils.getConnection(unitTestingDataSource);
    IDatabaseConnection dbUnitCon = new DatabaseConnection(con);

    FlatXmlDataSetBuilder builder = new FlatXmlDataSetBuilder();
    IDataSet dataSet = builder
            .build(new FileInputStream(
                    "./src/com.company.territoryzonelookup/dao/test/TerritoryZoneManagerTest.xml"));

    try {

        // NOTE: There is no need to use the DatabaseOperation.DELETE
        // functionality because spring will automatically remove all
        // inserted records after each test case is executed.
        DatabaseOperation.REFRESH.execute(dbUnitCon, dataSet);
    } finally {
        DataSourceUtils.releaseConnection(con, unitTestingDataSource);
    }
}

    @After
public void testTeardown() throws DatabaseUnitException, SQLException,
        FileNotFoundException {
    Connection con = DataSourceUtils.getConnection(unitTestingDataSource);
    IDatabaseConnection dbUnitCon = new DatabaseConnection(con);

    FlatXmlDataSetBuilder builder = new FlatXmlDataSetBuilder();
    IDataSet dataSet = builder
            .build(new FileInputStream(
                    "./src/com.company.territoryzonelookup/dao/test/TerritoryZoneManagerTest.xml"));

    try {

        // NOTE: There is no need to use the DatabaseOperation.DELETE
        // functionality because spring will automatically remove all
        // inserted records after each test case is executed.
        DatabaseOperation.DELETE.execute(dbUnitCon, dataSet);
    } finally {
        DataSourceUtils.releaseConnection(con, unitTestingDataSource);
    }
}

@Test
@Transactional
public void updateTerritory() {
    TerritoryZone zone = new TerritoryZone();
    int id = 1;
    zone = mgr.getTerritory(id);

    String newCity = "Congerville";
    zone.setCity(newCity);
    mgr.updateTerritory(zone);

    zone = mgr.getTerritory(id);
    Assert.assertEquals(newCity, zone.getCity());
}
}

Объект DAO также приводится ниже в случае, если это полезно.

@Repository
public class TerritoryZoneDaoManager implements ITerritoryZoneDaoManager {

/*
@Autowired
private EntityManagerFactory emf;
*/

/*
 * @PersistenceUnit EntityManagerFactory emf;
 * 
 * @PersistenceContext private EntityManager getEntityManager(){ return
 * emf.createEntityManager(); }
 */

@PersistenceContext
private EntityManager em;

private EntityManager getEntityManager() {
    // return emf.createEntityManager();
    return em;
}

/* (non-Javadoc)
 * @see com.company.territoryzonelookup.dao.ITerritoryZoneManager#addTerritory(com.company.territoryzonelookup.dao.TerritoryZone)
 */
@Override
public TerritoryZone addTerritory(TerritoryZone territoryZone) {
    EntityManager em = getEntityManager();
    em.persist(territoryZone);
    return territoryZone;
}

/* (non-Javadoc)
 * @see com.company.territoryzonelookup.dao.ITerritoryZoneManager#getTerritory(int)
 */
@Override
public TerritoryZone getTerritory(int id) {
    TerritoryZone obj = null;
    Query query = getEntityManager().createNamedQuery("selectById");
    query.setParameter("id", id);
    obj = (TerritoryZone) query.getSingleResult();
    return obj;
}

/* (non-Javadoc)
 * @see com.company.territoryzonelookup.dao.ITerritoryZoneManager#updateTerritory(com.company.territoryzonelookup.dao.TerritoryZone)
 */
@Override
public TerritoryZone updateTerritory(TerritoryZone territoryZone){
    getEntityManager().merge(territoryZone);
    return territoryZone;
}

/* (non-Javadoc)
 * @see com.company.territoryzonelookup.dao.ITerritoryZoneManager#getActiveTerritoriesByStateZipLob(java.lang.String, java.lang.String, java.util.Date, java.lang.String)
 */
@Override
public List<TerritoryZone> getActiveTerritoriesByStateZipLob(String stateCd, String zipCode, Date effectiveDate, String lobCd){
    List<TerritoryZone> territoryList;

    Query query = getEntityManager().createNamedQuery("selectActiveByZipStateLob");
    query.setParameter("zipCode", zipCode);
    query.setParameter("state", stateCd);
    query.setParameter("lob",lobCd);
    query.setParameter("effectiveDate", effectiveDate);

    territoryList = (List<TerritoryZone>) query.getResultList();

    return territoryList;
}

/* (non-Javadoc)
 * @see com.company.territoryzonelookup.dao.ITerritoryZoneManager#deleteAll()
 */
@Override
public void deleteAll(){
    Query query = getEntityManager().createNativeQuery("Delete from TerritoryZone");
    query.executeUpdate();
}

/***
 * the load method will remove all existing records from the database and then will reload it using it the data passed.
 * @param terrList
 */
public void load(List<TerritoryZone> terrList){
    deleteAll();
    for (TerritoryZone terr:terrList){
        addTerritory(terr);
    }
}

}

Заранее спасибо за вашу помощь. Джереми

1 Ответ

1 голос
/ 18 февраля 2012

jwmajors81

Я не могу знать, что не так с вашим кодом модульного тестирования из-за отсутствия некоторых деталей.

Я также использовал весенний юнит-тест и dbunit для моей библиотеки himvc, платформы RAD на основе spring3 и hibernate. вот код моего суперкласса для модульного тестирования ,

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:config/application-test-config.xml"})
@Transactional
@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
public class HiMVCTransactionalUnitTest extends AbstractTransactionalJUnit4SpringContextTests{
    @Autowired
    protected DBUnitHelper dbHelper;

    protected void loadFixture(){

        try{
            String fixtureFile=this.dbHelper.getDataFile();
            if(fixtureFile==null){
                fixtureFile=this.getDefaultXMLFixtureFile();
                this.dbHelper.setDataFile(fixtureFile);
            }
            if(this.dbHelper.isDataFileExisted()){
                if(this.dbHelper.isMSSQL()){
                    HiMVCInsertIdentityOperation operation=new HiMVCInsertIdentityOperation(DatabaseOperation.CLEAN_INSERT);
                    operation.setInTransaction(true);
                    this.dbHelper.executeDBOperation(operation);
                }else{
                    this.dbHelper.executeDBOperation(DatabaseOperation.CLEAN_INSERT);
                }
            }
        }catch(Exception x){
            x.printStackTrace();
        }
    }

...
}

Я использую аннотацию @Transactional в объявлении класса, а также указал транзакциюManager. я написал DBUnitHelper, чтобы обернуть детали dbunit загрузки данных.

Вот пример модульного теста:

public class MyTest extends HiMVCTransactionalUnitTest{
    @Before
    public void setup(){
        super.loadFixture();
    }
    //other testing methods
}  

Надеюсь, эти коды полезны.

...