/// Hibernate: /// 一对一关联有两种关联方式,即:主键关联和外键关联。 Member类: public class Member { private String id; private String name; private Integer age; private IdCard card;// ....... } IdCard类: public class IdCard { private String id; private String num; private Member member; ........ } 先对这两个类解释一下,Member类代表人员,IdCard类代表了身份证,这在现实中也是一对一的关系。 /// 1、主键关联 Member. hbm.xml的主要片段如下: <hibernate-mapping package="org.louis.domain"> <class name="Member" table="TEST_MEMBER"> <id name="id" column="ID"> <generator class="uuid.hex"></generator> </id> <property name="age" column="AGE"></property> <property name="name" column="NAME"></property> <one-to-one name="card" class="IdCard" cascade="all"></one-to-one> ......... </class> </hibernate-mapping> IdCard.hbm.xml的配置如下: <hibernate-mapping package="org.louis.domain"> <class name="IdCard" table="TEST_IDCARD"> <id name="id" column="ID"> <generator class="foreign"><!--使用主键关联,引用Member对应表的主键作为自己的主键--> <param name="property">member</param><!--此处的member必须和下面配置的one-to-one的name属性一样 --> </generator> </id> <property name="num" column="NUM"></property> <one-to-one name="member" class="Member" constrained="true"></one-to-one> </class> </hibernate-mapping> 至此,所有的配置工作已经完成。 测试进行测试: a、新增数据 public void insert() { Session session = HibernateSessionFactory.getSessionFactory().getCurrentSession(); session.beginTransaction(); Member m = new Member(); m.setAge(24); m.setName("Louis"); IdCard card = new IdCard(); card.setNum("123456789"); card.setMember(m);//设置Member和IdCard关系,以便IdCard可以从Member取得主键值 m.setCard(card);//设置Member和IdCard关系 session.save(m); session.getTransaction().commit(); } 后台Hibernate执行的SqlServer语句是: Hibernate: insert into TEST_MEMBER (AGE, NAME, ID) values (?, ?, ?) Hibernate: insert into TEST_IDCARD (NUM, ID) values (?, ?) 保存IdCard时使用IdCard对象中member对象的Id来为自己的Id赋值的。你现在可以查看数据库,里面两个表的主键值相同。 b、加载数据 public void getMemberById(String id) { Session session = HibernateSessionFactory.getSessionFactory().getCurrentSession(); session.beginTransaction(); Member m = (Member)session.load(Member.class, id); System.out.println(m); session.getTransaction().commit(); } 后台Hibernate执行的Sql语句是: select member0_.ID as ID5_1_, member0_.AGE as AGE5_1_, member0_.NAME as NAME5_1_, idcard1_.ID as ID4_0_, idcard1_.NUM as NUM4_0_ from TEST_MEMBER member0_ left outer join TEST_IDCARD idcard1_ on member0_.ID=idcard1_.ID where member0_.ID=? 可以看出默认采用的左外连接(左边表的所有行在右边没有得到匹配,那么右边表设置为null)的查询。 如果把Member.hbm.xml中做些改动如: <one-to-one name="card" class="IdCard" fetch="select" cascade="all"></one-to-one> 再次执行查询Sql语句如下: Hibernate: select member0_.ID as ID5_0_, member0_.AGE as AGE5_0_, member0_.NAME as NAME5_0_ from TEST_MEMBER member0_ where member0_.ID=? Hibernate: select idcard0_.ID as ID4_0_, idcard0_.NUM as NUM4_0_ from TEST_IDCARD idcard0_ where idcard0_.ID=? 可以看出生成了两条SQL语句,明显要比一条的性能低一些。 c、删除操作 Hibernate: select member0_.ID as ID5_0_, member0_.AGE as AGE5_0_, member0_.NAME as NAME5_0_ from TEST_MEMBER member0_ where member0_.ID=? Hibernate: select idcard0_.ID as ID4_0_, idcard0_.NUM as NUM4_0_ from TEST_IDCARD idcard0_ where idcard0_.ID=? Hibernate: delete from TEST_IDCARD where ID=? Hibernate: delete from TEST_MEMBER where ID=? 前两条Sql语句是加载Member和关联的IdCard对象。由于在测试加载数据时改变了抓取数据方式为fetch="select"所以生成了两条, 如果改为默认(fetch="join")则只生成一条,并且采用的是左外连接方式。在删除代码中,我只是删除了Member,但是查看数据库和 后台的SQL语句看出也把IdCard数据删除了,这是因为我在Member.hbm.xml中的<one-to-one>设置了cascade="all"。如果不 设置(默认为“none”),则只会删除Member对象,而不会级联删除IdCard对象。 注意:在这个例子中,一定要注意添加数据、删除数据的先后顺序。添加数据必须先添加Member(因为IdCard的主键由Member而来), 删除数据必须先删除IdCard(因为在IdCard.hbm.xml中设置了constrained="true"而使得两个表之间有了约束)。 2、外键关联 使用外键关联,我们还是使用这两个POJO类,只是其映射文件有所调整。调整后的映射文件如下: Member.hbm.xml: <hibernate-mapping package="org.louis.domain"> <class name="Member" table="TEST_MEMBER"> <id name="id" column="ID"> <generator class="uuid.hex"></generator> </id> <property name="age" column="AGE"></property> <property name="name" column="NAME"></property> <one-to-one name="card" class="IdCard" fetch="join" cascade="all" property-ref="member"></one-to-one> ...... </hibernate-mapping> IdCard.hbm.xml: <hibernate-mapping package="org.louis.domain"> <class name="IdCard" table="TEST_IDCARD"> <id name="id" column="ID"> <generator class="uuid.hex"></generator> </id> <property name="num" column="NUM"></property> <many-to-one name="member" class="Member" unique="true" column="MEMBER_ID"></many-to-one> </class> </hibernate-mapping> 依然采用上面的测试代码进行测试: a、插入数据 后台Hibernate执行的SQL语句 Hibernate: insert into TEST_MEMBER (AGE, NAME, ID) values (?, ?, ?) Hibernate: insert into TEST_IDCARD (NUM, MEMBER_ID, ID) values (?, ?, ?) IdCard的外键来自Member的主键。 b、加载数据 同上 c、删除数据 同上