java框架开发技术篇4---Hibernate数据关系映射

Hibernate数据关系映射

**

1 * 一对多/多对一**

① 场景
一个人可能有多个地址,在数据库中就可以建立两张表,一个是用户表,一个是地址表,为了反映这种关系,我们需要在地址表中保存该对应用的ID,从用户来讲一个用户就对应多个地址,这就是一对多的关系,从地址来讲,多个地址对应一个人,这就是多对一的关系。

② 数据库表的设计
在多方要保存一方的外键
在这里插入图片描述
③ Java实体类的设计
在多方保存一方的对象,(如果是双向的关联在一方保存多方的对象的Set集合)
注:一般情况下一张数据库表对应一个VO类
UserVo.java

public class UserVo {
	private int id;
	private String userName;
	private String password;
	private String email;
	//存放多个地址的集合
	private Set<AddressVo> adds;
//get/set方法
}

AddressVo.java

public class AddressVo {
	private int id;
	private String city;
	private String street;
	//存放用户的对象
	private UserVo user;
//get/set方法
}

④ Vo类相对应的映射文件的配置
UserVo.hbm.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <class name="com.xixw.vo.UserVo" table="user_table1">
    <!-- 映射主键 -->
    <id name="id" column="id">
       <!-- 设置主键的生成策略/用序列生成主键 -->
       <generator class="sequence">
           <!--指定生成主键的序列hibernate_sequence  -->
           <param name="sequence">hibernate_sequence</param>
       </generator>
    </id>
    <property name="userName" type="java.lang.String"></property>
    <property name="password"></property>
    <property name="email"></property>
    <!-- 配置地址集合 -->
    <set name="adds">
       	<!-- 多的一方存贮的外键的列名 -->
       	<key column="userid"></key>
       	<!-- 多的一方对应的类的完全限定名 -->
       	<one-to-many class="com.xixw.vo.AddressVo"/>
    </set>
   </class>
</hibernate-mapping> 

AddressVo.hbm.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <class name="com.xixw.vo.AddressVo" table="address_table1">
        <id name="id" column="id">
        	<generator class="sequence">
        		<param name="sequence">hibernate_sequence</param>
        	</generator>
        </id>
        <property name="city" />
        <property name="street"/> 
        <!-- name:指定地址类中的用户对象名称,class:指定用户类对象的完全限定名,column:指定数据库中外键名称 -->
        <many-to-one name="user" class="com.xixw.vo.UserVo" column="userid"></many-to-one>
    </class>
</hibernate-mapping>

⑤ 测试类进行测试

package com.xixw.test;
import java.util.HashSet;
import java.util.Set;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import com.xixw.vo.AddressVo;
import com.xixw.vo.UserVo;
public class ManyToOneTest {
	public static void main(String[] args) {
		Configuration cfg=new Configuration();
		cfg.configure();
		ServiceRegistry registry=new ServiceRegistryBuilder().applySettings(cfg.getProperties()).buildServiceRegistry();
		SessionFactory factory=cfg.buildSessionFactory(registry);
		Session session=factory.openSession();
		
		//4.获取session对象
		Session session=factory.openSession();
		Transaction tr=session.beginTransaction();
		
		UserVo user=new UserVo();
		user.setUserName("小军");
		user.setPassword("888888");
		user.setEmail("123@qq.com");
		
		Set<AddressVo> set=new HashSet<AddressVo>();
		AddressVo address=new AddressVo();
		address.setCity("西安");
		address.setStreet("郭杜街道");
		address.setUser(user);
		set.add(address);
		user.setAdds(set);
		
		session.save(user);
		session.save(address);
		tr.commit();
		session.close();
	}
}

⑥ 数据库表的创建
如果要自动生成数据库表,需要在hibernate的主配置文件中添加如下配置:

<!-- 设置是否自动创建表 -->
    	<property name="hibernate.hbm2ddl.auto">update</property>

update:代表如果数据库中没有表则进行创建,如果有,并且表的结构改变了,则进行更新,否则不变。
create:代表每次执行都会删除原来的表,创建新的表
none:不进行数据库表的自动创建

