2016-03-01 96 views
1

我使用的彈簧引導開發Spring應用程序1.3Spring的事務中導致彈簧MVC集成測試失敗

我有一個看起來像這樣的MVC請求處理程序:

@RequestMapping(method = PUT, path = "/{categoryId}") 
    public String update(@Valid @ModelAttribute("category") Category category, BindingResult result, @GetAttribute("currentStore") Store store, Model model, RedirectAttributes ra) { 
     if (result.hasErrors()) { 
      model.addAttribute("categories", categoryService.activeCategories(store)); 
      return EDIT_VIEW_NAME; 
     } else { 
      categoryService.update(category); 
      ra.addFlashAttribute("info", "Category updated successfully!"); 
      return redirectTo(categoryUrls.indexPath()); 
     } 
    } 

這裏是集成測試它

@RunWith(SpringJUnit4ClassRunner.class) 
@SpringApplicationConfiguration(EstoreApplication.class) 
@WebIntegrationTest 
@Transactional 
public class CategoriesControllerIntegrationTests { 

    @Autowired 
    private WebApplicationContext wac; 
    private MockMvc mockMvc; 


    @Test 
    @WithFactoryUser(roles = "admin") 
    public void testUpdateCategoryActionWithInvalidData() throws Exception { 
     //GIVEN 
     String categoryId = "category_001"; 
     Store store = storeBuilder.getTestStore(); 
     categoryBuilder.createListWithStore(5,store); 
     Category category = categoryBuilder.createWithId(categoryId); 

     //WHEN 
     this.mockMvc.perform(
       put("/admin/categories/{categoryId}", categoryId) 
         .param("name", category.getName()) 
         .param("title", category.getTitle()) 
         .param("status", " ") 
         .param("store", store.getId()) 
         .with(csrf()) 
     ) 

     //THEN 
       .andExpect(status().isOk()) 
       .andExpect(view().name(CategoriesController.EDIT_VIEW_NAME)) 
       .andExpect(model().attributeHasErrors("category")) 
       .andExpect(model().attributeHasFieldErrors("category", "status")) 
     ; 
    } 
} 

某些位空間刪除,但要注意在上面

@Transactional註釋

它運行並通過無線:

model.addAttribute("categories", categoryService.activeCategories(store)); 

但添加時,它給這個討厭的異常,這是無需任何數據插入操作的Bean驗證異常(驗證錯誤已經通過彈簧MVC處理和在BindingResult結果)

List of constraint violations:[ 
    ConstraintViolationImpl{interpolatedMessage='{com.estore.constraints.inset}', propertyPath=status, rootBeanClass=class org.commerceforge.estore.app.model.Category, messageTemplate='{com.estore.constraints.inset}'} 
    ConstraintViolationImpl{interpolatedMessage='may not be empty', propertyPath=status, rootBeanClass=class org.commerceforge.estore.app.model.Category, messageTemplate='{org.hibernate.validator.constraints.NotBlank.message}'} 
], mergedContextConfiguration = [[email protected] testClass = CategoriesControllerIntegrationTests, locations = '{}', classes = '{class org.commerceforge.estore.EstoreApplication}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.IntegrationTest=true}', resourceBasePath = '', contextLoader = 'org.springframework.boot.test.SpringApplicationContextLoader', parent = [null]]]. 

