簡體   English   中英

NonUniqueObjectException與計划作業合流

[英]NonUniqueObjectException in Confluence with scheduled job

Confluence的Job石英版在頁面創建方面遇到了很大的問題。

QUARTZ職位類別:

@ComponentImport
private final SpaceManager spaceManager;
@Autowired
private final GeneralConfig config;
@Autowired
private final PageCreator pageCreator;
@ComponentImport
private final PageManager pageManager;

@Autowired
public ReportingPluginJob(GeneralConfig config, SpaceManager spaceManager, PageCreator pageCreator,
        PageManager pageManager) {
    this.config = config;
    this.spaceManager = spaceManager;
    this.pageCreator = pageCreator;
    this.pageManager = pageManager;
}

private static final org.slf4j.Logger LOG = LoggerFactory.getLogger(ReportingPluginJob.class);

@Override
public void execute(JobExecutionContext jec) throws JobExecutionException {

    Collection<String> keys = spaceManager.getAllSpaceKeys(SpaceStatus.CURRENT);

    String parentPageName = config.getSchedulerWeeklyParentPageName();

    for (String key : keys) {

        Page parentPage
                = pageManager.getPage(key, parentPageName);

        if (parentPage != null) {
            LOG.debug("Creating weekly report for space " + key);
            long pageId = parentPage.getId();
            try {
                pageCreator.createEazyBiReport(key, pageId);
            } catch (ApplicationException e) {
                LOG.error("FAILED TO CREATE A REPORT FOR SPACE " + key + " with error: " + System.lineSeparator()
                        + e.getMessage());
            }

        }

    }

}

PAGE CREATION類:

  Space space = spaceManager.getSpace(spaceKey);

    if (page != null) {
        page.setTitle(pageTitle);
        page.setSpace(space);
        page.setVersion(1);
        page.addLabelling(new Labelling(label, page.getEntity(), AuthenticatedUserThreadLocal.get()));
        page.setCreator(AuthenticatedUserThreadLocal.get());
        page.setCreationDate(new Date());
        Page parent = pageManager.getPage(parentId);
        if (parent != null) {
            parent.addChild(page);
        }
    }
        pageManager.saveContentEntity(page, DefaultSaveContext.builder().suppressNotifications(true).build());
        attachmentProvider.attachExcelFileToPage(page);

最后是讓我生氣的異常:

