最近邊學邊用hibernate寫東西,然後出現各種問題,總結一下出現的問題及解決方法
在存在@OneToMany、@ManyToOne的情況報Table ‘table.A_B’ doesn’t exist異常
異常出現的背景:
排除真正的表不存在的因素外,該異常通常出現的情況如下:
create table a
(
id int primary key not null
);
create table b
(
id int primary key not null,
aID int not null,
foreign key(aID) references a(id)
)
就是這樣兩張簡單的表,下面是對應的實體類:
@Entity
@Table(name="a")
public class A{
@Id
@Column
private int id;
@OneToMany(cascade = CascadeType.ALL,fetch=FetchType.EAGER)
private Set<B> b;
...
}
@Entity
@Table(name="b")
public class B{
@Id
@Column
private int id;
@ManyToOne(cascade = CascadeType.ALL,fetch=FetchType.EAGER)
private A a;
...
}
異常出現原因:
如果實體類這樣寫的話,操作時候基本都會報這個錯,因爲這時它認爲是A、B類的關係是靠第三個表來維持,解決方法很簡答:
解決方法:
@Entity
@Table(name="a")
public class A{
@Id
@Column
private int id;
//加上mappedBy用於指定B類中哪個屬性作爲外鍵來保存關係
@OneToMany(cascade = CascadeType.ALL,mappedBy="a",fetch=FetchType.EAGER)
private Set<B> b = new HashSet<B>();
...
}
@Entity
@Table(name="b")
public class B{
@Id
@Column
private int id;
@ManyToOne(cascade = CascadeType.ALL,fetch=FetchType.EAGER)
//aID是數據庫表中對應的列名
@joinColumn(name="aID")
private A a;
...
}
關鍵是joincolumn和mappedby這兩個都不能漏
A different object with the same identifier value was already associated with the session
異常出現的背景:
信息是說session裏面出現多個有一樣identifier的對象,我出現這個錯誤時候是這樣:
create table A
(
id int primary key not null
);
create table B
(
id int primary key not null,
aid int not null,
foreign key(aid) references A(id)
);
create table C
(
id int primary key not null,
pbid int not null,
sbid int not null,
foreign key(pbid) references B(id),
foreign key(sbid) references B(id)
);
上面的表簡單表述爲:A有一個或者多個B,B和B之間存在父子(上下)關係,C表用於保存B的父子關係。
然後上面表對應的實體類如下:
@Entity
@Table(name="a")
public class A{
@Id
@Column
private int id;
@OneToMany(cascade=CascadeType.ALL,mappedBy="a",fetch=FetchType.EAGER)
private Set<B> bs = new HashSet<B>();
...
}
@Entity
@Table(name="b")
public class B{
@Id
@Column
private int id;
@ManyToOne(cascade=CascadeType.ALL)
@joinColumn(name="aid")
private A a;
@OneToMany(cascade=CascadeType.ALL,mappedBy="pb",fetch=FetchType.EAGER)
private Set<C> cOfP = new HashSet<C>();
@OneToMany(cascade=CascadeType.ALL,mappedBy="sb",fetch=FetchType.EAGER)
private Set<C> cOfS = new HashSet<C>();
...
}
@Entity
@Table(name="c")
public class C{
@Id
@Column
private int id;
@ManyToOne(cascade=CascadeType.ALL,fetch=FetchType.EAGER)
@joinColumn(name="pbid")
private B pb;
@ManyToOne(cascade=CascadeType.ALL,fetch=FetchType.EAGER)
@joinColumn(name="sbid")
private B sb;
...
}
下面爲測試類,也就是如下面運行時,會出現該異常:
//此處a已經存儲進數據庫,該表達式從庫中獲取a
A a = aRpertory.get();
//此處pb已經存儲進數據庫,該表達式從庫中獲取pb
//而且pb.a的信息與上面的a完全一樣:pb.a.getId() == a.getId()
B pb = bRepertory。get();
B sb = new B();
sb.setA(a);
C c = new C();
c.setPb(pb);
c.setSb(sb);
//調用session保存c
cRepertory.save(c);
異常出現原因:
結合異常的提示信息可以知道上面例子中出現異常的原因是:進行保存c的操作時,由於級聯(cascade=CascadeType.ALL),會自動操作與c相關聯的對象pb、sb,繼續由於級聯,會操作pb、sb相關聯的a。
而pb是從數據庫直接獲取、sb是引用新創建的a對象,實際上pb.a和sb.a裏面保存的信息是一樣的,這就導致了pb.a和sb.a是不同的對象(different object),但是有同樣的信息(with the same identifier value)
解決方法:
http://www.cnblogs.com/chenying99/archive/2012/05/10/2493630.html該博客介紹有3中方法。我這裏就只介紹其中一種吧:
很簡單就是在session操作之前,進行merge操作,如下:
Transaction transaction = session.getTransaction();
transaction.begin();
session.merge(object);
session.save(object);
transaction.commit();
P.S.這樣寫之後可能會引發另一個錯誤,就是下面這個錯誤
Multiple representations of the same entity […] are being merged. Detached:[…];Detached:[…]
異常出現的背景:
就上在解決上面的異常(添加了session.merge())後,出現了該異常
解決方法:
在配置文件上加上:
<property name="hibernate.event.merge.entity_copy_observer">allow</property>
Cannot use identity column key generation with mapping for
異常出現背景:
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class A{
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
}
@Entity
@Table(name="b")
public class B extends A{
}
@Entity
@Table(name="c")
public class C extends A{
}
我本意是A類不映射爲數據庫表,B、C類繼承A,並各自映射成表,而且主鍵均爲數據庫自動升成(auto_increment)
解決方法:
其實這個錯誤主要是父類A,定義上出現錯誤,如果不希望父類A映射成表,不應該用@Entity,而應該是@MappedSuperclass
@MappedSuperclass
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class A{
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
}