Java org.hibernate.NonUniqueObjectException。如何解决?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18702715/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
org.hibernate.NonUniqueObjectException. How to fix it?
提问by
In my model are 3 entities(in real more than 3, but 3 is actually at this situation)
在我的模型中有 3 个实体(实际上超过 3 个,但实际上在这种情况下有 3 个)
- Candidate
- Vacancy
- Event
- 候选人
- 空缺
- 事件
They all have relation many to many(Candidate can have may Vacancies and many Events, Vacancy ...candidates and... events.....).
它们都有多对多的关系(候选人可以有可能的空缺和许多事件,空缺......候选人和......事件......)。
If I update Candidate - good result.
if I update Vacancy - good result
BUT if I update Event I have org.hibernate.NonUniqueObjectException
如果我更新 Candidate - 好的结果。如果我更新 Vacancy - 好的结果但是如果我更新 Event I haveorg.hibernate.NonUniqueObjectException
It shows when I change collection of vacancy in Event. If I comment place, where I change vacancies of event I have no problem(place ONE
in my code)
Go to code:
Model mapping:
当我在 Event 中更改空缺集合时会显示它。如果我评论地方,我改变事件空缺的地方ONE
我没有问题(放在我的代码中)转到代码:模型映射:
Vacancy:
空缺:
@Entity
@Table(name = "vacancy")
@XmlRootElement(name="vacancy")
public class Vacancy {
private Integer id;
private String name;
private String description;
private Date date;
private User author;
@XmlTransient
private Set<Candidate> candidates = new HashSet<Candidate>();
private Set<VacancyStatus> statusList = new HashSet<VacancyStatus>();
private Set<Skill> skills = new HashSet<Skill>();
private Set<Note> comments = new HashSet<Note>();
private Set<Event> events = new HashSet<Event>();
public Vacancy() {
super();
}
@ManyToMany(mappedBy = "vacancies", fetch = FetchType.EAGER)
public Set<Event> getEvents() {
return events;
}
public void setEvents(Set<Event> events) {
this.events = events;
}
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
@ManyToMany(mappedBy = "vacancies", fetch = FetchType.EAGER)
public Set<Candidate> getCandidates() {
return candidates;
}
public void setCandidates(Set<Candidate> candidates) {
this.candidates = candidates;
}
@Override
public boolean equals(Object obj) {
if(obj!= null && ((Vacancy)obj).getId() == id ){
return true;
}
return false;
}
@Override
public int hashCode() {
Integer id = getId();
return id != null ? id.intValue() : super.hashCode();
}
...
}
Candidate:
候选人:
@Entity
@Table(name = "candidate")
@XmlRootElement(name = "candidate")
public class Candidate extends Person {
@Size(min=3,max=12)
@Pattern(regexp="[0-9]*",message="phone format must be without + and - (for example: 89123353456)")
private String phone;
@Past
private Date date;
private User author;
@Size(min=4, max=100)
@URL()
private String resumeUrl;
private List<CandidateStatus> statusList = new LinkedList<CandidateStatus>();
private Set<Vacancy> vacancies= new HashSet<Vacancy>();
private Set<Skill> skills = new HashSet<Skill>();
private List<Note> comments = new LinkedList<Note>();
private Set<Event> events = new HashSet<Event>();
public Candidate() {
super();
}
@ManyToMany(mappedBy = "candidates", fetch = FetchType.EAGER)
//@LazyCollection(LazyCollectionOption.FALSE)
public Set<Event> getEvents() {
return events;
}
public void setEvents(Set<Event> events) {
this.events = events;
}
@ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@JoinTable(name = "candidate_vacancy", joinColumns = @JoinColumn(name = "candidate_id"), inverseJoinColumns = @JoinColumn(name = "vacancy_id"))
@XmlTransient
public Set<Vacancy> getVacancies() {
return vacancies;
}
public void setVacancies(Set<Vacancy> vacancies) {
this.vacancies = vacancies;
}
...
}
@MappedSuperclass
public abstract class Person {
@Size(min=3)
@Pattern(regexp="[a-zA-Z]*")
private String name;
@Size(min=3)
@Pattern(regexp="[a-zA-Z]*")
private String surname;
private Integer id;
public Person() {
}
public Person(String name, String surname) {
super();
this.name = name;
this.surname = surname;
}
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY )
@Column (name = "id")
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
@Column(name = "name")
//@NotEmpty
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Column(name = "surname")
//@NotEmpty
public String getSurname() {
return surname;
}
public void setSurname(String surname) {
this.surname = surname;
}
@Override
public boolean equals(Object obj) {
if(obj!=null && ((Person)obj).getId() == id ){
return true;
}
return false;
}
@Override
public int hashCode() {
Integer id = getId();
return id != null ? id.intValue() : super.hashCode();
}
}
Event:
事件:
@Entity
@Table(name = "event")
@XmlRootElement
public class Event {
private Integer id;
@Size(min=3 )
@Pattern(regexp="[a-zA-Z]*")
private String name;
@Size(min=5)
@Pattern(regexp="[a-zA-Z]*")
private String description;
private Date date;
@Future
private Date eventDate;
private User author;
private Set<Candidate> candidates;
private Set<Vacancy> vacancies;
private EventType eventType;
private EventStatus eventStatus;
public Event() {
super();
}
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name ="id")
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
@Override
public boolean equals(Object obj) {
if(obj!=null && ((Event)obj).getId() == id ){
return true;
}
return false;
}
@Override
public int hashCode() {
Integer id = getId();
return id != null ? id.intValue() : super.hashCode();
}
@ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
public Set<Candidate> getCandidates() {
return candidates;
}
public void setCandidates(Set<Candidate> candidates) {
this.candidates = candidates;
}
@ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
public Set<Vacancy> getVacancies() {
return vacancies;
}
public void setVacancies(Set<Vacancy> vacancies) {
this.vacancies = vacancies;
}
}
In my @Controller class I write so method:
在我的@Controller 类中,我编写了这样的方法:
@RequestMapping(value = "/updateEvent", method = RequestMethod.POST)
public String updateEvent(Model model,
@Valid @ModelAttribute("existedEvent") Event event,
BindingResult result,
@ModelAttribute("linkedCandidates") Set<Candidate> candidates,
@ModelAttribute("linkedvacancies") Set<Vacancy> vacancies) {
if (result.hasErrors()) {
model.addAttribute("idEvent", event.getId());
return "eventDetails";
}
if (vacancies != null) {
for (Vacancy vacancy : vacancies) {
vacancy.getEvents().add(event);
}
}
if (candidates != null) {
for (Candidate candidate : candidates) {
candidate.getEvents().add(event);
}
}
event.setVacancies(vacancies);//place ONE (if comment this line - will //work)
event.setCandidates(candidates);
eventService.update(event);//error here
return "redirect:goToEventMenu";
}
update:
更新:
@Transactional
@Service
public class EventService {
public void update(Event event) {
eventDao.update(event);
}
....
}
@Repository("eventDaoImpl")
public class EventDaoImpl extends DaoAbstract implements EventDao {
@Autowired
CandidateDao candidateDao;
@Autowired
VacancyDao vacancyDao;
@Override
public boolean update(Event event) {
Session session = sessionFactory.getCurrentSession();
if (event == null) {
return false;
}
session.update(event);
return true;
}
...
}
Sorry for a lot of code/ But I don't know that write here)
抱歉有很多代码/但我不知道写在这里)
UPDATE 1
更新 1
stackTrace:
堆栈跟踪:
10.09.2013 11:46:14 org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet [appServlet] in context with path [/ui] threw exception [Request processing failed; nested exception is org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session: [com.epam.hhsystem.model.vacancy.Vacancy#6]] with root cause
org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session: [com.epam.hhsystem.model.vacancy.Vacancy#6]
at org.hibernate.engine.internal.StatefulPersistenceContext.checkUniqueness(StatefulPersistenceContext.java:697)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.performUpdate(DefaultSaveOrUpdateEventListener.java:296)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.entityIsDetached(DefaultSaveOrUpdateEventListener.java:241)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:109)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:90)
at org.hibernate.internal.SessionImpl.fireSaveOrUpdate(SessionImpl.java:735)
at org.hibernate.internal.SessionImpl.saveOrUpdate(SessionImpl.java:727)
at org.hibernate.engine.spi.CascadingAction.cascade(CascadingAction.java:258)
at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:388)
at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:331)
at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:209)
at org.hibernate.engine.internal.Cascade.cascadeCollectionElements(Cascade.java:418)
at org.hibernate.engine.internal.Cascade.cascadeCollection(Cascade.java:358)
at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:334)
at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:209)
at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:166)
at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:132)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.cascadeOnUpdate(DefaultSaveOrUpdateEventListener.java:364)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.performUpdate(DefaultSaveOrUpdateEventListener.java:338)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.entityIsDetached(DefaultSaveOrUpdateEventListener.java:241)
at org.hibernate.event.internal.DefaultUpdateEventListener.performSaveOrUpdate(DefaultUpdateEventListener.java:55)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:90)
at org.hibernate.internal.SessionImpl.fireUpdate(SessionImpl.java:786)
at org.hibernate.internal.SessionImpl.update(SessionImpl.java:778)
at org.hibernate.internal.SessionImpl.update(SessionImpl.java:774)
at com.epam.hhsystem.jpa.EventDaoImpl.update(EventDaoImpl.java:45)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
at $Proxy38.update(Unknown Source)
at com.epam.hhsystem.services.EventService.update(EventService.java:24)
at com.epam.hhsystem.services.EventService$$FastClassByCGLIB$53e1b6.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:698)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:631)
at com.epam.hhsystem.services.EventService$$EnhancerByCGLIB$66fd26.update(<generated>)
at com.epam.hhsystem.web.controllers.EventMenuController.updateEvent(EventMenuController.java:164)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:219)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:132)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:745)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:686)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:80)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:925)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:856)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:936)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:838)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:647)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:812)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:118)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:84)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:113)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:103)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:113)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:54)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:45)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:183)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:105)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:259)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:947)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1009)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:312)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:662)
UPDATE 2
更新 2
I noticed, that I have no problem if I write change mapping Vacancy in Event:
@ManyToMany(/*cascade = CascadeType.ALL,*/ fetch = FetchType.EAGER)// I comment cascade
public Set<Vacancy> getVacancies() {
return vacancies;
}
Why? for simmetrical entity Candidate this mapping works:
为什么?对于 simmetrical entity Candidate 这个映射有效:
@ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
public Set<Candidate> getCandidates() {
return candidates;
}
If I delete relation between Event and Vacancy in initally code variant- it works good
如果我在初始代码变体中删除 Event 和 Vacancy 之间的关系-效果很好
If I delete relation between Event and Candidate in initally code variant- it DON'T works
如果我在初始代码变体中删除 Event 和 Candidate 之间的关系 - 它不起作用
回答by Ralph
Try to merge the vacancies with the current transaction, before you use it.
在使用之前,尝试将空缺与当前交易合并。
@PersistenceContext
EntityManager entityManager;
...
public String updateEvent(Model model,
@Valid @ModelAttribute("existedEvent") Event event,
BindingResult result,
@ModelAttribute("linkedCandidates") Set<Candidate> candidates,
@ModelAttribute("linkedvacancies") Set<Vacancy> vacancies) {
if (result.hasErrors())...
...
List<Vacancie> mergedVacancies = new ArrayList<>();
if (vacancies != null) {
for(Vacancie v : vacancies) {
mergedVacancies.add(entityManager.merge(v));
}
}
for (Vacancy vacancy : mergedVacancies ) {
vacancy.getEvents().add(event);
}
...
//Attention: mergedVacancies is not null like in the original code
event.setVacancies(mergedVacancies );
...
}
回答by Sachin Thapa
This happens if you are tring to save Two objest with same Id in same session.
如果您想在同一会话中保存具有相同 Id 的两个对象,则会发生这种情况。
First of all this should not happen try to find out why it is happening and avoid it. If it turns out to be requirement of a use case then try
首先,这不应该发生,试着找出它发生的原因并避免它。如果事实证明这是用例的要求,请尝试
session.merge
session.merge
Cheers !!
干杯!!