坚持@PostConstruct:javax.persistence.TransactionRequiredException

时间:2012-12-18 13:41:57

标签: java jpa

在@PostConstruct中持久保存对象时,My Entitymanager没有事务。 我不知道为什么以及如何解决这个问题,任何人都可以帮助我吗?

PS。如果您需要任何其他数据,请询问

TestmachineManager

@Singleton
public class TestmachineManager {
    @PersistenceContext
    private EntityManager em;

    private TimerTask handler = new TimerTask() {
        @Override
        public void run() {
            DayPlanning planning = getPlanning();
            Order order = planning.getNextInLine();
            if(order instanceof Order) {
                em.merge(planning);
                List<String> tests = new ArrayList();
                for(Test test : order.getTests()) {
                    tests.add(test.getName());
                }

                TestmachineSender.orderTests(order.getId(), order.getDomain(), tests);
                timer.schedule(checker, safetycheckAt());
            }
            else {
                timer.schedule(handler, postponeTo());
            }
        }
    };

    @PostConstruct
    public void init() {
        if(getPlanning().hasActiveTest()) {
            handler.run();
        }
    }

    private DayPlanning getPlanning() {
        LocalDate today = new LocalDate(
                Calendar.getInstance().getTime());

        try {
            CriteriaBuilder cb = em.getCriteriaBuilder();
            CriteriaQuery<DayPlanning> query = cb.createQuery(DayPlanning.class);
            Root dayPlanning = query.from(DayPlanning.class);
            Predicate predicateDate = cb.equal(dayPlanning.get("dateOfPlanning"), today.toDate());

            query.select(dayPlanning).where(predicateDate);
            return em.createQuery(query).getSingleResult();
        } catch(NoResultException ex) {
            DayPlanning newPlanning = new DayPlanning(today);
            em.persist(newPlanning);
            return newPlanning;
        }
    }
}

堆栈跟踪

Caused by: javax.persistence.TransactionRequiredException
    at com.sun.enterprise.container.common.impl.EntityManagerWrapper.doTxRequiredCheck(EntityManagerWrapper.java:163)
    at com.sun.enterprise.container.common.impl.EntityManagerWrapper.doTransactionScopedTxCheck(EntityManagerWrapper.java:145)
    at com.sun.enterprise.container.common.impl.EntityManagerWrapper.persist(EntityManagerWrapper.java:263)
    at TestmachineManager.getPlanning(TestmachineManager.java:130)
    at TestmachineManager.init(TestmachineManager.java:78)

1 个答案:

答案 0 :(得分:0)

在@PostConstruct中有一个针对Singleton bean的事务。当您丢失交易时,就是当您使用timer.schedule(checker, safetycheckAt());timer.schedule(handler, postponeTo());启动新计时器时。我认为你正在使用的计时器对象实际上是java.util.Timer,看着签名。

您应该尝试使用EJB TimerService资源。例如:

@Resource
private TimerService timerService;

@Timeout
public void run() {
    DayPlanning planning = getPlanning();
    Order order = planning.getNextInLine();
    if(order instanceof Order) {
        em.merge(planning);
        List<String> tests = new ArrayList();
        for(Test test : order.getTests()) {
            tests.add(test.getName());
        }

        TestmachineSender.orderTests(order.getId(), order.getDomain(), tests);

        // if the checker handler doesn't need to run transactionally you could leave it like it was before
        timer.schedule(checker, safetycheckAt());
        // otherwise you could create a checker EJB that uses @Timeout in the same manner or @Scheduled from EJB3.1
    } else {
        // postpone timer
        timerService.createTimer(postponeTo(), "postponed timer information");    
    }
}

@PostConstruct
public void init() {
    if(getPlanning().hasActiveTest()) {
        timerService.createTimer(computeDelay(), "timer information");
        // or you could use the other create methods of the timerService, those that fits your needs better
    }
}

我没有测试代码,只是粗略的代码。希望它有所帮助。