hibernate中单向一对一实现有三种方式:主键关联,外键关联,表关联(自己给的名字,下面会详细说的)。
场景设置:
学生 和 校服 。
我记得我初中的时候,校服忘记在操作了,有人捡到了,但是不知道是谁的,就送到体育办公室,
于是我pdpd的跑去自己拿。
我想说的是: 只能从学生来找到校服,而不能从校服去找到学生,这就是单向的关系。
上代码:
Student:
package com.iteye.endual.bean1;
public class Student {
private int id ;
private String name ;
private int num ;
private XiaoFu xf = new XiaoFu() ;
public Student() {
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public XiaoFu getXf() {
return xf;
}
public void setXf(XiaoFu xf) {
this.xf = xf;
}
}
校服类:
package com.iteye.endual.bean1;
public class XiaoFu {
private int id ;
private String owername ;
public XiaoFu() {}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getOwername() {
return owername;
}
public void setOwername(String owername) {
this.owername = owername;
}
}
hibernate的主配置文件:
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- Database connection settings -->
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql://localhost/test</property>
<property name="connection.username">root</property>
<property name="connection.password">数据库密码</property>
<!-- JDBC connection pool (use the built-in)
<property name="connection.pool_size">1</property>
-->
<!-- SQL dialect -->
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- Enable Hibernate's automatic session context management
<property name="current_session_context_class">thread</property>
-->
<!-- Disable the second-level cache
<property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
-->
<!-- Echo all executed SQL to stdout -->
<property name="show_sql">true</property>
<property name="format_sql">true</property>
<!-- Drop and re-create the database schema on startup -->
<property name="hbm2ddl.auto">create</property>
<!-- 用谁只能放谁的,他们的名字一样,要冲突的
<mapping resource="com/iteye/endual/bean1/Student.hbm.xml"/>
<mapping resource="com/iteye/endual/bean1/XiaoFu.hbm.xml"/>
-->
<mapping resource="com/iteye/endual/bean2/Student.hbm.xml"/>
<mapping resource="com/iteye/endual/bean2/XiaoFu.hbm.xml"/>
<mapping resource="com/iteye/endual/bean3/Student.hbm.xml"/>
<mapping resource="com/iteye/endual/bean3/XiaoFu.hbm.xml"/>
</session-factory>
</hibernate-configuration>
sessionFactory 的类,创建这样要花很大大大大大大的资源的哦
package util;
import org.hibernate.*;
import org.hibernate.cfg.*;
public class HibernateUtil {
private static final SessionFactory sessionFactory;
static {
try {
// Create the SessionFactory from hibernate.cfg.xml
sessionFactory = new Configuration().configure().buildSessionFactory();
} catch (Throwable ex) {
// Make sure you log the exception, as it might be swallowed
System.err.println("Initial SessionFactory creation failed." + ex);
throw new ExceptionInInitializerError(ex);
}
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
}
以下三种方式的单向一对一的实体已经创建好了,配置文件,sessionFactory的类以及好了,这个是公用的。
---------------------------------------------------------------------
第一种,外键关联,也是我们通常在学习数据库设计的时候用到的。
什么是外键关联:
就是在学生表中,加个外键,这个外键的值就是校服表的主键的值。
我们要查询学生,通过学生的主键查询,查到学生的信息,然后就能查到这个外键的值,根据这个值那么可以到
校服表中去查询校服的信息了。
hibernate是面向对象的,所以在个外键是不需要我们在实体中去设置的,需要在配置文件中进行配置的。
看配置文件:
student
<?xml version="1.0"?>
<!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.iteye.endual.bean2.Student" table="t_stu2">
<id name="id" column="stu_id"> <!-- 设置主键 -->
<generator class="native"/> <!-- 设置数据库主键的增长方式 -->
</id>
<property name="name" column="stu_name" />
<!-- <one-to-one name="card" foreign-key="idx" class="endual.bean.Card" >
</one-to-one>
-->
<many-to-one name="xf" class="com.iteye.endual.bean2.XiaoFu" column="fk_id" unique="true" cascade="all"></many-to-one>
</class>
</hibernate-mapping>
<many-to-one name="xf" class="com.iteye.endual.bean2.XiaoFu" column="fk_id" unique="true" cascade="all">
一对一的单向关系中,就是多对一的特殊情况,所以用到了many to one 的标签。这个标签有个属性是
unique="true",表示这个是一对一的关系。(为什么多开发一套标签来支持一对一呢, 弄 的这么麻烦要拿 别人的修改下。)
cascade="all" 这是表示级联的意思,就是主如此更新的话,那么连接它的也更新,删除也一样,插入也一样。
column="fk_id" 这个是设置了外键的名字,会自动插入到student的表中的去,这个就是校服表的外键,这个值就是校服 表主键的值。
校服表的配置文件:
<?xml version="1.0"?>
<!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.iteye.endual.bean2.XiaoFu" table="t_xiaofu2">
<id name="id" column="xiaofu_id"> <!-- 设置主键 -->
<generator class="native"/> <!-- 设置数据库主键的增长方式 -->
</id>
<property name="owername" column="stu_name" />
</class>
</hibernate-mapping>
junit测试:
package endual.bean2;
import java.util.List;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import com.iteye.endual.bean2.Student;
import com.iteye.endual.bean2.XiaoFu;
import util.HibernateUtil;
import junit.framework.TestCase;
public class TestHibernate extends TestCase {
/**
* 对个实体bean的存储
*/
public void test1 () {
SessionFactory sf = HibernateUtil.getSessionFactory() ;
Session session = sf.openSession() ;
XiaoFu xf = new XiaoFu() ;
//xf.setId(id)
xf.setOwername("chenwei");
Student st = new Student() ;
st.setName("chenwei");
st.setNum(123456) ;
st.setXf(xf) ;
session.save(st) ;
Transaction tr = session.beginTransaction() ;
tr.commit() ;
//System.out.println(pp.getCard().getIdnum());
}
}
测试结果:
生成了两张表:(见插入,其他学生表中多了一个外键的字段)
1. session.save(st) ; //保存st,也保存了xf,他们的级联是all. 成功
2. session.save(xf) ;
session.save(st) ; //成功
3. session.save(st) ; //成功
session.save(xf) ;
4.session.save(xf) ; //只插入了校服
增加查找和删除修改和级联的设置有很大的关系
========================================================
第二种方式就是主键关联,我们知道主键的值是唯一的,那么我们将两个表的主键的值是一样的,就可以了嘛。
我们用学生表的主键的值用的是校服表的主键。
这样我们查询学生的时候,就能查到校服的主键,而根据校服的主键我们就能查到校服的信息了。
上代码:
学生表的主键的生成的不能是递增了,我们要用到forein的策略。两张表的字段没有多出来,也只生成两张表。
学生的配置文件:
<?xml version="1.0"?>
<!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.iteye.endual.bean3.Student" table="t_stu3">
<id name="id" column="stu_id"> <!-- 设置主键 -->
<generator class="foreign"> <!-- 主键生成策略为foreign,根据关联类生成主键来产生主键的值 -->
<param name="property">xf</param>
</generator>
</id>
<property name="name" column="stu_name" />
<!-- <one-to-one name="card" foreign-key="idx" class="endual.bean.Card" >
</one-to-one>-->
<one-to-one name="xf" cascade="all" constrained="true"></one-to-one>
</class>
</hibernate-mapping>
<id name="id" column="stu_id"> <!-- 设置主键 -->
<generator class="foreign"> <!-- 主键生成策略为foreign,根据关联类生成主键来产生主键的值 -->
<param name="property">xf</param>
</generator>
</id>
这个配置中就是告诉框架,学生表的主键的值要用的是外面来的,这个外面就是xf这个属性关联的那个表
测试代码:
package endual.bean3;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import com.iteye.endual.bean3.Student;
import com.iteye.endual.bean3.XiaoFu;
import util.HibernateUtil;
import junit.framework.TestCase;
public class TestHibernate extends TestCase {
/**
* 对个实体bean的存储
*/
public void test1 () {
SessionFactory sf = HibernateUtil.getSessionFactory() ;
Session session = sf.openSession() ;
XiaoFu xf = new XiaoFu() ;
xf.setOwername("chenwei");
//xf.setId(4) ;
Student st = new Student() ;
st.setName("chenwei");
st.setNum(123456) ;
st.setId(7);
st.setXf(xf) ;
session.save(st) ;
Transaction tr = session.beginTransaction() ;
tr.commit() ;
}
}
测试结果:生成了两种张表(见插图)
测试:
1. session.save(st) ; //成功,两个表都插入了
2. session.save(xf) ; //很显然值插入了一个校服表
3. session.save(xf) ;
session.save(st) ; //两个表都插入了,而且值插入一条的
4. session.save(st) ;
session.save(xf) ; //两个表都插入了,而且只插入了一条的
居然的各自负责测试举例要看情况了
---------------------------------------------------------------------------------------
下面来到了我们的第三中方法,那就是再创建一张表,通过这个来创建单向的连接
我们这表是框架自动会建立的,我们在学生配置文件中设置改表的字段已经名字。
表中放的学生表的主键和校服表的主键,这样我们查找学生的时候,能查到主键,
查到主键,我们在这种表中能查找校服表的主键,这样就能通过校服表的主键,查到校服的信息了。
思路是这样的。
配置文件是:
student的配置文件
<?xml version="1.0"?>
<!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.iteye.endual.bean1.Student" table="t_stu1">
<id name="id" column="stu_id"> <!-- 设置主键 -->
<generator class="native"/> <!-- 设置数据库主键的增长方式 -->
</id>
<property name="name" column="stu_name" />
<!-- <one-to-one name="card" foreign-key="idx" class="endual.bean.Card" >
</one-to-one>-->
<join table="join_stu_xf1">
<key column="xf_id"></key>
<!-- 一对一 是 多对一的 一个特殊情况 -->
<many-to-one name="xf" class="com.iteye.endual.bean1.XiaoFu" unique="true" cascade="all"></many-to-one>
</join>
</class>
</hibernate-mapping>
<join table="join_stu_xf1"> 校服表的名字,字段是自动生成,也可以自己设置的
测试类:
package endual.bean1;
import java.util.List;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import com.iteye.endual.bean1.Student;
import com.iteye.endual.bean1.XiaoFu;
import util.HibernateUtil;
import junit.framework.TestCase;
public class TestHibernate extends TestCase {
/**
* 对个实体bean的存储
*/
public void test1 () {
SessionFactory sf = HibernateUtil.getSessionFactory() ;
Session session = sf.openSession() ;
XiaoFu xf = new XiaoFu() ;
xf.setOwername("chenwei");
Student st = new Student() ;
st.setName("chenwei");
st.setNum(123456) ;
st.setXf(xf) ;
session.save(st) ;
Transaction tr = session.beginTransaction() ;
tr.commit() ;
session.close() ;
}
public void test3 () {
SessionFactory sf = HibernateUtil.getSessionFactory() ;
Session session = sf.openSession() ;
String hql = "from Student as stu where stu.id=?" ;
Query query = session.createQuery(hql) ;
query.setInteger(0, 1) ;
List<Student> lists = query.list() ;
Student stu = lists.get(0) ;
System.out.println(stu.getName());
//用到了才会去查询的
System.out.println(stu.getXf().getOwername());
// Transaction tr = session.beginTransaction() ;
//tr.commit() ;
//System.out.println(pp.getCard().getIdnum());
}
}
测试结果,生成了三张表:
1.session.save(stu); 成功插入三个表都有数据
2.session.save(xf) ; //失败
3. session.save(xf) ;
session.save(st) ; //成功
4. session.save(st) ;
session.save(xf) ; //成功
------------------------
以上是三个方法的代码?
有一个点我搞不清楚的是,单向连接啊,这箭头是指向的是学生呢还是校服呢 ?呵呵。
本文介绍了Hibernate中实现单向一对一关联的三种方法:外键关联、主键关联及额外关联表方式,并提供了详细的代码示例。
1135

被折叠的 条评论
为什么被折叠?



