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)