hibernate中单向多对一的关联疑惑(管理员勿将帖子转到问答,那里不好交流)

本人初学hibernate,希望大家多多指教!

我假设person和card的多对一的关系(实际这两者的关系不是多对一)

他们对应的映射文件是:

person.hbm.xml

<!---->

<hibernate-mapping schema="hibernatequickuse">
<class name="mypack.person" table="person">
<id name="id" column="id" type="java.lang.Integer">
<generator class="identity">
</id>
<property name="name" column="name" type="java.lang.String" not-null="true"></property>
<many-to-one name="mycard" column="card_id" class="mypack.Card" cascade="all"></many-to-one>
</class>
</hibernate-mapping>



Card.hbm.xml

<!---->

<hibernate-mapping>
<class name="mypack.Card" table="card">
<id name="id" column="ID" type="java.lang.Integer">
<generator class="identity">
</id>
<property name="name" column="NAME" type="java.lang.String" not-null="true"></property>
</class>
</hibernate-mapping>



假设当我们先把many-to-one中的cascade属性值去掉,改为:

<many-to-one name="mycard" column="card_id" class="mypack.Card"></many-to-one>


然后执行如下代码:

  person p=new person();
p.setName("jack01");
Card c=new Card();
c.setName("card0031");
p.setMycard(c);
Session session=null;
Transaction tran=null;
try{
session=factory.openSession();
tran=session.beginTransaction();
session.save(p);//为什么是update,而不是Insert
tran.commit();
。。。。。。。



执行结果本来应该会报一个异常,因为只持久化了person对象。而card是临时对象,所以当hibernate自动清理缓存中的持久化对象时会发现p引用了c临时对象,而在person表中对应的card_id字段值为0,这说明person持久化对象的状态和数据库的记录不一致,所以应该会抛出异常!但是它却并没有抛出异常,

而是插入了一条person记录,其card_id=0这是为什么???

Hibernate: insert into hibernatequickuse.person (name, card_id) values (?, ?)


当我把cascade="all"加上去之后,本来这时应该是先插入card记录,然后插入Person记录。但结果却是:

Hibernate: insert into hibernatequickuse.person (name, card_id) values (?, ?)
Hibernate: update card set NAME=? where ID=?


而且抛出异常,表示无法更新!这又是为什么????????

Exception executing batch: 
org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1


表结构如下:

-- 

-- 表的结构 card

CREATE TABLE card (
id int(11) NOT NULL auto_increment,
name varchar(20) collate latin1_general_ci NOT NULL,
PRIMARY KEY (id)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci AUTO_INCREMENT=7 ;

CREATE TABLE person (
id int(11) NOT NULL auto_increment,
name varchar(32) collate latin1_general_ci NOT NULL,
card_id int(11) unsigned NOT NULL,
PRIMARY KEY (id),
KEY card_id (card_id)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci AUTO_INCREMENT=4 ;



POJO如下:

person

package mypack;
public class person implements java.io.Serializable{
private int id;
private String name;
private Card mycard;

public person(){

}
private void setId(int id){
    this.id=id;
}
public void setName(String name){
    this.name=name;
}
public void setMycard(Card mycard){
    this.mycard=mycard;
}
public int getId(){
    return this.id;
}
public String getName(){
    return this.name;
}
public Card getMycard(){
  return this.mycard;
}

}





Card

package mypack;

public class Card {
private int id;
private String name;

public Card(){

}
public void setId(int id){
this.id=id;
}
public void setName(String name){
this.name=name;
}
public String getName(){
return this.name;
}
public int getId(){
return this.id;
}
}






问题补充
补充下:我是参照网友的教程来做的,地址是:http://ryanpoy.iteye.com/blog/189783

奇怪的是他的结果是正确的!程序里面唯一不同的是我主键的设置上,我用的是auto_increment,映射xml中用的是identity!




问题补充:
谢谢kulinglei的回答,问题是我将cascade="save-update"; 它也没报任何异常啊,正常的情况应该是会报你所说的异常啊 !我把源码上传下,能帮我看看吗?
问题补充:
这是源码,希望大家帮帮忙!
问题补充:
谢谢etank帮忙,但我也用的是hibernate3的包,并且把identity改为了native。把cascade设为none,结果还是没报任何异常啊?我用的是mysql的数据库

6个回答

晕,排版不象我想象的,反而搞乱了
区别是,原文用的hibernate3
http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd
lz用的hibernate2
http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd

楼主你没有在数据库设置外键约束关系

[code="java"]






[/code]

你去掉cascade="all,并不代表没有级联了,当你不写时他有个默认的级联cascade="save_update",你不想要级联可以指明cascade="none";

org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1
出现这样的异常一般是更新Id不存在(在数据库中没有),

我用hibernate3测试了下,如果不写cascade的话,会报错,因为你的表定义中用了not null,

而card表不会被提前创建出来,加了cascade之后存储数据正常,先insert card表再insert person表
[code="java"]
Hibernate: insert into CARD values ( )
Hibernate: insert into PERSON (CARD_ID) values (?)
[/code]
identity属性只能在支持auto_increment的数据库时使用,意思是id由数据库控制自增长,但是象oracle就需要用到sequence,所以一般使用native属性比较安全,移植性也比较好,hibernate会自己根据数据库类型来选择怎么生成id,不过看lz的表一定有可能是mysql,这个属性是有效的
以上都是基于hibernate3测试的结果,手头没有hibernate2的jar包,所以没有测试

啊,对了,我刚才看了下lz说的原文,在hibernate映射文件头使用的和我测试用的一样,都是
[code="java"]
http://hibernate.sourceforge.net/hibernate-mapping-[color=red]3.0[/color].dtd
[/code]
而lz的映射文件头为
[code="java"]
http://hibernate.sourceforge.net/hibernate-mapping-[color=red]2.0[/color].dtd
[/code]
有可能是版本问题,至于到底hibernate2到3之间改了什么,我就不清楚了,抱歉哈

Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
立即提问