#java #spring #jpa
#java #весна #jpa
Вопрос:
Когда я запускаю свои модульные тесты изолированно, они работают нормально, т.Е. (пропущены утверждения)
@Test
public void testSave()
{
EntityManagerHelper emh = new EntityManagerHelper();
LevelDAO dao = new LevelDAO();
Level l = new Level();
l.setName("aname");
emh.beginTransaction();
dao.save(l);
emh.commit();
}
затем запуск этого отдельного теста ниже без проблем
@Test
public void testUpdate()
{
EntityManagerHelper emh = new EntityManagerHelper();
LevelDAO dao = new LevelDAO();
Level l = new Level();
l.setName("bname");
l.setLevelid(1);
emh.beginTransaction();
dao.update(l);
emh.commit();
}
Когда они выполняются одновременно последовательно, я получаю сообщение об ошибке — транзакция в данный момент активна. Есть ли способ разрешить запуск каждого модульного теста только после того, как транзакция из предыдущей части работы не активна? Должен ли я вместо этого смотреть на Spring?
Обновить
EntityManagerHelper получает доступ к контексту сохранения следующим образом
emf = Persistence.createEntityManagerFactory("bw_beta");
threadLocal = new ThreadLocal<EntityManager>();
что выглядит как проблема
Таким образом, хакерским обходным путем было использование определения локально ie.
EntityManagerFactory factory = Persistence.createEntityManagerFactory("bw_beta");
EntityManager entityManager = factory.createEntityManager();
entityManager.getTransaction().begin();
dao.save(l);
entityManager.persist(l);
entityManager.getTransaction().commit();
Уверен, что есть лучший способ — возможно, с помощью Spring?
Комментарии:
1. Что происходит внутри
EntityManagerHelper
?2. @DataNucleus: он не говорит, что хочет запускать их параллельно.
3. И какова трассировка стека исключения?
Ответ №1:
- Уверен, что есть лучший способ — возможно, с помощью Spring?
Да, Spring сильно ее очищает и дает вам контроль над тем, что вы хотели бы запустить в транзакции, не загрязняя фактический тест.
С Spring ваши тесты будут выглядеть примерно так:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({ "classpath:META-INF/conf/spring/application-context.xml",
"classpath:META-INF/conf/spring/test-datasource-spring-config.xml" })
@TransactionConfiguration(transactionManager="txMgr", defaultRollback=false)
public class LevelDaoTest {
@Resource( name="levelDao" )
LevelDao levelDao;
@Test
public void shouldSaveNewLevels() {
Level l = new Level();
l.setName("aname");
levelDao.save(l);
// assert
}
@Test
public void shouldUpdateExistingLevels() {
Level l = new Level(); // or I would assume, you'd read this level back from DB, or set a proper ID, so the DAO will know to update it.. But that is besides the point
l.setName("bname");
levelDao.update(l);
// assert
}
}
Взгляните на документацию Spring в разделе Тестирование => Управление транзакциями, чтобы получить более подробную информацию.
PS Из вашего примера:
dao.save(l);
entityManager.persist(l);
Выглядит действительно странно, так как обычно вы инкапсулируете entityManager
в DAO, поэтому все, что вам нужно сделать, это dao.save(l)
Ответ №2:
Для всех, у кого может возникнуть эта проблема, вот как я ее решил. Я делал несколько сохранений и продолжал получать эту ошибку. Вы не хотите начинать несколько транзакций, не проверив, активна ли она.
if(!entityManager.getTransaction().isActive())
entityManager.getTransaction().begin();
dao.save(l);
entityManager.persist(l);
entityManager.getTransaction().commit();
Я реализовал одноэлементный подход для ее обработки.