7

我有一个小问题,我不知道如何解决。请问你能帮帮我吗?当我试图持久化实体时,我得到下一个异常:

12:47:39,398 ERROR [org.black.dmitriy.entityHome.ScheduleHome] (http--127.0.0.1-8080-1)  javax.persistence.EntityExistsException: a different object with the same identifier value was already associated with the session: [org.black.dmitriy.entity.Schedule#1]
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1333) [hibernate-entitymanager-4.0.1.Final.jar:4.0.1.Final]
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1289) [hibernate-entitymanager-4.0.1.Final.jar:4.0.1.Final]
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1295) [hibernate-entitymanager-4.0.1.Final.jar:4.0.1.Final]
at org.hibernate.ejb.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:859) [hibernate-entitymanager-4.0.1.Final.jar:4.0.1.Final]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) [rt.jar:1.7.0_04]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) [rt.jar:1.7.0_04]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) [rt.jar:1.7.0_04]
at java.lang.reflect.Method.invoke(Method.java:601) [rt.jar:1.7.0_04]
at org.jboss.seam.persistence.EntityManagerInvocationHandler.invoke(EntityManagerInvocationHandler.java:46) [jboss-seam.jar:2.3.0.Final]
at $Proxy81.persist(Unknown Source) at org.jboss.seam.framework.EntityHome.persist(EntityHome.java:84) [jboss-seam.jar:2.3.0.Final]
at org.black.dmitriy.entityHome.ConversationHome.tryPersist(ConversationHome.java:147) [ejb.jar:]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) [rt.jar:1.7.0_04]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) [rt.jar:1.7.0_04]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) [rt.jar:1.7.0_04]
at java.lang.reflect.Method.invoke(Method.java:601) [rt.jar:1.7.0_04]
at org.jboss.seam.util.Reflections.invoke(Reflections.java:22) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.intercept.RootInvocationContext.proceed(RootInvocationContext.java:32) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:56) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.transaction.RollbackInterceptor.aroundInvoke(RollbackInterceptor.java:28) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:68) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.core.ConversationInterceptor.aroundInvoke(ConversationInterceptor.java:65) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:68) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.transaction.TransactionInterceptor$1.work(TransactionInterceptor.java:97) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.util.Work.workInTransaction(Work.java:61) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.transaction.TransactionInterceptor.aroundInvoke(TransactionInterceptor.java:91) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:68) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.core.MethodContextInterceptor.aroundInvoke(MethodContextInterceptor.java:44) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:68) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.intercept.RootInterceptor.invoke(RootInterceptor.java:107) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.intercept.JavaBeanInterceptor.interceptInvocation(JavaBeanInterceptor.java:186) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.intercept.JavaBeanInterceptor.invoke(JavaBeanInterceptor.java:104) [jboss-seam.jar:2.3.0.Final]
at org.black.dmitriy.entityHome.ScheduleHome_$$_javassist_seam_8.tryPersist(ScheduleHome_$$_javassist_seam_8.java) [ejb.jar:]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) [rt.jar:1.7.0_04]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) [rt.jar:1.7.0_04]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) [rt.jar:1.7.0_04]
at java.lang.reflect.Method.invoke(Method.java:601) [rt.jar:1.7.0_04]
at org.jboss.el.util.ReflectionUtil.invokeMethod(ReflectionUtil.java:335) [jboss-el-1.0_02.CR6.jar:1.0_02.CR6]
at org.jboss.el.util.ReflectionUtil.invokeMethod(ReflectionUtil.java:348) [jboss-el-1.0_02.CR6.jar:1.0_02.CR6]
at org.jboss.el.parser.AstPropertySuffix.invoke(AstPropertySuffix.java:58) [jboss-el-1.0_02.CR6.jar:1.0_02.CR6]
at org.jboss.el.parser.AstValue.invoke(AstValue.java:96) [jboss-el-1.0_02.CR6.jar:1.0_02.CR6]
at org.jboss.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:276) [jboss-el-1.0_02.CR6.jar:1.0_02.CR6]
at com.sun.faces.facelets.el.TagMethodExpression.invoke(TagMethodExpression.java:105) [jsf-impl-2.1.7-jbossorg-2.jar:]
at javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:88) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
at com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:102) [jsf-impl-2.1.7-jbossorg-2.jar:]
at javax.faces.component.UICommand.broadcast(UICommand.java:315) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
at javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:794) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
at javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:1259) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
at com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:81) [jsf-impl-2.1.7-jbossorg-2.jar:]
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101) [jsf-impl-2.1.7-jbossorg-2.jar:]
at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118) [jsf-impl-2.1.7-jbossorg-2.jar:]
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:593) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:329) [jbossweb-7.0.13.Final.jar:]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:248) [jbossweb-7.0.13.Final.jar:]
at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:83) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.web.LoggingFilter.doFilter(LoggingFilter.java:60) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.web.IdentityFilter.doFilter(IdentityFilter.java:40) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.web.MultipartFilter.doFilter(MultipartFilter.java:90) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.web.ExceptionFilter.doFilter(ExceptionFilter.java:64) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.web.RedirectFilter.doFilter(RedirectFilter.java:45) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.web.HotDeployFilter.doFilter(HotDeployFilter.java:53) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.servlet.SeamFilter.doFilter(SeamFilter.java:158) [jboss-seam.jar:2.3.0.Final]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:280) [jbossweb-7.0.13.Final.jar:]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:248) [jbossweb-7.0.13.Final.jar:]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:275) [jbossweb-7.0.13.Final.jar:]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:161) [jbossweb-7.0.13.Final.jar:]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:397) [jbossweb-7.0.13.Final.jar:]
at org.jboss.as.jpa.interceptor.WebNonTxEmCloserValve.invoke(WebNonTxEmCloserValve.java:50) [jboss-as-jpa-7.1.1.Final.jar:7.1.1.Final]
at org.jboss.as.web.security.SecurityContextAssociationValve.invoke(SecurityContextAssociationValve.java:153) [jboss-as-web-7.1.1.Final.jar:7.1.1.Final]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:155) [jbossweb-7.0.13.Final.jar:]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102) [jbossweb-7.0.13.Final.jar:]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109) [jbossweb-7.0.13.Final.jar:]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:368) [jbossweb-7.0.13.Final.jar:]
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:877) [jbossweb-7.0.13.Final.jar:]
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:671) [jbossweb-7.0.13.Final.jar:]
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:930) [jbossweb-7.0.13.Final.jar:]
at java.lang.Thread.run(Thread.java:722) [rt.jar:1.7.0_04]