org.springframework.dao.DuplicateKeyException: A different object with the same identifier value was already associated with the session : [com.atlassian.confluence.spaces.Space#31653891]; nested exception is org.hibernate.NonUniqueObjectException: A different object with the same identifier value was already associated with the session : [com.atlassian.confluence.spaces.Space#31653891]
at org.springframework.orm.hibernate5.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:259)
at org.springframework.orm.hibernate5.HibernateTemplate.doExecute(HibernateTemplate.java:362)
at org.springframework.orm.hibernate5.HibernateTemplate.executeWithNativeSession(HibernateTemplate.java:326)
at org.springframework.orm.hibernate5.HibernateTemplate.saveOrUpdate(HibernateTemplate.java:704)
at com.atlassian.confluence.core.persistence.hibernate.HibernateObjectDao.saveRaw(HibernateObjectDao.java:207)
at com.atlassian.confluence.pages.persistence.dao.hibernate.CachingPageDao.saveRaw(CachingPageDao.java:157)
at com.atlassian.confluence.core.DefaultContentEntityManager.saveContentEntity(DefaultContentEntityManager.java:150)
at com.atlassian.confluence.pages.DefaultPageManager.saveContentEntity(DefaultPageManager.java:1388)
at sun.reflect.GeneratedMethodAccessor2132.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:302)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:281)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at com.atlassian.spring.interceptors.SpringProfilingInterceptor.invoke(SpringProfilingInterceptor.java:16)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at com.atlassian.confluence.util.profiling.ConfluenceMonitoringMethodInterceptor.invoke(ConfluenceMonitoringMethodInterceptor.java:34)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:208)
at com.sun.proxy.$Proxy105.saveContentEntity(Unknown Source)
at sun.reflect.GeneratedMethodAccessor2132.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.atlassian.plugin.util.ContextClassLoaderSettingInvocationHandler.invoke(ContextClassLoaderSettingInvocationHandler.java:26)
at com.sun.proxy.$Proxy253.saveContentEntity(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:302)
at org.eclipse.gemini.blueprint.service.importer.support.internal.aop.ServiceInvoker.doInvoke(ServiceInvoker.java:56)
at org.eclipse.gemini.blueprint.service.importer.support.internal.aop.ServiceInvoker.invoke(ServiceInvoker.java:60)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:133)
at org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:121)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.eclipse.gemini.blueprint.service.util.internal.aop.ServiceTCCLInterceptor.invokeUnprivileged(ServiceTCCLInterceptor.java:70)
at org.eclipse.gemini.blueprint.service.util.internal.aop.ServiceTCCLInterceptor.invoke(ServiceTCCLInterceptor.java:53)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.eclipse.gemini.blueprint.service.importer.support.LocalBundleContextAdvice.invoke(LocalBundleContextAdvice.java:57)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:133)
at org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:121)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:208)
at com.sun.proxy.$Proxy2863.saveContentEntity(Unknown Source)
at com.censored.atlassian.plugins.service.PageCreator.createEazyBiReport(PageCreator.java:128)
at com.censored.atlassian.plugins.service.ReportingPluginJob.execute(ReportingPluginJob.java:64)
at com.atlassian.confluence.plugin.descriptor.JobModuleDescriptor$DelegatingPluginJob.lambda$execute$0(JobModuleDescriptor.java:113)
at com.atlassian.confluence.impl.vcache.VCacheRequestContextManager.doInRequestContextInternal(VCacheRequestContextManager.java:87)
at com.atlassian.confluence.impl.vcache.VCacheRequestContextManager.doInRequestContext(VCacheRequestContextManager.java:71)
at com.atlassian.confluence.plugin.descriptor.JobModuleDescriptor$DelegatingPluginJob.execute(JobModuleDescriptor.java:112)
at org.quartz.core.JobRunShell.run(JobRunShell.java:223)
at com.atlassian.confluence.schedule.quartz.ConfluenceQuartzThreadPool.lambda$runInThread$0(ConfluenceQuartzThreadPool.java:16)
at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:549)

根據堆棧跟蹤,頁面保存(saveContentEntity)時出現問題。 看來,頁面保存也需要更新與該頁面關聯的空間。 問題來了。 根據堆棧跟蹤,此空間已存在於Hibernate會話中。 evictclear實際會話不起作用。 有什么建議,如何處理該異常,或者實際上如何從Hibernate會話中刪除空間?

顯然,這是代碼中發生的事情:

  1. 在您的SpaceManager ,您的會話會找到ID為1(假定為ID)的Session對象並返回它。
  2. 您的方法使用此引用與另一個對象( Page一個)關聯。
  3. 最后,您的PageManager這些數據保留在數據庫中。

可能您的問題是以下問題:
從步驟1到2,當SpaceManager返回數據時,您的事務結束,並且您返回的對象變為detached
此后,當您調用save ,您將嘗試保留一個分離的Session ,但是它已經存在於數據庫中。 然后,您將獲得一個例外。

您可以嘗試使用merge方法或從實體中的該引用中刪除cascade

(請提供您的實體代碼,以便在出現任何錯誤或不適合您的情況下改善答案。)

我們遇到了同樣的問題,為我們解決的是將創建頁面的代碼(並加載其他對象,例如空間或父頁面)全部放入事務中:

private void createNewPage(String title, String pageInput, Long parentPageId, String spaceKey) {
    transactionTemplate.execute(() -> {
        Page page = new Page();
        page.setTitle(title);
        page.setBodyAsString(pageInput);

        Space space = spaceManager.getSpace(spaceKey);
        page.setSpace(space);

        Page parentPage = pageManager.getPage(parentPageId);
        if (parentPage != null) {
            page.setParentPage(parentPage);
            parentPage.addChild(page);
        }

        pageManager.saveContentEntity(page, DefaultSaveContext.DEFAULT);

        return null;
    });
}

com.atlassian.sal.api.transaction.TransactionTemplate可以使用@ComponentImport注入

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM