hibernate映射详解:一对一映射的两种实现方式

hibernate映射详解,这里是一对一映射的单讲:

本例采用phone和simcard实例:

phone和phone.hbm.xml:

Phone类:

package hibernate_onToOne;

public class Phone {
	private int id;
	private String name;
	//一对一映射时不要实例化,因为数据库中没有对应的表,hibernate不认识该对象
	//无法生成代理
	private SimCard simCard;
	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 SimCard getSimCard() {
		return simCard;
	}
	public void setSimCard(SimCard simCard) {
		this.simCard = simCard;
	}
	@Override
	public String toString() {
		return "Phone:  [id=" + id + ", name=" + name + "]";
	}
	
}

phone.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2016-4-3 16:12:29 by Hibernate Tools 3.4.0.CR1 -->
<hibernate-mapping package="hibernate_onToOne">
    <class name="Phone" table="phone">
        <id name="id" type="int">
            <column name="ID" />
            <generator class="native" />
        </id>
        <property name="name" type="string">
            <column name="name" />
        </property>
        <!--     一对一形式有两种实现方法:一种是基于外键的实现,然后在外键上加上unique约束,
        这种方式从有外键方可以解除关联,常用
                一种是基于主键引用的方式,不可以解除关联
 -->
       <!--  <one-to-one name="simCard" class="SimCard"  property-ref="phone">
            
            	采用基于外键的一对一映射方式,本方无外键方。
			property-ref属性:
				写的是对方映射中外键列对应的属性名
        </one-to-one> -->
        
        
        
 <!--        基于主键的一对一方式:
        采用基于主键的一对一映射方式,本方无外键方。 
        只需设置关联对象即可-->
        <one-to-one name="simCard" class="SimCard"></one-to-one>
    </class>
</hibernate-mapping>

SimCard和Simcard.hbm.xml:

SimCard类:

package hibernate_onToOne;

public class SimCard {
	private int id;
	private String number;
	//一对一映射时不要实例化,因为数据库中没有对应的表,hibernate不认识该对象
		//无法生成代理
	private Phone phone;
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getNumber() {
		return number;
	}
	public void setNumber(String number) {
		this.number = number;
	}
	public Phone getPhone() {
		return phone;
	}
	public void setPhone(Phone phone) {
		this.phone = phone;
	}
	@Override
	public String toString() {
		return "simCard [id=" + id + ", number=" + number + "]";
	}
}
SimCard.hbm.xml:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2016-4-3 16:12:29 by Hibernate Tools 3.4.0.CR1 -->
<hibernate-mapping package="hibernate_onToOne">
    <class name="SimCard" table="simcard">
        <id name="id" type="int">
            <column name="ID" />
            	<!-- 当使用基于主键的一对一映射时,
				有外键方的主键生成策略一定要是foreign。
				参数property:
					生成主键值时所根据的对象。
			 -->
            <generator class="foreign" >
                <param name="property">phone</param>
            </generator>
        </id>
        <property name="number" type="string">
            <column name="number" />
        </property>
    <!--     一对一形式有两种实现方法:一种是基于外键的实现,然后在外键上加上unique约束,
        这种方式从有外键方可以解除关联,常用:
      
        一种是基于主键引用的方式,不可以解除关联 -->
     <!--   <many-to-one name="phone" class="Phone" column="phoneID"  unique="true">
             表达的是本类与Phone的一对一。
			采用基于外键的一对一映射方式,本方有外键方,注意添加唯一约束
       </many-to-one> -->
       
       
       
    <!--    基于主键的一对一方式,双方都是one-to-one标签,
       constrained只能在one-to-one的映射中使用,(一般在主表的映射中,有外键的那个表)。
如果constrained=true, 则表明存在外键与关联表对应,并且关联表中肯定存在对应的键与其对应, 
另外该选项最关键的是影响save和delete的先后顺序。例如增加的时候,
如果constainted=true,则会先增加关联表,然后增加本表。 删除的时候反之。
       : -->
       <one-to-one name="phone" class="Phone" constrained="true"></one-to-one>
    </class>
</hibernate-mapping>
测试类:

package hibernate_onToOne;

import hibernate_manyeToMany.Student;
import hibernate_manyeToMany.Teacher;

import java.util.List;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.junit.Test;

/**
 * @author 梁磊
 *
 */
