Spring单例bean - 后台线程;没有实体事务可用错误的EntityManager

时间:2018-05-10 15:28:02

标签: java spring rest background-process transactional

该程序经常运行后台线程唤醒并将传入的DataEvent上传到远程服务器。

@Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON)
@Singleton
@Component
public class RWDataUploader {

    protected org.slf4j.Logger log = LoggerFactory.getLogger(RWDataUploader.class);

    @PersistenceContext(type = PersistenceContextType.TRANSACTION)
    private EntityManager em;

    protected EntityManager getEntityManager() {
        return em;
    }

    private final Object objectUploaderMonitor = new Object();

    private boolean isActive = true;
    private int errorCount = 0;
    private long sleepTime = 20000l;
    private Timer bgProcessTimer;

    @PostConstruct
    public void init() {
        log.info("RWDataUploadClient initilized {} ", RWDataUploader.this);
         TimerTask task = new TimerTask() {
            @Override
            public void run() {
                log.info("Staring Upload process...");
                RWDataUploader.this.startUpload();
                bgProcessTimer.cancel();
            }
        };
        bgProcessTimer = new Timer("Upload process");
        bgProcessTimer.scheduleAtFixedRate(task, 10000, 3000); // start with a delay
    }

    @PreDestroy
    public void close() {
        stopUpload();
        log.info("RWDataUploadClient closed {} ", RWDataUploader.this);
    }

    public void stopUpload() {
        isActive = false;
        synchronized (objectUploaderMonitor) {
            objectUploaderMonitor.notify();
        }
    }

    public void startUpload() {
        while (isActive) {
            synchronized (objectUploaderMonitor) {
                try {
                    uploadTxnToServer();
                    log.debug("UploadTxnToServer Done Sleeping for next cycle " + sleepTime);
                    objectUploaderMonitor.wait(sleepTime);
                } catch (Exception ex) {
                    errorCount++;
                    log.error("Exception at ObjectUploaderMonitor.wait " + ex.getMessage() , ex); 
                    if (errorCount == 1) {
                        isActive = false; 
                    }
                }
            }
        }
        log.info("Uploader client is stopped");
    }


    @Transactional
    private void uploadTxnToServer() {
        List<RWDataEvent> openDevnts = getPendingDataEvents();
        for (RWDataEvent openDevnt : openDevnts) {
            log.info("Uploaded DE {} ", openDevnt);
            // logic Upload event to remote server
            // upload done
            openDevnt.setProcessedStatusCode("UPLOADED");
            em.merge(openDevnt);
        }
    }

    private List<RWDataEvent> getPendingDataEvents() {
        Query nq = em.createNamedQuery("RWDataEvent.findByProcessedStatusCode");
        nq.setParameter("processedStatusCode", "WAIT_UPLOAD");
        return nq.getResultList();
    }

}  

执行时出现以下错误

  

错误c.r.r.c.uploader.RWDataUploader - ObjectUploaderMonitor.wait的异常没有可用于当前线程的实际事务的EntityManager - 无法可靠地处理'merge'调用   javax.persistence.TransactionRequiredException:没有可用于当前线程的实际事务的EntityManager - 无法可靠地处理'merge'调用       在org.springframework.orm.jpa.SharedEntityManagerCreator $ SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:282)       在com.sun.proxy。$ Proxy230.merge(未知来源)       在com.retailwave.rwos.compartment.uploader.RWDataUploader.uploadTxnToServer(RWDataUploader.java:106)       在com.retailwave.rwos.compartment.uploader.RWDataUploader.startUpload(RWDataUploader.java:82)       在com.retailwave.rwos.compartment.uploader.RWDataUploader $ 1.run(RWDataUploader.java:57)

1 个答案:

答案 0 :(得分:0)

没有重组一切。使用TransactionTemplate在事务中执行代码。

您必须使用 var httpRequest = new XMLHttpRequest(); httpRequest.onreadystatechange = function() { if(httpRequest.readyState == 4 && httpRequest.status == 200) { return httpRequest.responseText; } }; httpRequest.open("GET", url, true); httpRequest.send(null); }; }; var request = new HttpRequest(); var response = request.get("https://min-api.cryptocompare.com/data/price?fsym=BTC&tsyms=BTC,USD", "blank"); console.log(response); 方法并将实现放在其中。