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