`

hibernate03 一对一 多对多双向映射

阅读更多

*一)【双向】一对多【客户 vs 订单】优化
    (1)传统:保存订单,级联保存客户,设置双向关联--------------7条SQL
  问题的前提:是双向关系
  问题的产生:在默认情况下,单方和多方,都负责产生SQL语句,这样的话,可能产生不必要的多余SQL语句。
         理论上哪方负责都可以,
  但实际中用多方负责产生SQL较佳,即多方是主控方。
  inverse反转/向
    (2)优化:保存订单,级联保存客户,设置单向关联--------------4条SQL
    (3)什么情况下用cascade和inverse属性    
  cascade:
  当你需要操作Customer时,同时又要操作对应的所有Order,这样可以使用cascade属性
  常用取值:save-update,delete,all
  inverse:
  前提:必须是双向关联,单向关联不存在inverse的情况
  保存多方,要级联保存单方的情况
  常用取值:true

Customer.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映射文件 -->    
<hibernate-mapping package="one2many_double">
	<class name="Customer" table="CUSTOMERS">
		<id name="id" column="ID">
			<generator class="native"/>
		</id>
		<property name="name" column="NAME"/>
		<property name="age"  column="AGE"/>
		<property name="des"  column="DES"/>
		<!-- 
			inverse=true如果出现在Customer类中,表示
			Order类是主控方,负责产生SQL语句
			
			inverse=false如果出现在Customer类中,表示
			Customer类是主控方,负责产生SQL语句
			
			如果Customer和Order都无inverse的话,表示
			Customer和Order都是主控方,负责产生SQL语句
			如果这样的话:问题有二:
			一)会产生多余的SQL(成功)
			二)会产主键重重(失败)
			
		 -->
		<set name="orders" table="ORDERS" cascade="all" inverse="true"> 
			<key column="CUSTOMERS_ID"/>
			<one-to-many class="Order"/>
		</set>
	</class>	
</hibernate-mapping>    

 Order.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映射文件 -->    
<hibernate-mapping package="one2many_double">
	<class name="Order" table="ORDERS">
		<id name="id" column="ID">
			<generator class="native"/>
		</id>
		<property name="orderno" column="ORDERNO"/>
		<property name="price"  column="PRICE"/>
		<property name="time"  column="TIME"/>
		<many-to-one 
			name="customer"
			column="customers_id"
			cascade="all"
		/>
	</class>	
</hibernate-mapping>    

 

二)【双向】一对一【人 vs 身份证】 

    

	private Integer id;
	private String name;
	private Double salary;
	private Card card;

 
     Person.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映射文件 -->    
<hibernate-mapping package="onetoonedouble">
	<class name="Person" table="PERSON">
		<id name="id" column="ID">
			<generator class="native"/>
		</id>
		<property name="name" column="NAME"/>
		<property name="salary" column="SALARY"/>
		<!-- 
			name:表示Person类的关联属性
			property-ref:表示Person类的对方Card类的关联属性
		 -->
		<one-to-one 
			name="card"
			property-ref="person"
			cascade="all"
		/>	
	</class>	
</hibernate-mapping> 

 

	private int id;
	private String number;
	private String location;

 
     Card.hbm.xml文件
    

<hibernate-mapping package="onetoonedouble">
	<class name="Card" table="CARD">
		<id name="id" column="ID">
			<generator class="native"/>
		</id>
		<property name="number" column="NUMBER"/>
		<property name="location"  column="LOCATION"/>
		<!-- 
			name:表示Card类的关联属性
			column:表示cards表对应的外健
			not-null:表示该列不能为NULL
			unique:表示该列的值必须惟一
		 -->
		<many-to-one 
			name="person"
			column="PERSON_ID"
			not-null="true"
			unique="true"
		/>
	</class>	
</hibernate-mapping> 

 
     (1)保存人,级联保存身份证
     (2)查询人,对象导航查询身份证
     (3)更新人,级联更新身份证
     (4)删除人,级联删除身份证
 
*三)【双向】多对多【学生 vs 老师】

use hibernate
drop table if exists middles;
drop table if exists students;
drop table if exists teachers;
create table if not exists students(
id int primary key auto_increment,
name varchar(20)
);
create table if not exists teachers(
id int primary key auto_increment,
name varchar(20)
);
create table if not exists middles(
students_id int,
teachers_id int,
primary key(students_id,teachers_id),
constraint students_id_FK foreign key(students_id) references students(id),
constraint teachers_id_FK foreign key(teachers_id) references teachers(id)
);
select * from students;
select * from middles;
select * from teachers;

 

	int id;
	String name;
	Set<Teacher> teacherset = new HashSet<Teacher>();

 
     Student.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映射文件 -->    
<hibernate-mapping package="many2many_double">
	<class name="Student" table="STUDENTS">
		<id name="id" column="ID">
			<generator class="native"/>
		</id>
		<property name="name" column="NAME"/>
		<!-- 
			name:表示Student类的关联属性
			table:表示middles表名
			key-column:表示middles表中引用students表的外健
			class:表示Student类对应的类型,即Teacher类型
			many-to-many-column:表示middles表中引用teachers表的外健
		 -->
		<set name="teacherset" table="MIDDLES" cascade="all" inverse="true">
			<key column="STUDENTS_ID"/>
			<many-to-many class="Teacher" column="TEACHERS_ID"/>
		</set>
	</class>	
</hibernate-mapping>    
	private int id;
	private String name;
	Set<Student> studentset = new HashSet<Student>();

 
     Teacher.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映射文件 -->    
<hibernate-mapping package="many2many_double">
	<class name="Teacher" table="TEACHERS">
		<id name="id" column="ID">
			<generator class="native"/>
		</id>
		<property name="name" column="NAME"/>
		<set name="studentset" table="MIDDLES" cascade="all">
			<key column="TEACHERS_ID"/>
			<many-to-many class="Student" column="STUDENTS_ID"/>
		</set>
	</class>	
</hibernate-mapping>   

 
    (1)保存老师,级联保存学生【学生是主控方或老师是主控方】
    (2)删除1号老师,不级联删除学生

	@Test
	public void test2() {
		Session session = sessionFactory.openSession();
		Transaction t = session.beginTransaction();
		try {
			Teacher t1 = (Teacher) session.load(Teacher.class, 1);
			for (Student s : t1.getStudentset()) {
				s.getTeacherset().remove(t1);
			}
			t1.setStudentset(null);
			session.delete(t1);
			t.commit();
		} catch (Exception e) {
			e.printStackTrace();
			t.rollback();
		} finally {
			session.close();
		}
	}

 

四)映射组件整体与部分的关系【客户 vs 公司地址和家庭地址】
    (1)hibernate将持久化对象分为二种类型
         >>含有OID的对象:实体型,一定对应一条完整记录
         >>不含OID的对象:值类型,不能对应一条完整记录,只能对应一条记录的某些部分
        

<hibernate-mapping package="cn.itcast.web.hibernate.component">
	<class name="User" table="USERS">
		<id name="id" column="ID">
			<generator class="increment"/>
		</id>
		<property name="name" column="NAME"/>
		<!-- 
			name:表示User中JavaBean的属性
			class:表示该JavaBean属性的类型
		 -->
		<component name="homeAddress" class="Address">
			<property name="province" column="HOME_PROVINCE"/>
			<property name="city" column="HOME_CITY"/>
			<property name="area" column="HOME_AREA"/>
		</component> 
		<component name="comAddress" class="Address">
			<property name="province" column="COM_PROVINCE"/>
			<property name="city" column="COM_CITY"/>
			<property name="area" column="COM_AREA"/>
		</component> 
	</class>	
</hibernate-mapping>    

 
    (2)保存客户
    (3)查询客户
    (4)更新客户
    (5)删除客户

*五)深入理解session一级缓存与批处理
   (1)对象生命周期图堆栈图
 Session是Hibernate中操作数据库的重要对象,完成CRUD操作
 Session就是由集合组成
 只要Session有引用存在,它所引用的对象,就不会被GC回收
   (2)hibernate自动清理session一级缓存的时间
 清理flush:session一级缓存根据持久化对象属性值的改变情况,自动生成SQL的过程,叫清理。
 注意:此时并没有与数据库交互
   (3)对比以下方法:
        >>session.flush()
   清理session缓存,但session缓存中的持久化对象没有删除

       *>>session.evict()
   将【一个】持久状态对象转成游离状态对象

        >>session.clear()
   一次性将位于session缓存中的所有持久状态对象,清出session缓存区
   将【多个】持久状态对象转成游离状态对象
 
       *>>transaction.commit()
   它包括二个子步骤:
          A)session.flush()
   B)事务提交,就与数据库交互

       *>>session.close()
   它包括二个子步骤:
   A)session.clear()
   B)回收资源
          注意:如果要全完销毁Session,一定要加上如下代码:session = null     


   (4)批量向MySQL数据库插入10万条数据,并记录所耗时间 

	public void test1() {
		Session session = sessionFactory.openSession();
		Transaction t = session.beginTransaction();
		try {
			long begin = System.currentTimeMillis();
			for (int i = 1; i <= 100001; i++) {
				User user = new User("用户" + i);
				session.save(user);
				if (i % 1000 == 0) {
					t.commit();
					session.clear();
					t = session.beginTransaction();
				}
			}// end of for loop
			t.commit();
			long end = System.currentTimeMillis();
			System.out.println((end - begin) / 1000 + "��");
		} catch (Exception e) {
			e.printStackTrace();
			t.rollback();
		} finally {
			session.close();
		}
	}

 
    参见<<PPT第21,22页>>

六)安装Oracle数据库11g版本

 

 

 

 

 

 

 

 

 

0
0
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics