Spring data JPA:未提交每条记录的事务

Posted

技术标签:

【中文标题】Spring data JPA:未提交每条记录的事务【英文标题】:Spring data JPA : Transaction for every record is not commited 【发布时间】:2017-06-17 19:16:49 【问题描述】:

我需要通过以下操作在循环中提交记录:

删除旧状态的记录(父+子) 创建新记录,插入父+子 下面的 deleteOldAndsaveNew() 方法在循环中调用,我希望每次都提交里面的操作。

PFB代码sn-p:

调用方法: //服务层

public int updateOldDocumentsFromList(List<DocumentChildDTO> childDocuments) 
            
            int nbDocsUpdated = 0;
            for (DocumentChildDTO docChildDTO : childDocuments) 

            if (docChildDTO .getDocument() != null) 
                DocumentDTO documentDTO = docChildDTO .getDocument();
                Document document =            documentMapper.documentDTOToDocument(documentDTO);
                Document latestDoc = getLatestChildDocument(document);
                

                DocumentStatus statusObsolete = docStatusService.findByName(DocumentStatusType.Obsolete.toString());
                DocumentStatus statusValidated = docStatusService.findByName(DocumentStatusType.Validated.toString());
                boolean isDBDocObsolete = isDBDocObsolete(statusObsolete, latestDoc);
                boolean createDoc = false;
                nbDocsUpdated = documentDAO.deleteObsoleteAndSaveValidatedDoc(docChildDTO, document, latestDoc, statusValidated, isDBDocObsolete,
                        nbDocsUpdated, createDoc);
            
        
        LOG.info("End updating olddocouments (nb docs updated: " + nbDocsUpdated + ")");
        return nbDocsUpdated;
    

//道层

   @Transactional(propagation = Propagation.REQUIRES_NEW) 
 public int deleteObsoleteAndSaveValidatedDoc(DocumentChildDTO docChildDTO, Document document, Document latestDoc,
            DocumentStatus statusValidated, boolean isDBDocObsolete, int nbDocsUpdated, boolean createDoc) 
                DocumentStatus statusObsolete = getOldDocStatus();
                
                if ((latestDoc == null) || isDBDocObsolete(statusObsolete, latestDoc)) 
                    createDoc = true;
                
                if (isDBDocObsolete(statusObsolete, latestDoc)) 
                    documentDAO.delete(latestDoc);
                
                DocumentDTO documentDTO;
                if (createDoc) 
                    setters for new document
        
                    // Save the new doc
                    documentDTO = docService.save(document);
                    if (documentDTO == null) 
                        LOG.error("Error");
                     else 
                        nbDocsUpdated++;
                    
                    
                
        docChildDTO.setDocument(documentDTO);
                        if (save(docChildDTO) == null) 
                            LOG.error("Error");
                        
                    
                return nbDocsUpdated;
            
    
    Delete document method
    
        @PersistenceContext
        private EntityManager entityManager;
        public void delete(Document obsoleteDocument)  
                  this.entityManager.remove(obsoleteDocument);
                  this.entityManager.flush();
            
    
        @Transactional
            public void saveDocument(Document document) 
                LOG.debug("Request to save Document : ", document);
                this.entityManager.persist(document);
                this.entityManager.flush();
               
            
        
        @Transactional
            public void save(DocumentChild documentChild ) 
                LOG.debug("Request to save documentChild : ", documentChild );
              documentChildDao.saveAndFlush(documentChild);
               
            

我已经使用实体管理器和 Spring 数据方法来查看哪一个有效,我可以看到生成了删除语句和 2 个插入语句(父和子),并且 id 也增加了,但它没有在 db 中反映/提交.

这行@Transactional(propagation = Propagation.REQUIRES_NEW) 是否不能保证每次访问deleteOldAndsaveNew() 方法时都提交其中的操作?

编辑:我已删除 (propagation = Propagation.REQUIRES_NEW) 并尝试仅在每次都需要提交的操作上使用事务。

请提出建议。

谢谢。

【问题讨论】:

这里有人,如果我不够清楚,请告诉我?谢谢 尝试从 DAO 方法中删除 @Transactional.. 只需在服务层使用它.. 其中定义了 deleteOldAndsaveNew 方法 感谢 Maciej...从 DAO 方法中删除事务没有帮助。请问还有什么建议吗? 我尝试在服务类级别上删除 @Transactional 并将其仅放在 deleteOldAndsaveNew 上,但没有成功.. 另外,在每次操作后调用 flush 并不是一个好主意。删除那些 .. em 将在事务结束时刷新.. 【参考方案1】:

谢谢,我能解决这个问题。通过在单独的类中使用以下代码并从类级别中删除 Transactional。

调用方法:

public int updateObsoleteDocumentsFromList(List<DocumentChildDTO> childDocuments) 
         LOG.info("Start updating Obsolete documents (nb docs to update: " + childDocuments.size()+ ")" );

         int nbDocsUpdated = 0;
        try 
            DocumentStatus statusObsolete = docStatusService.findByName(StatusType.Old.toString());
            Status statusValidated = docStatusService.findByName(StatusType.Validated.toString());
            for (DocumentChildDTO docChildDTO : childDocuments) 
                if (docChildDTO .getDocument() != null) 
                    DocumentDTO documentDTO = docChildDTO .getDocument();
                    Document document = documentMapper.documentDTOToDocument(documentDTO);
                    nbDocsUpdated = documentDAO.deleteObsoleteAndSaveValidatedDoc(docChildDTO, document, statusValidated,  
                            nbDocsUpdated, statusObsolete);
                
            
        

        return nbDocsUpdated;
    

被调用的方法(在单独的类中)

@Transactional
    public Integer deleteObsoleteAndSaveValidatedDoc(DocumentChildDTO docChildDTO, Document document,
            DocumentStatus statusValidated, int nbDocsUpdated ,DocumentStatus statusObsolete) 

        Document latestDoc = getLatestChildDocument(document);
        boolean isDBDocObsolete = isDBDocObsolete(statusObsolete, latestDoc);
        boolean createDoc = false;
        DocumentDTO documentDTO;
        if ((latestDoc == null) || isDBDocObsolete) 
            createDoc = true;
        

        if (isDBDocObsolete) 
            documentChildDao.deleteChildDocumentByDocId(latestDoc.getId());
            deleteDocumentById(latestDoc.getId());
        
        if (createDoc) 
            document.setUpdateDate(new Date());
            document.setStatus(statusValidated);
            document.setIsObsolete(false);

            documentDTO = saveDocument(document);
            if (documentDTO == null) 
                LOG.error("Cannot create document " + document.getName());
             else 
                nbDocsUpdated++;
            
            docChildDTO.setDocument(documentDTO);
            if (documentChildDao.save(docChildDTO) == null) 
                LOG.error("Cannot create child document " + docChildDTO.getNameChild());
            

        return nbDocsUpdated;
    

谢谢。

【讨论】:

以上是关于Spring data JPA:未提交每条记录的事务的主要内容,如果未能解决你的问题,请参考以下文章

Spring-data-jpa + Hibernate 未创建预期表

Spring Data JPA - 防止一对一关系的双重表单提交

spring spring data jpa save操作事务

带有spring boot JPA Postgresql的data.sql未加载

带有 Hikari 的 Spring Data JPA:为啥 hikari 自动提交属性设置为“true”?

Spring Data JPA Native Query - 未注册命名参数