<!--inverse:设置维护关系,false:不放弃维护  true:代表放弃维护 
默认双方都维护,一般我们会设置让“多”的一方去维护,“一”的一方放弃维护
 -->
       		<set name="adds" inverse="true">
       			<!-- 多的一方存贮的外键的列名 -->
       			<key column="userid"></key>
       			<!-- 多的一方对应的类的完全限定名 -->
       			<one-to-many class="com.xixw.vo.AddressVo"/>
       		</set>

2. 一对一

场景
一个人对应一张身份证,一张身份证只能对应一个人
一对一映射关系分两种:主键关联和唯一外键关联
主键关联:两张表共用一个主键
唯一外键关联:特殊的多对一的关系

**

主键关联

**
① 主键关联数据库表的设计方案
从表的主键的生成关联的是主表的主键,从表的主键即是主键又是外键。
在这里插入图片描述
② 实体类设计方案
两个实体类中互存对象
PersonVo.java

public class PersonVo {
	private int id;
	private String name;
	//存放唯一对应的CardVo对象
	private CardVo card;
//get/set方法
}

CardVo.java

public class CardVo {
	private int id;
	private String cardNo;
	//存放唯一对应的PersonVo对象
	private PersonVo person;
//get/set方法
}

③ Vo类相对应的映射文件的配置
PersonVo.hbm.xml

<?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 package="com.xixw.OneToOne">
	<!-- 映射类和表 -->
	<class name="Person" table="person_t">
		<!-- 映射主键 -->
		<id name="id">
			<!-- 设置主键的生成策略 -->
			<generator class="increment"></generator>
		</id>
		<!-- 映射普通属性 -->
		<property name="name"></property>
		<!-- 配置映射关系 
			cascade:设置对象的级联操作
					delete:在执行删除操作的时候进行级联删除
					save-update:在执行保存或者更新的情况下进行级联操作
					all:在所有的情况下都会进行级联操作
					none:不进行级联操作(默认)。
			注意:尽量避免使用all进行级联,因为会降低程序的执行效率。
		-->
<!-- 设置一对一关系,name:对象中存放的CardVo对象的属性名 -->
		<one-to-one name="card" class="Card" cascade="all"></one-to-one>
	</class>
</hibernate-mapping>

CardVo.hbm.xml

<?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 package="com.bxit.OneToOne">
	<!-- 映射类和表 -->
	<class name="Card" table="card_t">
		<!-- 映射主键 -->
		<id name="id">
			<!-- 设置主键的生成策略,从表主键的生成方式必须要依赖于主表
				foreign:以外键的形式生成主键 -->
			<generator class="foreign">
				<!-- 指定外键的依赖的对象属性 -->
				<param name="property">person</param>
			</generator>
		</id>
		<!-- 映射普通属性 -->
		<property name="cardNo"></property>
		<!-- 映射对象 -->
		<one-to-one name="person" class="Person" cascade="all">
</one-to-one>
	</class>
</hibernate-mapping>

设置级联操作:cascade:save-update/delete/all/none

<!-- 设置级联策略cascade
all:在所有的情况下都进行级联操作
      save-update:只是在保存和更新的时候进行级联操作
      delete:只是在删除的时候进行级联操作
      none:不进行级联操作(默认)
      级联操作会降低程序的执行效率,在需要的时候进行添加,尽量不要设置级联操作为all 
-->
<one-to-one name="card" class="com.xixw.vo.CardVo" cascade="delete">
</one-to-one>

④ 元数据加入到主配置文件中

<mapping resource="com/xixw/OneToOne/Person.hbm.xml"/>
<mapping resource="com/xixw/OneToOne/Card.hbm.xml"/>

⑤ 测试

package com.xixw.OneToOne;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.ServiceRegistryBuilder;

