hibernate表關聯出現的異常及解決方法

最近邊學邊用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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章