bal*_*teo 4 jpa spring-mvc spring-data-jpa
假设我有一个具有大量属性的实体/ javabean.
此外,我有一个用于更新该实体的html表单(在jsp或thymeleaf中).
正如我的应用程序在这里是我如何继续更新实体:
以下是我的控制器方法的示例:
@RequestMapping(value = "/family/advertisement/edit", method = RequestMethod.POST, produces = "text/html")
public String editFamilyAdvertisement(@ModelAttribute @Validated(value = Validation.AdvertisementCreation.class) FamilyAdvertisement familyAdvertisement,
BindingResult bindingResult, Model model) {
FamilyAdvertisement advertisementForUpdate = advertisementService.findFamilyAdvertisement(familyAdvertisement.getId());
if (bindingResult.hasErrors()) {
populateModel(model, familyAdvertisement);
return "family/advertisement/edit";
}
advertisementForUpdate.setNeeds(familyAdvertisement.getNeeds());
advertisementForUpdate.setChildcareTypes(familyAdvertisement.getChildcareTypes());
advertisementForUpdate.setDayToTimeSlots(familyAdvertisement.getDayToTimeSlots());
...
advertisementService.editFamilyAdvertisement(advertisementForUpdate);
return "redirect:/some/url";
}
Run Code Online (Sandbox Code Playgroud)
我目前的应用程序有两个问题:
任何人都可以建议更好的模式或解决方案?
编辑1:我按照提供的建议.
这是我修改过的控制器方法:
@RequestMapping(value = "/family/advertisement/edit", method = RequestMethod.POST, produces = "text/html")
public String editFamilyAdvertisement(@ModelAttribute @Validated(value = Validation.AdvertisementCreation.class) FamilyAdvertisementInfo familyAdvertisementInfo,
BindingResult bindingResult, Model model) {
Member member = memberService.retrieveCurrentMember();
FamilyAdvertisement advertisementForCheck = advertisementService.findFamilyAdvertisement(familyAdvertisementInfo.getFamilyAdvertisement().getId());
if (!member.getAdvertisements().contains(advertisementForCheck)) {
throw new IllegalStateException("advertisement does not belong to member");
}
if (bindingResult.hasErrors()) {
populateModel(model, familyAdvertisementInfo);
return "family/advertisement/edit";
}
advertisementService.editFamilyAdvertisement(familyAdvertisementInfo.getFamilyAdvertisement());
return "redirect:/family/advertisement/edit/" + familyAdvertisementInfo.getFamilyAdvertisement().getId();
}
Run Code Online (Sandbox Code Playgroud)
您看到我必须从db中获取Family广告实体,以便检查它是否属于会话中的当前成员.然后,当我尝试按照建议保存实体时,我得到一个StaleObjectStateException,如下所示:
SEVERE: Servlet.service() for servlet [bignibou] in context with path [/bignibou] threw exception [Request processing failed; nested exception is org.springframework.orm.jpa.JpaOptimisticLockingFailureException: org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [com.bignibou.domain.FamilyAdvertisement#1]; nested exception is javax.persistence.OptimisticLockException: org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [com.bignibou.domain.FamilyAdvertisement#1]] with root cause
org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [com.bignibou.domain.FamilyAdvertisement#1]
at org.hibernate.event.internal.DefaultMergeEventListener.entityIsDetached(DefaultMergeEventListener.java:303)
at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:151)
at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:76)
at org.hibernate.internal.SessionImpl.fireMerge(SessionImpl.java:903)
at org.hibernate.internal.SessionImpl.merge(SessionImpl.java:887)
at org.hibernate.internal.SessionImpl.merge(SessionImpl.java:891)
at org.hibernate.ejb.AbstractEntityManagerImpl.merge(AbstractEntityManagerImpl.java:879)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:366)
at com.sun.proxy.$Proxy120.merge(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:241)
at com.sun.proxy.$Proxy119.merge(Unknown Source)
at org.springframework.data.jpa.repository.support.SimpleJpaRepository.save(SimpleJpaRepository.java:345)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.executeMethodOn(RepositoryFactorySupport.java:334)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:319)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocatio
Run Code Online (Sandbox Code Playgroud)
编辑2:如果我不从数据库中获取实体,我所遇到的问题是,上面的调用contains始终要进行评估,false因为它在equals内部使用该方法并且实体可能已经更改(毕竟这是为了方法).
if (!member.getAdvertisements().contains(familyAdvertisementInfo.getFamilyAdvertisement())) {
throw new IllegalStateException("advertisement does not belong to member");
}
Run Code Online (Sandbox Code Playgroud)
编辑3:
我仍然遇到与StaleObjectStateException相同的问题,因为我的控制器方法似乎执行了两次保存/事务.
@RequestMapping(value = "/family/advertisement/edit", method = RequestMethod.POST, produces = "text/html")
public String editFamilyAdvertisement(@ModelAttribute @Validated(value = Validation.AdvertisementCreation.class) FamilyAdvertisementInfo familyAdvertisementInfo,
BindingResult bindingResult, Model model) {
Member member = memberService.retrieveCurrentMember();//ONE
if (!advertisementService.advertisementBelongsToMember(familyAdvertisementInfo.getFamilyAdvertisement(), member)) {
throw new IllegalStateException("advertisement does not belong to member");
}
if (bindingResult.hasErrors()) {
populateModel(model, familyAdvertisementInfo);
return "family/advertisement/edit";
}
familyAdvertisementInfo.getFamilyAdvertisement().setMember(member);
advertisementService.editFamilyAdvertisement(familyAdvertisementInfo.getFamilyAdvertisement());//TWO
return "redirect:/family/advertisement/edit/" + familyAdvertisementInfo.getFamilyAdvertisement().getId();
}
Run Code Online (Sandbox Code Playgroud)
见例外:
org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [com.bignibou.domain.FamilyAdvertisement#1]
org.hibernate.event.internal.DefaultMergeEventListener.entityIsDetached(DefaultMergeEventListener.java:303)
org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:151)
org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:76)
org.hibernate.internal.SessionImpl.fireMerge(SessionImpl.java:903)
org.hibernate.internal.SessionImpl.merge(SessionImpl.java:887)
org.hibernate.internal.SessionImpl.merge(SessionImpl.java:891)
org.hibernate.ejb.AbstractEntityManagerImpl.merge(AbstractEntityManagerImpl.java:879)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:601)
org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:366)
com.sun.proxy.$Proxy123.merge(Unknown Source)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:601)
org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:241)
com.sun.proxy.$Proxy122.merge(Unknown Source)
org.springframework.data.jpa.repository.support.SimpleJpaRepository.save(SimpleJpaRepository.java:345)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:601)
org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.executeMethodOn(RepositoryFactorySupport.java:334)
org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:319)
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110)
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:155)
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
org.springframework.data.jpa.repository.support.LockModeRepositoryPostProcessor$LockModePopulatingMethodIntercceptor.invoke(LockModeRepositoryPostProcessor.java:91)
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:91)
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
com.sun.proxy.$Proxy129.save(Unknown Source)
com.bignibou.service.AdvertisementServiceImpl_Roo_Service.ajc$interMethod$com_bignibou_service_AdvertisementServiceImpl_Roo_Service$com_bignibou_service_AdvertisementServiceImpl$updateFamilyAdvertisement(AdvertisementServiceImpl_Roo_Service.aj:58)
com.bignibou.service.AdvertisementServiceImpl.updateFamilyAdvertisement(AdvertisementServiceImpl.java:1)
com.bignibou.service.AdvertisementServiceImpl_Roo_Service.ajc$interMethodDispatch1$com_bignibou_service_AdvertisementServiceImpl_Roo_Service$com_bignibou_service_AdvertisementServiceImpl$updateFamilyAdvertisement(AdvertisementServiceImpl_Roo_Service.aj)
com.bignibou.service.AdvertisementServiceImpl.editFamilyAdvertisement(AdvertisementServiceImpl.java:27)
com.bignibou.controller.AdvertisementController.editFamilyAdvertisement(AdvertisementController.java:85)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3605 次 |
| 最近记录: |