public class Test {
	public static void main(String[] args) {
		Configuration cfg=new Configuration();
		//加载主配置文件
		cfg.configure();
		ServiceRegistry   serviceRegistry = new ServiceRegistryBuilder().applySettings(cfg.getProperties()).buildServiceRegistry();
		SessionFactory factory = cfg.buildSessionFactory(serviceRegistry);
		//获取session对象
		Session session=factory.openSession();
		Transaction tr=session.beginTransaction();
		Person person=new Person();
		person.setName("张三");
		Card card=new Card();
		card.setCardNo("999999999");
		person.setCard(card);
		card.setPerson(person);
		//保存数据
		session.save(person);
		//session.save(card);
		
		/*Person person=(Person) session.get(Person.class, 1);
		session.delete(person);*/
		//System.out.println(person.getName());
		//System.out.println(person.getCard().getCardNo());
		tr.commit();
		session.close();
	}
}

唯一外键关联

① 唯一外键关联数据库表设计方案
两张表中互存外键
在这里插入图片描述
② 实体类的设计方案(参考主键关联的设计方案)
两个实体类中互存对象

③ Vo类映射文件配置
PersonVo.hbm.xml

<?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 package="com.xixw.OneToOne1">
	<!-- 映射表和类 -->
	<class name="Person1" table="person1_t">
		<!-- 映射主键 -->
		<id name="id">
			<generator class="increment"></generator>
		</id>
		<!-- 映射普通属性 -->
		<property name="name"></property>
		<!-- 映射对象
			特殊的多对一:所以使用many-to-one
		 -->
		<many-to-one name="card" class="Card1" column="cid" cascade="delete"></many-to-one>
	</class>
</hibernate-mapping>

CardVo.hbm.xml

<?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 package="com.xixw.OneToOne1">
	<!-- 映射类和表 -->
	<class name="Card1" table="card1_t">
		<!-- 映射主键 -->
		<id name="id">
			<generator class="increment"></generator>
		</id>
		<!-- 映射普通属性 -->
		<property name="cardNo"></property>
		<!-- 映射对象 -->
		<many-to-one name="person" class="Person1" column="pid" cascade="delete"></many-to-one>
	</class>
</hibernate-mapping>

④ 元数据加入到主配置文件中

<mapping resource="com/xixw/OneToOne1/Person.hbm.xml"/>
<mapping resource="com/xixw/OneToOne1/Card.hbm.xml"/>

*3. 多对多

① 场景
学生老师的对应关系

② 数据库表设计方案
产生一个中间表来表明两张表之间的关系,中间表最少有两个字段,两个字段对应的是两张表的主键,两个字段共同组成了中间表的主键,叫做复合主键。
在这里插入图片描述
③ Vo类设计
两个对象互存集合
TeacherVo.java

public class TeacherVo {
	private int id;
	private String name;
	private Set<StudentVo> stuSet;
//get()和set()方法
}

StudentVo.java

public class StudentVo {
	private int id;
	private String name;
	private Set< TeacherVo> teaSet;
//get()和set()方法
}

④ Vo类的映射文件配置
TeacherVo.hbm.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
    <hibernate-mapping package=”com.xixw.vo”>
        <class name="TeacherVo" table="tea_table">
        	<id name="id" >
        		<generator class="increment"></generator>
        	</id>
        	<property name="name" column="t_name"/>
        	<!--name:对应TeacherVo类中set集合的名称
        		table:对应多对多关系的中间表
        		<key column>:中间表中teacher表的对应的外键
            -->
        	<set name="stuSet" table="table_s_t" fetch="join">
        		<key column="t_id"></key>
        		<!--column:中间表中student表的对应的外键
        		     class:对应StudentVo类的完全限定名
        		  -->
        		<many-to-many column="s_id" class="StudentVo">
</many-to-many>
        	</set>
        </class>
    </hibernate-mapping>

