Java Session.flush()未按预期工作

Java Session.flush()未按预期工作,java,spring,hibernate,Java,Spring,Hibernate,在服务类中,我有一个从@Transactional方法调用的方法。我已验证在调用此代码时有一个事务处于活动状态。我意识到我不应该有DA层,但我使用的是一个遗留应用程序,它使得以“正确”的方式做事变得非常麻烦,而不是现在的价值 映射如下所示: public class Foo { private String id; private Bar bar; @Id @Column(name = "FOO_ID", unique = true, nullable = false, le

在服务类中,我有一个从
@Transactional
方法调用的方法。我已验证在调用此代码时有一个事务处于活动状态。我意识到我不应该有DA层,但我使用的是一个遗留应用程序,它使得以“正确”的方式做事变得非常麻烦,而不是现在的价值

映射如下所示:

public class Foo {

  private String id;
  private Bar bar;

  @Id
  @Column(name = "FOO_ID", unique = true, nullable = false, length = 16)
  @GeneratedValue(generator = "blahIdSeq")
  @GenericGenerator(name = "blahIdSeq",
                    strategy = "org.blah.CustomIdGenerator")
  public String getId() {return id;}

  @JoinColumn(name = "FOO_ID")
  @OneToOne(fetch = FetchType.LAZY, optional = false)
  public Bar getBar() { return bar; }

  // SETTERS INCLUDED

}

public class Bar {
  private String id;
  private Foo foo;

  @Id
  @Column(name = "FOO_ID")
  @GeneratedValue(generator = "someSeq")
  @GenericGenerator(name = "someSeq",
                    strategy = "foreign",
                    parameters = {
                      @Parameter(name = "property", value = "foo")
                    })
  public String getId() { return id; }

  @OneToOne(fetch = FetchType.LAZY)
  @PrimaryKeyJoinColumn(name = "FOO_ID")
  public Foo getFoo() { return foo; }

  // SETTERS INCLUDED

}
public String createFoo(Foo foo) {
  Session ses = getSessionFactory().getCurrentSession();
  Bar bar = new Bar();
  bar.setFoo(foo);
  foo.setBar(bar);
  ses.save(foo);
  ses.save(bar);

  System.out.println(foo.getId()); // yields the ID value set by generator
  System.out.println(bar.getId()); // yields same ID value as above

  ses.flush();
  ses.refresh(foo);
}
方法如下所示:

public class Foo {

  private String id;
  private Bar bar;

  @Id
  @Column(name = "FOO_ID", unique = true, nullable = false, length = 16)
  @GeneratedValue(generator = "blahIdSeq")
  @GenericGenerator(name = "blahIdSeq",
                    strategy = "org.blah.CustomIdGenerator")
  public String getId() {return id;}

  @JoinColumn(name = "FOO_ID")
  @OneToOne(fetch = FetchType.LAZY, optional = false)
  public Bar getBar() { return bar; }

  // SETTERS INCLUDED

}

public class Bar {
  private String id;
  private Foo foo;

  @Id
  @Column(name = "FOO_ID")
  @GeneratedValue(generator = "someSeq")
  @GenericGenerator(name = "someSeq",
                    strategy = "foreign",
                    parameters = {
                      @Parameter(name = "property", value = "foo")
                    })
  public String getId() { return id; }

  @OneToOne(fetch = FetchType.LAZY)
  @PrimaryKeyJoinColumn(name = "FOO_ID")
  public Foo getFoo() { return foo; }

  // SETTERS INCLUDED

}
public String createFoo(Foo foo) {
  Session ses = getSessionFactory().getCurrentSession();
  Bar bar = new Bar();
  bar.setFoo(foo);
  foo.setBar(bar);
  ses.save(foo);
  ses.save(bar);

  System.out.println(foo.getId()); // yields the ID value set by generator
  System.out.println(bar.getId()); // yields same ID value as above

  ses.flush();
  ses.refresh(foo);
}
现在,当
org.hibernate.SQL
日志设置为
DEBUG
时,我可以看到为Foo和Bar创建了insert语句,但是调用flush后的刷新抛出一个
org.hibernate.unsolvableObjectException:不存在具有给定标识符的行
异常

这是什么原因造成的?使用的数据库是Oracle 11gR2

更新 我已将我的问题缩小到会议。调用
currentSession.flush()
似乎并没有按照刷新的预期将数据写入数据库。如果我注释掉该方法的其余部分,它将在最后提交,所有内容都将在数据库中

但是,执行刷新/刷新不会返回水合对象,因此我以后无法在事务中使用数据库填充值(由列默认值设置)。我也不能将事务拆分为多个事务,因为我需要能够在方法中的任何一点回滚

你知道为什么flush没有提供数据库中的可访问数据吗

另一个更新 我移动了很多代码只是为了尝试隔离这个问题,但我仍然有问题。我还摆脱了两个实体之间的关系,尝试手动处理所有事情,只是想看看这是否能解决问题。考虑到Steve的所有评论,以下是我现在得到的:

public class Foo {

  private String id;
  private Bar bar;

  @Id
  @Column(name = "FOO_ID", unique = true, nullable = false, length = 16)
  @GeneratedValue(generator = "blahIdSeq")
  @GenericGenerator(name = "blahIdSeq",
                    strategy = "org.blah.CustomIdGenerator")
  public String getId() {return id;}

  // SETTERS INCLUDED

}


又一次更新 在oracleland中进行了一番尝试,以确保SQL在同一个会话上运行,我发现了问题所在。尽管Hibernate正在记录正在设置SQL绑定变量,但它们实际上并没有设置。使用Oracle 11gR2的
V$SQL\u BIND\u CAPTURE
,我可以看到,使用最后执行的SQL ID(验证为insert语句)有24个绑定变量,其中没有一个绑定了值。仍然不确定是什么导致这些值为空,但我离找到答案还有一段距离。这一定是我的映射的问题,我不能把它全部放在这里

作为绑定变量,我猜Oracle不会因为无法插入而大发雷霆。JDBC通常只返回为
INSERT
语句插入的行数进行验证,但我不确定Hibernate抽象是如何处理这些内容的。我目前正在使用Hibernate 3.6.10——从3.6.5升级,看看它是否可以解决这个问题。它没有:P

我被误导了 忽略上面的“另一次更新”部分。在提交事务之前,绑定变量似乎不会显示在
V$SQL\u bind\u CAPTURE
视图中。回到绘图板上

另一次修订-我发誓我会被禁止的 我决定回到基础上来。自从它处于工作状态以来,我改变了什么?主要是映射。一些服务层项目也发生了更改,但主要是将Hibernate映射从XML移动到注释。因此,我采用了我一直在使用的相同服务方法,注释掉了所有其他内容,并尝试使用另一种持久对象类型来执行与我尝试使用
Foo
相同的操作。你猜怎么着?这很有效。此时唯一可能引起我心痛的链接是我对
Foo
的映射。我怀疑我的雇主是否希望我提供全部的信息来源,所以我可能不得不自己解决这个问题。当我最终找到答案时,我会以某种身份发布答案

成功!但我不知道为什么。。。 这是给我带来麻烦的代码。请记住,
BAZ
是一个链接表,其复合ID由一个
@embeddeble
(本例中仅称为“key”)组成,由引用
FOO
表中一行的
FOO ID
和引用另一个表的
STATE\u ID
组成

public class Foo {

  // OTHER FIELDS INCLUDING IDs AND SUCH

  private Baz bazOfDoom;
  private Baz bazOfLight;
  private Set<Baz> allTheBaz;

  @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.REFRESH)
  @JoinColumns({
    @JoinColumn(name = "FOO_ID", referencedColumnName = "FOO_ID", insertable = false, updatable = false, nullable = false)
    @JoinColumn(name = "DOOM_ID", referencedColumnName = "STATE_ID", insertable = false, updatable = false, nullable = false)
  })
  public Baz getBazOfDoom() { return bazOfDoom; }

  @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.REFRESH)
  @JoinColumns({
    @JoinColumn(name = "FOO_ID", referencedColumnName = "FOO_ID", insertable = false, updatable = false, nullable = false)
    @JoinColumn(name = "LIGHT_ID", referencedColumnName = "STATE_ID", insertable = false, updatable = false, nullable = false)
  })
  public Baz getBazOfLight() { return bazOfLight; }

  @OneToMany(mappedBy = "key.foo", fetch = FetchType.LAZY, cascade = CascadeType.REFRESH)
  public Set<Baz> getAllTheBaz() { return allTheBaz; }
}
公共类Foo{
//其他字段,包括ID等
私人商场;
私人照明;
私人设置allTheBaz;
@OneToOne(fetch=FetchType.LAZY,cascade=CascadeType.REFRESH)
@连接柱({
@JoinColumn(name=“FOO\u ID”,referencedColumnName=“FOO\u ID”,insertable=false,updateable=false,nullable=false)
@JoinColumn(name=“DOOM\u ID”,referencedColumnName=“STATE\u ID”,insertable=false,updateable=false,nullable=false)
})
public Baz getBazOfDoom(){return bazOfDoom;}
@OneToOne(fetch=FetchType.LAZY,cascade=CascadeType.REFRESH)
@连接柱({
@JoinColumn(name=“FOO\u ID”,referencedColumnName=“FOO\u ID”,insertable=false,updateable=false,nullable=false)
@JoinColumn(name=“LIGHT\u ID”,referencedColumnName=“STATE\u ID”,insertable=false,updateable=false,nullable=false)
})
public Baz getBazOfLight(){return bazOfLight;}
@OneToMany(mappedBy=“key.foo”,fetch=FetchType.LAZY,cascade=CascadeType.REFRESH)
public Set getAllTheBaz(){return allTheBaz;}
}

我移除了瀑布,它成功了。我不知道为什么。无论谁能解释这一点,我都会给他打上“正确答案”的分数

在将对象保存到数据库后,您的对象似乎不拥有对象的标识符,从而导致调用refresh()时出现异常

实际上,假设数据库表的主键定义为
自动递增
。因此,当保存第一个Foo对象时,主键列的值为:
1

然而,Hibernate必须意识到这一点
@GeneratedValue(strategy = GenerationType.AUTO)