我使用Seam 2.3,休眠。我的 import.sql 文件中有一个插入语句:

INSERT INTO Schedules (id, name, dayCount, lessonCount, firstTermSize, secondTermSize, subgroupSize) VALUES(1, '2012/2013', 5, 8, 9, 9, 18)

它将一个实体插入到表 Schedules 中。

然后我使用 EntityHome 创建新的 Schedule 实体 throw 网页

@Name("scheduleHome")
@Scope(ScopeType.CONVERSATION)
public class ScheduleHome extends ConversationHome<Schedule> {
    private static final long serialVersionUID = 1L;

    public ScheduleHome() {
    }

    @Override
    protected boolean isUnique() {
        Schedule schedule = getInstance();
        Schedule foundSchedule = ScheduleDAO.instance().getByName(schedule.getName());

        if ((foundSchedule != null) && (!foundSchedule.equals(schedule))) {
            showExistsErrorMessage(getInstance().getName());
            return false;
        }

        return true;
    }

    @Override
    protected Schedule createInstance() {
        return new Schedule();
    }

    @Override
    public String getEditOutcome() {
        return "scheduleEdit";
    }

    @Override
    protected void prepareEntityForSaving() {

    }
}

和超类

public abstract class ConversationHome<T> extends EntityHome<T> {
    private static final long serialVersionUID = 1L;
    private String parentView;

    public boolean isParentViewExists() {
        return parentView != null && parentView.length() > 0;
    }

    public void setParentView(String parentView) {
        this.parentView = parentView;
    }

    public String getParentView() {
        return parentView;
    }

    public abstract String getEditOutcome();

    protected abstract void prepareEntityForSaving();

    protected abstract boolean isUnique();

    @Override
    @Create
    public void create() {
        create(false);
    }

    protected void create(boolean createNestedConversation) {
        Conversation conversation = Conversation.instance();
        if (!createNestedConversation && conversation.isLongRunning()) {
            getLog().debug("conversation already started, nested will not create(isLongRunning = #0, isNested = #1)", conversation.isLongRunning(), conversation.isNested());
        } else {
            conversation.begin(false, conversation.isLongRunning());
            conversation.changeFlushMode(FlushModeType.MANUAL);
            getLog().debug("create(isLongRunning = #0, isNested = #1, id = #2)", conversation.isLongRunning(), conversation.isNested(), conversation.getId());
        }
        super.create();
    }

    private boolean init(Long id) {
        FacesContext context = FacesContext.getCurrentInstance();
        setParentView(Pages.getViewId(context));

        if (id != null) {
            setId(id);
            try {
                getInstance();
                getLog().debug("instance initialized #0", getInstance());
            } catch (EntityNotFoundException e) {
                getLog().error(e);
                return false;
            }
        }
        return true;
    }

    public String startEdit(Long id) {
        getLog().debug("start editing #0", id);
        if (init(id)) {
            return getEditOutcome();
        } else {
            return cancel();
        }
    }

    public String cancel() {
        if (isManaged()) {
            getEntityManager().refresh(getInstance());
        }
        return returnToParent();
    }

    @End
    protected String returnToParent() {
         if (isParentViewExists()) {
                Conversation conversation = Conversation.instance();
                getLog().debug("end conversation(id = #0, isLongRunning = #1, isNested = #2)",
                        conversation.getId(), conversation.isLongRunning(), conversation.isNested());
                conversation.end(true);
                return getParentView();
            } else {
                clearInstance();
                return null;
            }
    }