org.springframework.web.util.NestedServletException: Request processing failed; nested exception is javax.validation.ConstraintViolationException: Validation failed for classes [org.commerceforge.estore.app.model.Category] during persist time for groups [javax.validation.groups.Default, ] 
List of constraint violations:[ 
    ConstraintViolationImpl{interpolatedMessage='{com.estore.constraints.inset}', propertyPath=status, rootBeanClass=class org.commerceforge.estore.app.model.Category, messageTemplate='{com.estore.constraints.inset}'} 
    ConstraintViolationImpl{interpolatedMessage='may not be empty', propertyPath=status, rootBeanClass=class org.commerceforge.estore.app.model.Category, messageTemplate='{org.hibernate.validator.constraints.NotBlank.message}'} 
] 
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:981) 
    at org.springframework.web.servlet.FrameworkServlet.doPut(FrameworkServlet.java:882) 
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:651) 
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:845) 
    at org.springframework.test.web.servlet.TestDispatcherServlet.service(TestDispatcherServlet.java:65) 
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:729) 
    at org.springframework.mock.web.MockFilterChain$ServletFilterProxy.doFilter(MockFilterChain.java:167) 
    at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:134) 
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:316) 
    at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:126) 
    at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:90) 
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) 
    at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:114) 
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) 
    at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:122) 
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) 
    at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111) 
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) 
    at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:169) 
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) 
    at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:48) 
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) 
    at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:205) 
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) 
    at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:120) 
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) 
    at org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:120) 
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) 
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) 
    at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64) 
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) 
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) 
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91) 
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) 
    at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53) 
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) 
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) 
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213) 
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176) 
    at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:134) 
    at org.springframework.test.web.servlet.MockMvc.perform(MockMvc.java:155) 
    at org.commerceforge.estore.tests.mvc.web.integration.CategoriesControllerIntegrationTests.testUpdateCategoryActionWithInvalidData(CategoriesControllerIntegrationTests.java:296) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) 
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) 
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) 
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) 
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26) 
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75) 
    at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27) 
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86) 
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84) 
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:254) 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:89) 
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) 
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) 
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) 
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) 
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) 
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26) 
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61) 
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70) 
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363) 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:193) 
    at org.junit.runners.Suite.runChild(Suite.java:128) 
    at org.junit.runners.Suite.runChild(Suite.java:27) 
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) 
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) 
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) 
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) 
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) 
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363) 
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137) 
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:78) 
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:212) 
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:68) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140) 
Caused by: javax.validation.ConstraintViolationException: Validation failed for classes [org.commerceforge.estore.app.model.Category] during persist time for groups [javax.validation.groups.Default, ] 
List of constraint violations:[ 
    ConstraintViolationImpl{interpolatedMessage='{com.estore.constraints.inset}', propertyPath=status, rootBeanClass=class org.commerceforge.estore.app.model.Category, messageTemplate='{com.estore.constraints.inset}'} 
    ConstraintViolationImpl{interpolatedMessage='may not be empty', propertyPath=status, rootBeanClass=class org.commerceforge.estore.app.model.Category, messageTemplate='{org.hibernate.validator.constraints.NotBlank.message}'} 
] 
    at org.hibernate.cfg.beanvalidation.BeanValidationEventListener.validate(BeanValidationEventListener.java:160) 
    at org.hibernate.cfg.beanvalidation.BeanValidationEventListener.onPreInsert(BeanValidationEventListener.java:95) 
    at org.hibernate.action.internal.EntityInsertAction.preInsert(EntityInsertAction.java:218) 
    at org.hibernate.action.internal.EntityInsertAction.execute(EntityInsertAction.java:97) 
    at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:465) 
    at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:351) 
    at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:350) 
    at org.hibernate.event.internal.DefaultAutoFlushEventListener.onAutoFlush(DefaultAutoFlushEventListener.java:67) 
    at org.hibernate.internal.SessionImpl.autoFlushIfRequired(SessionImpl.java:1227) 
    at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1293) 
    at org.hibernate.internal.QueryImpl.list(QueryImpl.java:103) 
    at org.hibernate.jpa.internal.QueryImpl.list(QueryImpl.java:573) 
    at org.hibernate.jpa.internal.QueryImpl.getResultList(QueryImpl.java:449) 
    at org.hibernate.jpa.criteria.compile.CriteriaQueryTypeQueryAdapter.getResultList(CriteriaQueryTypeQueryAdapter.java:67) 
    at org.springframework.data.jpa.repository.query.JpaQueryExecution$CollectionExecution.doExecute(JpaQueryExecution.java:114) 
    at org.springframework.data.jpa.repository.query.JpaQueryExecution.execute(JpaQueryExecution.java:78) 
    at org.springframework.data.jpa.repository.query.AbstractJpaQuery.doExecute(AbstractJpaQuery.java:100) 
    at org.springframework.data.jpa.repository.query.AbstractJpaQuery.execute(AbstractJpaQuery.java:91) 
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:462) 
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:440) 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) 
    at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:61) 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) 
    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 org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136) 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) 
    at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:131) 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) 
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92) 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) 
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:208) 
    at com.sun.proxy.$Proxy163.findAllByStoreAndStatus(Unknown Source) 
    at org.commerceforge.estore.app.service.impl.CategoryServiceImpl.activeCategories(CategoryServiceImpl.java:115) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    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 org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:208) 
    at com.sun.proxy.$Proxy200.activeCategories(Unknown Source) 
    at org.commerceforge.estore.app.web.mvc.CategoriesController.update(CategoriesController.java:81) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:222) 
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:137) 
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110) 
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:814) 
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:737) 
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85) 
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959) 
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893) 
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:969) 
    ... 84 more 

