-1

我有以下@Transactional由 a 管理的方法HibernateTransactionManager

@Transactional(rollbackFor = NoActiveTraceException.class)
public void insertTraceEvent(TraceEvent traceEvent) throws NoActiveTraceException {
    Trace trace = traceDao.findActiveForNumber(traceEvent.getSourceParty());
    if (trace == null) {
        throw new NoActiveTraceException(traceEvent.getSourceParty()); // custom
    } else {
        traceEvent.setTrace(trace);
        trace.getTraceEvents().add(traceEvent); // returns set to which I can add
        // there is a Cascade.All on the @OneToMany set

        traceDao.create(traceEvent);
    }
}

// ...in traceDao
@Override
public Long create(TraceEvent traceEvent) {
    getCurrentSession().persist(traceEvent);
    return traceEvent.getTraceEventId();
}

Trace并且TraceEvent是由 Hibernate 管理的实体。

当我在开发过程中测试这段代码时,我从来没有遇到任何问题。但是在生产中,它会不时抛出

org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session: [myobject#2664] 
at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:180) ~[hibernate-core-4.1.9.Final.jar:4.1.9.Final]
at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:136) ~[hibernate-core-4.1.9.Final.jar:4.1.9.Final]
at org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:208) ~[hibernate-core-4.1.9.Final.jar:4.1.9.Final]
at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:151) ~[hibernate-core-4.1.9.Final.jar:4.1.9.Final]
at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:78) ~[hibernate-core-4.1.9.Final.jar:4.1.9.Final]
at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:843) ~[hibernate-core-4.1.9.Final.jar:4.1.9.Final]
at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:818) ~[hibernate-core-4.1.9.Final.jar:4.1.9.Final]
at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:822) ~[hibernate-core-4.1.9.Final.jar:4.1.9.Final]
at com.package.model.dao.impl.TraceDaoHibernateImpl.create(TraceDaoHibernateImpl.java:116) ~[TraceDaoHibernateImpl.class:na]

当试图坚持它时。我想不出会导致这种情况的 prod 和 dev 之间的任何区别。此过程独立于一切(并在事务中运行)。

我知道,一旦我调用.add(traceEvent),它就会弄脏PersistentSet(并且可能会persist弄脏 traceEvent)。然后当我调用它时create(traceEvent),它也可能会尝试persist它,从而在 Hibernate Session 中添加相同的对象。

为什么会发生异常,为什么会以这样的随机间隔发生?

编辑实体

@Entity
@Table(name = "TRACE_EVENT")
@Inheritance(strategy = InheritanceType.JOINED)
public abstract class TraceEvent {
    @Id
    @GenericGenerator(name = "generator", strategy = "increment")
    @GeneratedValue(generator = "generator")
    @Column(name = "trace_event_id")
    private Long traceEventId;

    @Column(nullable = false)
    private Calendar transmissionDate;

    @Column(nullable = false)
    private String sourceParty; 

    @Column
    private String destinationParty;

    @ManyToOne(optional = false)
    @JoinColumn(name = "trace_id")
    private Trace trace;

@Entity
@Table(name = "TRACE")
public class Trace {
    @Id
    @GenericGenerator(name = "generator", strategy = "increment")
    @GeneratedValue(generator = "generator")
    @Column(name = "trace_id")
    private Long traceId;

    @Column(nullable = false)
    private String number;

    @Column(nullable = false)
    private Calendar startDate;

    @Column
    private Calendar endDate;   

    @Column(nullable = false)
    private Boolean isActive = false; // default value of false

    // USED TO BE CASCADE.ALL
    @OneToMany(fetch = FetchType.LAZY, cascade = {CascadeType.REMOVE}, mappedBy = "trace")
    private Set<TraceEvent> traceEvents = new HashSet<>();  

    @ManyToOne
    private Account account;
4

1 回答 1

1

自从我上次使用 Hibernate 已经有一段时间了,这个问题很困难,所以我将描述各种选项:

  • 由于您的Trace对象有一个选项,因此仅在集合上添加并调用就Cascade.All足够了吗?就像现在一样,我的印象是,当会话关闭时,它会尝试保存对象。或者避免修改集合。只需保存. 你不会再被使用,所以修改它没有意义。下次使用时,可能会从数据库中加载。以上所有行为可能取决于您的配置,但可能值得一看。TraceEventsession.save(trace)TraceTraceEventTrace

  • 你使用某种休眠缓存吗?会不会是某个Trace对象可能不是最新版本?

  • 是如何TraceEvent创建的?是否该对象已分离(在先前的请求中加载并现在重新使用?)这似乎不太可能,但请检查。

  • 这似乎是一个可以从许多地方调用的函数(即记录用户的操作)。是否有可能其他地方之一正在使用相同的会话并可能对其进行修改?

  • 假设从许多地方调用它,您是否能够从日志中将错误与某些特定的业务功能联系起来(例如,当用户单击该链接/按钮等时)?

  • 如果所有其他方法都失败了,为什么不尝试在下次更新生产环境时添加一个EventListener或一个on persist 事件(我知道您不能轻易复制此错误)。Interceptor这将是一个简单的捕获NonUniqueObjectException它可以打印额外的日志信息,然后重新抛出

于 2013-07-19T20:25:58.793 回答