开发者

JPA Error : Transaction is currently active

开发者 https://www.devze.com 2023-04-11 17:15 出处:网络
When I run my unit tests in isolation they work fine ie. (omitted the assert开发者_运维问答s) @Test

When I run my unit tests in isolation they work fine ie. (omitted the assert开发者_运维问答s)

@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();
}

then running this individual test below no problem

@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();
}

When they run at same time in sequence I recieve that error - Transaction is currently active. Is there a way to allow each unit test to run only after a transaction from previous piece of work is not active? Should I be looking at Spring instead?

Update

The EntityManagerHelper gains access to the persistence context like so

emf = Persistence.createEntityManagerFactory("bw_beta");        
threadLocal = new ThreadLocal<EntityManager>();

which looks like the problem

So a hacky workaround was to use define locally ie.

    EntityManagerFactory factory = Persistence.createEntityManagerFactory("bw_beta");
    EntityManager entityManager = factory.createEntityManager();
    entityManager.getTransaction().begin();
    dao.save(l);
    entityManager.persist(l);
    entityManager.getTransaction().commit();

Pretty sure there's a better way - maybe using Spring?


  • Pretty sure there's a better way - maybe using Spring?

Yes, Spring cleans it up a lot and gives you control on what you'd like to run within a transaction without polluting the actual test.

With Spring, your tests would look something like this:

@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
    }
}

Take a look at Spring Documentation under Testing => Transaction Management to get more details.

P.S. From your example:

dao.save(l);
entityManager.persist(l);

Looks really strange, as usually you would encapsulate entityManager within a DAO, so all you'd need to do is dao.save(l)


For anyone that may be having this issue here is how I resolved it. I was doing multiple saves and I kept getting this error. You do not want to begin multiple transactions without checking if it is active.

if(!entityManager.getTransaction().isActive())
    entityManager.getTransaction().begin();
dao.save(l);
entityManager.persist(l);
entityManager.getTransaction().commit();

I implemented a Singleton approach to handle it.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号