當我刪除@Transactional出現在一流水平的,一切順利,所以我認爲這是在交易中一點改進

行:

model.addAttribute("categories", categoryService.activeCategories(store)); 

是圍繞取景器查詢的包裝:

@Transactional(readOnly = true) 
    public List<Category> activeCategories(Store store) { 
     return categoryRepository.findAllByStoreAndStatus(store, Category.STATUS_ENABLED); 
    } 

,這只是一個選擇quert,應該不會引起豆驗證錯誤

會發生什麼事是,我通過一組無效數據來測試它不會傳遞,spring mvc在BindingResult中捕獲錯誤,但似乎在測試方法結束時,某種事務回滾(我不確定,只是猜測)並嘗試插入數據

如果我刪除了@Transactional註釋,但是這對我來說不實用,因爲我的整個測試套件(950多個測試)依賴於空數據庫,並且我使用@Transactional實現它以回滾對數據的任何更改

+0

您傳遞了無效數據,因此測試必須失敗,但您不希望它失敗?你爲什麼在你的測試課上有'@ Transactional'?因爲_「在Spring TestContext框架中集成測試的回滾語義默認爲true」_。 '@ Transactional'不是這樣的。 – zeroflagL

+0

當傳遞無效數據時,測試應該通過,因爲spring框架會捕獲驗證異常,將結果放入BindingResult對象中。 @Transactional with rollback = true會導致在測試過程中刪除所有未填寫的數據,導致在測試結束時清空空數據庫 – Joseph

+0

@ Transactional沒有'rollback'屬性。再次說明:所有測試都應該在默認回滾的事務中運行。沒有必要明確地做任何事情。 – zeroflagL

回答

0

我認爲問題是readOnly查詢的刷新模式。如果你使用休眠模式,你可以通過你的方法的org.springframework.data.jpa.repository.QueryHints-Annotation來將flush模式設置爲COMMIT(https://docs.jboss.org/hibernate/orm/4.3/javadocs/org/hibernate/jpa/QueryHints.html#HINT_FLUSH_MODE)。


我只能猜測在這一點......等待你對我的問題的迴應。但我認爲你有做爲類別,對象查找(類似於http://www.javabeat.net/modelattribute-spring-mvc/的東西)爲什麼範疇對象從請求加載,然後通過數據修改

這就是,去掉了@的ModelAttribute標註方法status-value => Category-Object,其中包含在提交查詢時刷新的entityManager中的無效數據。

該問題也可以通過調用entityManager.clear()我猜,或entityManager.detach(類)來緩解。


我想你有一個OpenEntityManagerInViewFilter的地方。你應該知道,即使在你的控制器沒有顯式調用persist/update的情況下,如果實體是從非readOnly-repository-method中獲取的,你所做的每個修改都會被寫入數據庫,除非有事務回滾(通過拋出異常或手動告訴事務回滾http://docs.spring.io/spring-framework/docs/2.5.6/api/org/springframework/transaction/TransactionStatus.html#setRollbackOnly%28%29

...編輯

啊。這就是爲什麼測試在沒有@ Transactional-rollback的情況下工作的原因,因爲在調用@ ModelAttribute-annotated方法時沒有事務=> entityManager立即關閉,因此在提交查詢時不會刷新Category。

+0

代碼示例請? – Joseph

+0

我添加的行: @QueryHints(@QueryHint(名稱= org.hibernate.jpa.QueryHints.HINT_FLUSH_MODE,值=「COMMIT」))在取景器方法的頂部 和它的工作:) :) 請請請,你可以提供一些解釋或指向參考文檔的指針。 這將高度讚賞。謝謝 – Joseph

+0

我不知道爲什麼會發生。似乎是這樣的,實體管理器在發出jpa查詢時包含一個帶有無效數據的Category對象,這導致了entityMangers狀態的刷新(以確保查詢的數據是最新的)......我將試圖找出爲什麼這會發生你的情況。同時,你可以發佈你的categoryBuilder的相關代碼嗎? – cproinger