Transaction required exception on execute update f

2019-04-09 08:40发布

问题:

I get this error when I try to run this code.

Error:

javax.persistence.TransactionRequiredException: executeUpdate is not supported for a Query object obtained through non-transactional access of a container-managed transactional EntityManager

Code: (_ut is a UserTransaction object)

public void setMainCategory(Integer deptId, Integer catId) {

        try {
            Query setmain = _entityManager.createNamedQuery("Category.setAsMain");
            Query removeMain = _entityManager.createNamedQuery("Category.removeMain");
            setmain.setParameter("categoryId", catId);
            Department d;
            d=_entityManager.find(Department.class, deptId);
            removeMain.setParameter("department", d);
            _ut.begin();
            removeMain.executeUpdate();
            _ut.commit();
            _ut.begin();
            setmain.executeUpdate();
            _ut.commit();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

I have other functions that are identical in implementation and they do not throw this error.

Any suggestions would be greatly appreciated.

Thanks.

回答1:

You are using an EntityManager to get the Named Queries and also using an (what I think is) injected UserTransaction.

See that the error message says "...Query object obtained through non-transactional access...". This means you are getting the "NamedQuery" through non-transactional access, because the EntityManager is not in the same transaction as _ut. So, you first join the EntityManager to the UserTransaction then you get and execute the query.

Finally your block should look like:

@PersistenceContext(unitName = "myPU")
EntityManager em;

@Inject
UserTransaction ut;

public void doSomeStuff()
{
    ut.begin();
    em.joinTransaction();

    em.createNamedQuery("query1").executeUpdate();

    ut.commit();
}


回答2:

The problem does not come from your method implementation but from your execution context.
All method that update database must be executed within an opened transaction. The way you ensure that depends on the way you manage transaction. If transactions are user-managed you have to explicitly retrieve and join an existing transaction or open a new one. If it's container-managed just add @transactional annotation on your method or ensure that there is a method in your call hierarchy holding the annotation.

Here you're using user-managed transactions in a container-managed transaction context (see "container-managed transactional EntityManager" in your error message). You shouldn't so begin and commit / rollback yourself the transactions. If you want to do so, just retrieve an application-managed EntityManager to be able to properly access to JTA transactions.

cf. http://docs.oracle.com/cd/E19226-01/820-7627/bnbqy/index.html



回答3:

According to the error message, I think the reason is that your order of transaction, you didn't get the Department d in transaction, so the statement of d is detached, then you want to directly update it which will change the statement to managed, the JPA can't do this. just move the find code in the transaction, I think it will be ok.