这两天在研究hibernate,发现<<深入浅出hibernate>>一书挺好,清晰易懂,只是在看到one to one 主键关联映射的地方,有些疑惑。
关系模型是这样的,很简单,如下:
T_Person |
id number(11) <pk,fk> name varchar2(50) age number(3) ..... |
T_PASSPORT |
id number(11) <pk>, serial varchar2(20), expiry number(11) |
如上,T_Person的id即是主键又是外键,引用T_PASSPORT的主键字段id.并且它们是一对一的关系。
对应的实体类如下:
TPerson implents Serializable |
+TPerson |
id:Integer age:Integer name:String passport:TPassport |
TPassport implents Serializable |
+Tpassport |
id:Integer serial:String expiry:Integer person:Tperson |
实体关系如上,它们建立了双向一对一关系,具体映射文件如下:
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="com.alcatel.cn.hibernate.ORMapping.onetoone.pojo.TPerson" table="T_PERSON"> <id name="id" column="id" type="java.lang.Integer"> <generator class="sequence"> <param name="sequence">person_seq</param> </generator> </id> <property name="name" type="string" column="name"></property> <property name="age" type="java.lang.Integer" column="age"></property> <one-to-one name="passport" class="com.alcatel.cn.hibernate.ORMapping.onetoone.pojo.TPassport" cascade="all" outer-join="true"/> </class> </hibernate-mapping>
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="com.alcatel.cn.hibernate.ORMapping.onetoone.pojo.TPassport" table="T_PASSPORT"> <id name="id" column="id" type="java.lang.Integer"> <generator class="foreign"> <param name="property">person</param> </generator> </id> <one-to-one name="person" class="com.alcatel.cn.hibernate.ORMapping.onetoone.pojo.TPerson" constrained="true" ></one-to-one> <property name="serial" type="string" column="SERIAL"></property> <property name="expiry" type="java.lang.Integer" column="EXPIRY"></property> </class> </hibernate-mapping>
测试代码如下:
package com.alcatel.cn.hibernate.ORMapping.onetoone.test;
import org.hibernate.Session;
import org.hibernate.Transaction;
import com.alcatel.cn.hibernate.ORMapping.onetoone.pojo.TPassport;
import com.alcatel.cn.hibernate.ORMapping.onetoone.pojo.TPerson;
import com.alcatel.cn.hibernate.common.HibernateUtil;
public class Test {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Session s=HibernateUtil.currentSession();
TPerson p=new TPerson();
p.setAge(20);
p.setName("Sunrui");
TPassport passport=new TPassport();
passport.setSerial("PCN759386");
passport.setExpiry(new Integer(2));
//相互设置关联
passport.setPerson(p);
p.setPassport(passport);
try{
Transaction tx=s.beginTransaction();
s.save(p);//注意:这里只对Person进行保存
tx.commit();
TPassport pp=(TPassport)s.load(TPassport.class, new Integer(5));
System.out.println("Passport Serial ==>"+pp.getSerial());
System.out.println("Person name==>"+pp.getPerson().getName());
}catch(Exception e){
e.printStackTrace();
}
}
}
运行,出现如下异常:
Hibernate: select person_seq.nextval from dual
Hibernate: insert into T_PERSON (name, age, id) values (?, ?, ?)
org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:71)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:249)
at org.hibernate.jdbc.AbstractBatcher.prepareStatement(AbstractBatcher.java:92)
at org.hibernate.jdbc.AbstractBatcher.prepareStatement(AbstractBatcher.java:87)
at org.hibernate.jdbc.AbstractBatcher.prepareBatchStatement(AbstractBatcher.java:218)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2159)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2595)
at org.hibernate.action.EntityInsertAction.execute(EntityInsertAction.java:51)
at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:248)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:232)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:139)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:297)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:27)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1000)
at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:338)
at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:106)
at com.alcatel.cn.hibernate.ORMapping.onetoone.test.Test.main(Test.java:36)
Caused by: java.sql.BatchUpdateException: ORA-02291: integrity constraint (HIBERNATE.FK_PASSPORT) violated - parent key not found
仔细把自己的代码与书中的实例对照了下,发现没有任何差错,但确确实实发生异常了。仔细分析了下,这个异常是违反了约束性,第一想到的是违反了外键约束,看看日志(阴影部分),它确实是先往T_Person表里插入记录,当然找不到对应的T_Passport的id,违反了外键约束。
我尝试了把Person.hbm.xml与Passport.hbm.xml中配置方式互换,即让Passport.hbm.xml维护主键生成,然后Person.hbm.xml配置外键生成方式。运行完好。
这里,我从不怀疑<<深入浅出Hibernate>>作者的水平,他们确实都是比较牛的人物,也是我的偶像,像夏昕写的spring,hibernate等都是非常难得的好书。
所以,是不是我用的是hibernate3.0,而书本中用的是hibernate2.0等原因造成的?很迷茫。