public class App {
	static SessionFactory sessionFactory;
	static{
		//初始化数据
		sessionFactory=new Configuration().configure()
				.addClass(Phone.class).addClass(SimCard.class)
				.buildSessionFactory();
	}
	@Test
	public void testSave() {
		//新建对像
	Phone phone=new Phone();
	phone.setName("小米");
	SimCard card=new SimCard();
	card.setNumber("12345566");
	//关联起来
	phone.setSimCard(card);
	card.setPhone(phone);
	//保存
	Session session=sessionFactory.openSession();
	session.beginTransaction();
	session.save(phone);
	session.save(card);
	session.getTransaction().commit();
	}
	@Test
	public void testGet() {
		//测试获取一方
		Session session=sessionFactory.openSession();
		session.beginTransaction();
		//获取PHone得到simcard
		Phone phone=(Phone) session.get(Phone.class, 1);
		System.out.println(phone);
		System.out.println(phone.getSimCard());
		//获取simcard得到phone
		/*SimCard simCard=(SimCard) session.get(SimCard.class, 1);
		System.out.println(simCard);
		System.out.println(simCard.getPhone());*/
		session.getTransaction().commit();
	}
	
	/**
	 * 测试解除关联关系
	 */
	@Test
	public void testRemove() {
		
		Session session=sessionFactory.openSession();
		session.beginTransaction();
		//从phone方解除关联
		//不会发生update语句,因为phone是外键方,不维护外键,所以解除关系只能从有外键方解除
		Phone phone=(Phone) session.get(Phone.class, 1);
		phone.setSimCard(null);
		//解除关系只能从有外键方解除关系,被引用方无法解除关联
	/*	SimCard simCard=(SimCard) session.get(SimCard.class, 1);
		simCard.setPhone(null);*/
		
		
		
		//当使用基于主键的关联方式时,由于主键无法为空,所以不会执行sql语句,当然也无法解除关联
		session.getTransaction().commit();
	}	
	/**
	 * 测试删除一方
	 */
	@Test
	public void testDelete() {
		Session session=sessionFactory.openSession();
		session.beginTransaction();
		//数据的删除,如果删除外键方会报错,凡是学过数据的同学都知道这点,所以当我们要删除外键方对象时,要先把引用置空才能删除
		//直接删除实惠报错的,所以我们只能这样删除
	/*	Phone phone=(Phone) session.get(Phone.class, 1);
		//session.delete(phone);
		//先把引用置空,这样就可以保证在删除phone的同时不会删除simcard
		phone.getSimCard().setPhone(null);
		session.delete(phone);*/
		//删除有外键方,直接会删除,delete from simcard where ID=?
		/*SimCard simCard=(SimCard) session.get(SimCard.class, 1);
		session.delete(simCard);*/
		
		
		//采用基于逐渐的一对一映射,所以可以从外键方删除
		SimCard simCard=(SimCard) session.get(SimCard.class, 1);
		session.delete(simCard);
		//当删除phone,由于simCard的主键是基于phone的主键生成的,所以删除phone的记录时由于有外键引用,就会报
	/*	Phone phone=(Phone) session.get(Phone.class, 1);
		session.delete(phone);*/
		session.getTransaction().commit();
	}
}

配置:

<!DOCTYPE hibernate-configuration PUBLIC
	"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
	"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

<hibernate-configuration>
	<session-factory>
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
		<property name="connection.url">jdbc:mysql:///test</property>
		<property name="connection.username">root</property>
		<property name="connection.password">root</property>
		
		<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
		<!-- 指定方言,指定mysql ,建议配置成上面,不然hibernate在执行创建表的时候会报错,目前没有找到原因-->
		<property name="hbm2ddl.auto">update</property><!-- -这个参数指定,hibernate可以更新数据,当为create时,hibernate每次执行插入操作都会先删除表,然后在创建表插入数据 -->
		<property name="show_sql">true</property><!-- -这个参数,表示,hibernate会把自动生成的参数,显示在控制台给我们看,一般用于开发阶段 -->
		<!-- 这个属性是设置事务隔离级别的
		1:表示读未提交
		2:表示读已提交
		4:可重复读
		8:串行化(不可并发) -->
		<property name="hibernate.connection.isolation">2</property>
	
	
		<!-- <mapping resource="com/leige/domain/User.hbm.xml"/> --><!-- -指定映射文件,告诉hibernate,对象与表的映射关系 -->
	
	</session-factory>
</hibernate-configuration>




你可能感兴趣的:(hibernate映射)