Hibernate实体生成奇怪的sql并尝试保存重复的条目

时间:2012-01-12 05:02:21

标签: java sql hibernate

我有以下实体

@Entity
@Table(name="mail_event")
@Cacheable(false)
public class MailEvent extends DomainObject {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue
    private Long id;    

    @JoinTable(name="mail_event_recipients")
    @ManyToMany(fetch=FetchType.EAGER)
    private Set<User> recipients = new HashSet<User>();

    @Column(length=255)
    @Basic(optional=false)
    private String subject;

    @Column(length=255)
    @Basic(optional=false)
    private String fromName;

    @Column(length=255)
    @Basic(optional=false)
    private String fromEmail;

    @Lob
    @Basic(optional=false)
    private String messageBody;

    /*
     * Any users that should appear in the reply-to part of the email header are added here
     */
    @JoinTable(name="mail_event_reply_to")
    @ManyToMany(fetch=FetchType.EAGER)
    private Set<User> replyTo = new HashSet<User>();

    public MailEvent(){}

    public MailEvent(
                    final String subject,
                    final String messageBody,
                    final User recipient,
                    final String fromName,
                    final String fromEmail){
        this(subject,messageBody,recipient,fromName,fromEmail,null);
    }

    public MailEvent(
                    final String subject,
                    final String messageBody,
                    final Collection<User> recipients,
                    final String fromName,
                    final String fromEmail){
        this(subject,messageBody,recipients,fromName,fromEmail,null);
    }

    public MailEvent(
                    final String subject,
                    final String messageBody,
                    final User recipient,
                    final String fromName,
                    final String fromEmail,
                    final Collection<User> replyTo){
        this.subject = subject;
        this.messageBody = messageBody;
        this.recipients.add(recipient);
        this.fromName = fromName;
        this.fromEmail = fromEmail;
        if( replyTo != null )
            this.replyTo.addAll(replyTo);   
    }

    public MailEvent(           
                    final String subject,
                    final String messageBody,
                    final Collection<User> recipients,
                    final String fromName,
                    final String fromEmail,
                    final Collection<User> replyTo
                    ){
        this.subject = subject;
        this.messageBody = messageBody;
        this.recipients.addAll(recipients);
        this.fromName = fromName;
        this.fromEmail = fromEmail;
        if( replyTo != null )
            this.replyTo.addAll(replyTo);       

    }

    public Long getId() {
        return id;
    }

    public Set<User> getRecipients() {
        return recipients;
    }

    public void setRecipients(Set<User> recipients) {
        this.recipients = recipients;
    }

    public void setSubject(String subject) {
        this.subject = subject;
    }

    public String getSubject() {
        return subject;
    }

    public String getFromName() {
        return fromName;
    }

    public void setFromName(String fromName) {
        this.fromName = fromName;
    }

    public String getFromEmail() {
        return fromEmail;
    }

    public void setFromEmail(String fromEmail) {
        this.fromEmail = fromEmail;
    }

    public String getMessageBody() {
        return messageBody;
    }

    public void setMessageBody(String messageBody) {
        this.messageBody = messageBody;
    }

    public Set<User> getReplyTo() {
        return replyTo;
    }

    public void setReplyTo(Set<User> replyTo) {
        this.replyTo = replyTo;
    }

    @Override
    public int hashCode() {
        final int weight = 31;
        int result = 17;

        result = weight * result + ((id == null) ? 0 : (int) (id ^ (id >>> 32)));

        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (this.getClass() != obj.getClass())
            return false;

        MailEvent other = (MailEvent) obj;

        if (id == null) {
            if (other.id != null)
                return false;
        } else if (!id.equals(other.id))
            return false;

        return true;
    }



}

Hibernate从中生成以下表格:

为什么我得到相同的索引?此外,当我尝试保存此类的对象时,我得到以下异常:

2012 Jan 12 13:18:42,980[ERROR] - RequestCycle - Could not execute JDBC batch update; SQL [insert into mail_event_recipients (mail_event_id, recipients_id) values (?, ?)]; constraint [null]; nested exception is org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
org.springframework.dao.DataIntegrityViolationException: Could not execute JDBC batch update; SQL [insert into mail_event_recipients (mail_event_id, recipients_id) values (?, ?)]; constraint [null]; nested exception is org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
    at org.springframework.orm.hibernate3.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:637)
    at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:102)
    at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:471)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:754)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:723)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:393)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:120)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
    at $Proxy84.save(Unknown Source)
    at se.su.dsv.scipro.data.controllers.impl.NotificationControllerImpl.processNotification(NotificationControllerImpl.java:111)
    at se.su.dsv.scipro.data.controllers.impl.NotificationControllerImpl.notifyConferencePost(NotificationControllerImpl.java:181)
    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.apache.wicket.proxy.LazyInitProxyFactory$JdkHandler.invoke(LazyInitProxyFactory.java:414)
    at org.apache.wicket.proxy.$Proxy1.notifyConferencePost(Unknown Source)
    at se.su.dsv.scipro.conference.panels.ConferencePanel$SendWallMessageForm$1.onSubmit(ConferencePanel.java:324)
    at org.apache.wicket.ajax.markup.html.form.AjaxButton$1.onSubmit(AjaxButton.java:101)
    at org.apache.wicket.ajax.form.AjaxFormSubmitBehavior.onEvent(AjaxFormSubmitBehavior.java:143)
    at org.apache.wicket.ajax.AjaxEventBehavior.respond(AjaxEventBehavior.java:177)
    at org.apache.wicket.ajax.AbstractDefaultAjaxBehavior.onRequest(AbstractDefaultAjaxBehavior.java:302)
    at org.apache.wicket.request.target.component.listener.BehaviorRequestTarget.processEvents(BehaviorRequestTarget.java:157)
    at org.apache.wicket.request.AbstractRequestCycleProcessor.processEvents(AbstractRequestCycleProcessor.java:92)
    at org.apache.wicket.RequestCycle.processEventsAndRespond(RequestCycle.java:1250)
    at org.apache.wicket.RequestCycle.step(RequestCycle.java:1329)
    at org.apache.wicket.RequestCycle.steps(RequestCycle.java:1436)
    at org.apache.wicket.RequestCycle.request(RequestCycle.java:545)
    at org.apache.wicket.protocol.http.WicketFilter.doGet(WicketFilter.java:486)
    at org.apache.wicket.protocol.http.WicketFilter.doFilter(WicketFilter.java:319)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter.doFilterInternal(OpenEntityManagerInViewFilter.java:113)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298)
    at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:859)
    at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:588)
    at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)
    at java.lang.Thread.run(Thread.java:662)
Caused by: org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
    at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:96)
    at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
    at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:275)
    at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:263)
    at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:183)
    at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)
    at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51)
    at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1206)
    at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:375)
    at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:137)
    at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:76)
    at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:467)
    ... 44 more
Caused by: java.sql.BatchUpdateException: Duplicate entry '11642' for key 'PRIMARY'
    at com.mysql.jdbc.PreparedStatement.executeBatchSerially(PreparedStatement.java:2020)
    at com.mysql.jdbc.PreparedStatement.executeBatch(PreparedStatement.java:1451)
    at com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.executeBatch(NewProxyPreparedStatement.java:1723)
    at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:70)
    at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:268)
    ... 53 more

这让我相信Hibernate会尝试使用已经用于新对象的ID。我该如何解决这个问题?

编辑:问题似乎是由于某种原因,我不允许多次在mail_event_recipients中输入相同的recipients_id。为什么存在这种约束?如何摆脱它呢?

1 个答案:

答案 0 :(得分:0)

您无法添加重复的条目,因为它是一个Set

  

Hibernate注入的持久集合的行为类似于HashMap,HashSet,TreeMap,TreeSet或ArrayList,具体取决于接口类型。

     

集合实例具有值类型的通常行为

您可以使用ArrayList替换HashSet