最近边学边用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;
}