    public String tryPersist() {
        if (isUnique()) {
            try {
                prepareEntityForSaving();

                String outcome = persist();
                if (!"failed".equals(outcome)) {
                    return returnToParent();
                }
            } catch (Exception e) {
                getLog().error(getInstance(), e);
                showSaveErrorMessage(e);
            }
        }
        return "failed";
    }
}

当我尝试坚持它时,我得到了这个例外。和网页上的消息

保存错误消息:具有相同标识符值的不同对象已与会话关联:[org.black.dmitriy.entity.Schedule#1]

它将休眠将 id 属性设置为 1,但我已经有了带有 的实体id = 1,因为我手动创建了它并抛出 import.sql。

这是我的 Schedule 实体:

import java.util.ArrayList;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.validation.constraints.NotNull;

@Entity
@Table(name = "Schedules")
public class Schedule {

    @Id
    @GeneratedValue
    @Column(name = "id", nullable = false)
    private Long id;

    @NotNull
    @Column(name = "name", nullable = false, length = 40)
    private String name;

    @Column(name = "dayCount")
    private int dayCount = 5;

    @Column(name = "lessonCount")
    private int lessonCount = 8;

    @Column(name = "firstTermSize")
    private int firstTermSize = 9;

    @Column(name = "secondTermSize")
    private int secondTermSize = 9;

    @Column(name = "subgroupSize")
    private int subgroupSize = 18;

    @OneToMany(mappedBy = "schedule", cascade = CascadeType.ALL, targetEntity = Faculty.class)
    private List<Faculty> faculties = new ArrayList<>();

    @OneToMany(mappedBy = "schedule", cascade = CascadeType.ALL, targetEntity = Building.class)
    private List<Building> buildings = new ArrayList<>();

    public Schedule() {

    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getDayCount() {
        return dayCount;
    }

    public void setDayCount(int dayCount) {
        this.dayCount = dayCount;
    }

    public int getLessonCount() {
        return lessonCount;
    }

    public void setLessonCount(int lessonCount) {
        this.lessonCount = lessonCount;
    }

    public int getFirstTermSize() {
        return firstTermSize;
    }

    public void setFirstTermSize(int firstTermSize) {
        this.firstTermSize = firstTermSize;
    }

    public int getSecondTermSize() {
        return secondTermSize;
    }

    public void setSecondTermSize(int secondTermSize) {
        this.secondTermSize = secondTermSize;
    }

    public int getSubgroupSize() {
        return subgroupSize;
    }

    public void setSubgroupSize(int subgroupSize) {
        this.subgroupSize = subgroupSize;
    }

    public List<Faculty> getFaculties() {
        return faculties;
    }

    public void setFaculties(List<Faculty> faculties) {
        this.faculties = faculties;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((id == null) ? 0 : id.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (!(obj instanceof Schedule)) {
            return false;
        }
        Schedule other = (Schedule) obj;
        if (id == null) {
            if (other.id != null) {
                return false;
            }
        } else if (!id.equals(other.id)) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        return this.name;
    }
}

如您所见,id属性上有@GeneratedValue注释,所以我认为hibernate应该自己生成id,hibernate应该知道数据库中有id = 1的实体,并在新实体中设置id = 2。但是Hibernate设置了id在新实体中到 1. 你能阻止我吗?

4

2 回答 2

17

问题是hibernate如何生成你id的,它从1开始。当它在将对象保存到数据库之前将1分配给对象时,它会看到数据库中已经存在具有相同id的行并导致异常。这个问题的简单而自然的解决方案是简单地限制休眠,以便它不能1作为 id 分配给相关类的任何对象(在您的情况下)。

mySql的解决方案:

如果您使用的是 mySql,您可以手动创建表并设置自动增量,例如:

  CREATE TABLE IF NOT EXISTS `testTable` (
      `id` number(11) NOT NULL AUTO_INCREMENT,
       ...,
       ...,
       ...,
       PRIMARY KEY (`id`)
 ) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=2; //assigning id by hibernate, will start from 2.

在您的域类中,您可以像下面这样注释 id:

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "ID")
public long getId() {
   ....
}

GenerationType.AUTO默认情况下在 mySql 中使用自动增量。并且在设置AUTO_INCREMENT=2休眠后将开始分配 id's from 2(因此1被跳过)。

甲骨文的解决方案:

如果您限制休眠使用“序列”并且您将序列的初始点设置为您的意愿,则可以对 oracle 执行相同的操作。您可以创建一个序列以开始2和递增,1如下所示:

 create sequence idSequence
        start with 2
        increment by 1
        maxvalue 9999999999999;

您可以指定要用于生成域类对象的 id 的序列,如下所示:

@Id
@SequenceGenerator(name = "idGeneratorSeq", sequenceName = "idSequence")
@GeneratedValue(strategy = GenerationType.AUTO, generator = "idGeneratorSeq")
@Column(name = "ID")
public long getId() {
   ....
}

你的问题已经解决了。

于 2012-12-10T18:25:12.050 回答
0

persist()在调用方法之前执行以下步骤。

首先分离您当前的实例

getEntityManager().detach(getInstance());

现在将其设置Id为空

getInstance().setId(null);

现在坚持

String outcome = persist();
于 2012-12-07T13:05:51.253 回答