更新:让我澄清一点,我正在编写的应用程序基本上是一个批量处理器的输入文件.系统需要逐行读取文件并将记录插入数据库.文件格式基本上是在我们的模式中的几个表的非规范化视图,所以我要做的是解析父记录或将其插入到数据库中,以便我可以获得一个新的合成键,或者如果它已经存在选择它.然后我可以在其他表中添加额外的关联记录,这些表中有外键返回到该记录.
这个棘手的原因是,每个文件都需要完全导入,或者根本没有导入,即对于给定文件所做的所有插入和更新都应该是一个事务的一部分.如果只有一个进程正在进行所有导入,那么这很简单,但如果可能,我想在多个服务器上进行分解.由于这些限制,我需要能够保留在一个事务中,但是处理已经存在记录的异常.
父记录的映射类如下所示:
@Entity public class Foo { @Id @GeneratedValue(strategy = IDENTITY) private int id; @Column(unique = true) private String name; ... }
我最初尝试写这个方法如下:
public Foo findOrCreate(String name) { Foo foo = new Foo(); foo.setName(name); try { session.save(foo) } catch(ConstraintViolationException e) { foo = session.createCriteria(Foo.class).add(eq("name",name)).uniqueResult(); } return foo; }
问题是当我正在寻找的名称存在时,org.hibernate.AssertionFailure异常被调用到uniqueResult()抛出.完整的堆栈跟踪如下所示:
org.hibernate.AssertionFailure: null id in com.searchdex.linktracer.domain.LinkingPage entry (don't flush the Session after an exception occurs) at org.hibernate.event.def.DefaultFlushEntityEventListener.checkId(DefaultFlushEntityEventListener.java:82) [hibernate-core-3.6.0.Final.jar:3.6.0.Final] at org.hibernate.event.def.DefaultFlushEntityEventListener.getValues(DefaultFlushEntityEventListener.java:190) [hibernate-core-3.6.0.Final.jar:3.6.0.Final] at org.hibernate.event.def.DefaultFlushEntityEventListener.onFlushEntity(DefaultFlushEntityEventListener.java:147) [hibernate-core-3.6.0.Final.jar:3.6.0.Final] at org.hibernate.event.def.AbstractFlushingEventListener.flushEntities(AbstractFlushingEventListener.java:219) [hibernate-core-3.6.0.Final.jar:3.6.0.Final] at org.hibernate.event.def.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:99) [hibernate-core-3.6.0.Final.jar:3.6.0.Final] at org.hibernate.event.def.DefaultAutoFlushEventListener.onAutoFlush(DefaultAutoFlushEventListener.java:58) [hibernate-core-3.6.0.Final.jar:3.6.0.Final] at org.hibernate.impl.SessionImpl.autoFlushIfrequired(SessionImpl.java:1185) [hibernate-core-3.6.0.Final.jar:3.6.0.Final] at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1709) [hibernate-core-3.6.0.Final.jar:3.6.0.Final] at org.hibernate.impl.Criteriaimpl.list(Criteriaimpl.java:347) [hibernate-core-3.6.0.Final.jar:3.6.0.Final] at org.hibernate.impl.Criteriaimpl.uniqueResult(Criteriaimpl.java:369) [hibernate-core-3.6.0.Final.jar:3.6.0.Final]
有人知道是什么导致这个异常被抛出? hibernate是否支持更好的方式来实现?
让我先抢先解释为什么我先插入,然后选择是否和何时失败.这需要在分布式环境中工作,所以我无法通过检查进行同步,以查看记录是否已经存在并插入.最简单的方法是让数据库通过检查每个插入的约束违例来处理此同步.
解决方法
我正在使用Spring的TransactionTemplate,但是如果您不希望对Spring有依赖关系,我相信您可以轻松地进行翻译.
public T findOrCreate(final T t) throws InvalidRecordException { // 1) look for the record T found = findUnique(t); if (found != null) return found; // 2) if not found,start a new,independent transaction TransactionTemplate tt = new TransactionTemplate((PlatformTransactionManager) transactionManager); tt.setPropagationBehavior(TransactionDeFinition.PROPAGATION_REQUIRES_NEW); try { found = (T)tt.execute(new TransactionCallback<T>() { try { // 3) store the record in this new transaction return store(t); } catch (ConstraintViolationException e) { // another thread or process created this already,possibly // between 1) and 2) status.setRollbackOnly(); return null; } }); // 4) if we Failed to create the record in the second transaction,found will // still be null; however,this would happy only if another process // created the record. let's see what they made for us! if (found == null) found = findUnique(t); } catch (...) { // handle exceptions } return found; }
原文地址:https://www.jb51.cc/java/123794.html
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。