Java @事务性带注释的方法有时会引发非UniqueObjectException
我有以下Java @事务性带注释的方法有时会引发非UniqueObjectException,java,hibernate,transactions,Java,Hibernate,Transactions,我有以下@Transactional方法,该方法由HibernateTransactionManager管理: @Transactional(rollbackFor = NoActiveTraceException.class) public void insertTraceEvent(TraceEvent traceEvent) throws NoActiveTraceException { Trace trace = traceDao.findActiveForNumber(trac
@Transactional
方法,该方法由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
(并且可能persistent
traceEvent)。然后,当我调用create(traceEvent)
时,它可能也会尝试持久化它,从而在Hibernate会话中添加相同的对象
为什么会发生异常,为什么会以这样的随机间隔发生异常
编辑实体
@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;
及
@实体
@表(name=“TRACE”)
公共类跟踪{
@身份证
@GenericGenerator(name=“generator”,strategy=“increment”)
@GeneratedValue(generator=“generator”)
@列(name=“trace\u id”)
私有长traceId;
@列(nullable=false)
私有字符串编号;
@列(nullable=false)
私人日历开始日期;
@纵队
私人日历结束日期;
@列(nullable=false)
私有布尔值isActive=false;//默认值为false
//过去是瀑布式的
@OneToMany(fetch=FetchType.LAZY,cascade={CascadeType.REMOVE},mappedBy=“trace”)
私有集traceEvents=new HashSet();
@许多酮
私人帐户;
自从我上次使用Hibernate已经有一段时间了,这个问题很难解决,所以我只介绍各种选项:
- 由于您的
跟踪
对象具有一个级联。所有
选项仅在集合中添加跟踪事件
并调用会话。保存(跟踪)就足够了
?现在,我的印象是,当会话关闭时,它将尝试保存跟踪
对象。或者避免修改集合。只需保存跟踪事件
。您不会返回任何要使用的跟踪
,因此修改它没有意义。下次使用它时,它可能会从数据库。所有上述行为可能取决于您的配置,但可能值得一看
- 您是否使用某种hibernate缓存?是否可能是
跟踪
对象可能不是最新版本
TraceEvent
是如何创建的?是否该对象已分离(在以前的请求中加载,现在重新使用?)这似乎不大可能,但请检查
- 这似乎是一个可以从多个地方调用的函数(即,记录用户的操作)。是否有可能其他地方正在使用相同的会话并可能对其进行修改
- 假设它是从许多地方调用的,您是否能够从日志中将错误与某些特定的业务功能联系起来(例如,当用户单击该链接/按钮等)
- 如果所有其他操作都失败,为什么不尝试在下次更新生产环境时在持久化事件上添加一个
EventListener
或拦截器
(我知道您无法轻松复制此错误)。这将是一个简单的捕获ununiqueobjectexception
的方法,它可以打印额外的日志信息,然后重新抛出
你检查过了吗?@c.s只查看了最上面的答案。这可能与级联有关,但我仍然不明白为什么会偶尔发生。你能发布有关实体的更多详细信息吗?hbm文件或注释类会很有用。@Joe Yup,发布了实体。底层SQL实现是什么,它是在一个cluste中r?我觉得这实际上不是级联问题,而是刷新问题。生成器策略可能不应该是递增的,而应该是表策略或本机策略。我将尝试您的第一点和最后一点。其他方面:我不使用Hibernate缓存。TraceEvent是以POJO样式创建的。这一切都发生在@Transac中在计划执行器中发生的异常
块。我还将Cascade.All
更改为Cascade.Remove
。
@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;