StudentVo.hbm.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
     <hibernate-mapping package=”com.xixw.vo”>
        <class name="StudentVo" table="stu_table">
        	<id name="id" >
        		<generator class="increment"></generator>
        	</id>
        	<property name="name" column="s_name"/>
        	<!--name:对应StudentVo类中set集合的名称
        		 table:对应多对多关系的中间表
        		<key column>:中间表中student表的对应的外键
             --> 
        		<!--fetch:设置hibernate查询的抓取策略(查询方式)
        		  	 值:join:使用外连接进行查询
        		  	 	select:使用select进行查询
        		  	 	subselect:使用子查询进行查询	 
        		 -->
	             <!--lazy:设置hibernate延时加载功能
        		  	 值:true:打开延时加载的功能(默认)
        		  	 	 False:关闭延时加载的功能
        		 -->
     <set name="teaSet" table="table_s_t" lazy="true" fetch="join">
        <key column="s_id"></key>
        <!--column:中间表中teacher表的对应的外键
        	 class:对应TeacherVo类的完全限定名
        -->
        <many-to-many column="t_id" class="TeacherVo"></many-to-many>
     </set>
    </class>
</hibernate-mapping>

将元数据加载到主配置文件

<mapping resource="com/xixw/Vo/StudentVo.hbm.xml"/>
<mapping resource="com/xixw/Vo/TeacherVo.hbm.xml"/> 

⑤ 测试

package com.xixw.test;
import java.util.HashSet;
import java.util.Set;
import org.hibernate.Hibernate;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import com.xixw.vo.StudentVo;
import com.xixw.vo.TeacherVo;

public class ManyToManyTest {
public static void main(String[] args) {
	        //1.创建Configuration对象
			Configuration cfg=new Configuration();
			//2.加载主配置文件
			cfg.configure();
			//3.获取SessionFactory工厂
			SessionFactory factory=cfg.buildSessionFactory();
			//4.获取session对象
			Session session=factory.openSession();
			//Transaction tr=session.beginTransaction();
            //保存对象
			/*StudentVo stu1=new StudentVo();
			stu1.setName("李四");
			TeacherVo tea1=new TeacherVo();
			tea1.setName("小明1");
			TeacherVo tea2=new TeacherVo();
			tea2.setName("小红1");
			Set<TeacherVo> teaSet=new HashSet<TeacherVo>();
			teaSet.add(tea1);
			teaSet.add(tea2);
			stu1.setTeaSet(teaSet);*/
			
			/*Set<StudentVo> stuSet1=new HashSet<StudentVo>();
			stuSet1.add(stu1);
			tea1.setStuSet(stuSet1);
			Set<StudentVo> stuSet2=new HashSet<StudentVo>();
			stuSet2.add(stu1);
			tea2.setStuSet(stuSet2);*/
			
			StudentVo stu=(StudentVo) session.get(StudentVo.class, 1);
			/*解决: org.hibernate.LazyInitializationException
			 * 1.使用hibernate预加载功能,将关联的对象事先加载完成
                 Hibernate.initialize(stu.getTeaSet());
			 * 2.将对象延时加载的功能关闭:lazy="false",(默认是开启的)
                  关闭会影响程序的性能
			 * 3.修改抓取策略为join:fetch=”join”
                  Join:使用外连接的形式进行查询
                  Select:使用普通查询,会报懒加载异常
                  subSelect:使用子查询的方式进行查询
			 * */
		//	Hibernate.initialize(stu.getTeaSet());
			session.close();
			Set<TeacherVo> set=stu.getTeaSet();
			for (TeacherVo teacherVo : set) {
				System.out.println(teacherVo.getName());
			}
			/*session.save(tea1);
			session.save(tea2);
			session.save(stu1);
			*/
			//tr.commit();
			//session.close();	
}
}

总结

Inverse(设置维护关系)一般在多对一的时候让一方放弃维护,由多方去维护他们之间的关系 true:设置放弃维护关系 false:(默认)设置不放弃维护关系
Cascade(设置级联操作)delete:在删除的时候进行级联操作。save-update:在保存或者更新的时候进行级联操作。all:在所有的情况下都会进行级联操作。none:(默认)不进行级联操作
Lazy(设置延时加载)注意:在使用延时加载的时候要注意避免懒加载异常
Fetch(设置抓取策略)join:使用外连接进行查询;select:使用普通select进行查询;subselect:使用子查询进行查询
order-by:进行排序,值是需要排序的属性名注意:只能定义在set集合中,然后对set集合中的对象进行排序

下一篇:Hibernate注解
Hibernate注解

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值