hibernate框架03

来源:互联网 发布:java web信息管理系统 编辑:程序博客网 时间:2024/05/15 07:13
1、表之间的关系有几种:
四种。
一对多,多对一。
多对多,一对一。

    一对一:

   用处:分为常用信息表和不常用信息表

直接查询所有信息费时且占内存资源太多,简言之空间换时间

     外键加了unique唯一就是一对一而不是一对多


2、学习hibernate多表映射应该遵循的步骤:
第一步:明确两张表之间的关系
第二步:在数据库中实现两张表之间的关系
第三步:在实体类中描述出两个实体之间的关系
第四步:在映射配置文件中配置出两个实体和表之间的关系

3、一对多关系:
使用的示例:客户和联系人 
前提:
   一对多的情况下,我们一般把一称之为主表,把多称之为从表

第一步:明确客户和联系人之间的关系是一对多
第二步:在数据库中如何实现一对多的关系建立:
靠外键。外键指的就是从表中的一列,它的取值来源于主表的主键。
第三步:实现实体类中一对多的描述
主表实体:包含一个从表实体的集合引用
从表实体:包含一个主表实体的对象引用
第四步:映射配置文件的配置
主表映射配置文件:
set标签,key标签,one-to-many标签
从表映射配置文件:
many-to-one标签
一对多关系的窍门:
找外键。有外键的表就是从表,引用谁的主键,谁就是主表。他们之间的关系就是一对多。

细节:

一对多关系主表映射涉及的标签: set.作用:映射set集合属性属性: name:指定集合元素的属性名称 table:指定从表名称。此时可以不写涉及的子标签:

key作用:用于映射外键字段属性:

column:指定从表外键字段名称涉及的子标签:

one-to-many作用:用于映射一对多属性: class:指定的是从表的实体类


多对一关系映射:涉及的标签:many-to-one属性: name:指定实体类中属性的名称 column:指定的是从表中外键字段的名称 class:指定主表的实体类名称



 * 双向一对多的增,删,改操作
 * @author zhy
 *
 */
public class HibernateDemo2 {

/**
* 需求:
* 保存客户和联系人
* 要求:
* 创建一个客户,创建一个联系人
* 建立客户和联系人的单向多对一关联关系
*  先保存联系人,再保存客户
* 问题:
* 会产生3条语句,其中两条inerst,1条update。而我们保存两个实体,只需要2条insert。
* 分析update语句产生的原因:
* 就是因为快照机制的存在
* 解决办法:
* 在一对多的保存时,我们一定要遵循保存原则,即:先保存主表,再保存从表
*/
@Test
public void test1(){
Customer c = new Customer();
c.setCustName("one2Many Customer");

LinkMan l = new LinkMan();
l.setLkmName("one2Many LinkMan");

//建立双向关联关系
l.setCustomer(c);
//c.getLinkmans().add(l);


Session s = HibernateUtil.getCurrentSession();
Transaction tx = s.beginTransaction();
//按照要求做:先保存联系人,再保存客户
//
s.save(l);
//
s.save(c);
//解决多一条Update的原因:符合保存原则
s.save(c);
s.save(l);

tx.commit();
}

/**
* 需求:
* 保存两个实体:客户和联系人
* 要求:
* 创建一个客户,创建一个联系人
* 建立客户和联系人的双向关联关系
*  保存客户和联系人
*  先保存客户,再保存联系人(遵循保存原则)
* 问题:
*   当我们建立了双向关联关系之后,即便是先保存主表,在保存从表仍然会出现3条语句。
* 解决办法:
* 让主表方放弃维护关联关系的权利。在调用session的操作方法时放弃。 
*使用配置文件配置的方式:
*在主表的映射配置文件中,找到set标签。
*使用的属性:inverse
*含义:是否放弃维护关联关系的权利
*取值:
*true 放弃
*false 不放弃(默认值)
*  

也就是说关系不是双方维护的,只需要交给某一方去维护就可以了。通常我们都是交给多的一方去维护的


*/
@Test
public void test2(){
Customer c = new Customer();
c.setCustName("one2Many Customer-2");

LinkMan l = new LinkMan();
l.setLkmName("one2Many LinkMan-2");

//建立双向关联关系
l.setCustomer(c);
c.getLinkmans().add(l);


Session s = HibernateUtil.getCurrentSession();
Transaction tx = s.beginTransaction();
//按照要求做:符合保存原则
s.save(c);
s.save(l);

tx.commit();

//客户和联系人还能用吗?
System.out.println(l.getCustomer());
System.out.println(c.getLinkmans());
}



/**
* 需求:
*更新一个客户
* 要求:
*  根据id查询一个客户
*  创建一个新的联系人
*  建立客户和联系人的双向关联关系
*  更新客户
* 问题:
*当一个持久态关联一个瞬时态对象时,当更新持久态对象时,会报错。
*  错误说的是:请先把瞬时态对象保存,然后再更新持久态对象。
* 解决办法:
*级联操作  
*  使用配置的方法实现。
*  配置的位置:
*  要操作谁,找谁的映射配置文件
*  要级联操作谁,找谁的配置
*配置的属性:
*cascade:级联操作
*属性的取值:
*save-update:级联保存更新
*  
*/
@Test
public void test3(){
LinkMan l = new LinkMan();//瞬时态
l.setLkmName("one2Many LinkMan-update-2");


Session s = HibernateUtil.getCurrentSession();
Transaction tx = s.beginTransaction();
//根据id查询客户
Customer c5 = s.get(Customer.class, 5L);//持久态
//建立和联系人的双向关联关系
l.setCustomer(c5);
c5.getLinkmans().add(l);

//更新客户
s.update(c5);//只做一件事,更新客户。现在我们需要它做两件事,一件是保存联系人,另一件是更新客户。
tx.commit();
}



/**
* 删除操作
*   
* 删除从表数据:随便删
* 删除主表数据:
*有没有从表数据引用:
*有引用:
*外键字段是否允许为null
*允许为null:先把外键字段置为null,再删除主表数据
*不允许为null:删除失败,因为有外键字段引用
*     没有引用:随便删
* 当我们配置了inverse属性之后,如果有从表数据引用主表时,删除失败,因为它只关心自己,不会再去更新从表的外键字段为null了。
* 就想删除成功:
* 级联删除。
*删除主表数据时,先会把所有关联的从表数据一并删除,然后再来删除主表数据。

* 级联删除:在实际开发中,如果遇到重要性很强的数据,尽量不用。

*/
@Test
public void test4(){
Session s = HibernateUtil.getCurrentSession();
Transaction tx = s.beginTransaction();
//根据id查询客户
Customer c6 = s.get(Customer.class, 6L);//持久态
//删除id为5的客户
s.delete(c6);
tx.commit();
}




 * 演示一对多映射配置关于主从表映射都需要指定外键的字段的原因
 * 对象导航查询:
 * 它是hibernate中五种查询方式的其中之一,
 * 它可以实现,在有关联关系的实体之间,直接通过调用getXXXX方法来获取数据。
 * 使用对象导航查询的要求:
 * 两个实体之间,必须有关联关系(四种之一)
 * 问题:
 * 当我们有少的一方时,要不要查询多的一方
 * 当我们有多的一方时,要不要查询少的一方
 * 分析:
 * 在多对一,一对一的情况下:
 * 采用立即加载的思想。我们查询多的一方,需要把关联的少的一方也查出来。
 * 可以配置成延迟加载:
 * 配置的方式:就是many-to-one的lazy属性。
 * 取值:
 * false:立即加载
 * proxy:它是看一的一方的class标签上lazy属性的取值 默认值
 * no-proxy:一般不用。
 * 实际开发中,多对一的情况,需要我们配置。
 * 在一对多,多对多的情况下:
 * 采用延迟加载的思想,我们查询少的一方,不需要把关联的多的一方也查出来。什么时候需要用到多的一方的数据时,什么时候真正的去查询。
 * 在不配置的情况下:它默认就是延迟加载。
 * 可以配置成立即加载:
 * 配置的方式,就是在set标签上使用lazy属性。
 * lazy的取值:
 * true:延迟加载 默认值
 * false:立即加载
 * extra:极懒加载。用什么,查什么,不用的都不查。
 * 
 * @author zhy
 *
 */
public class HibernateDemo1 {


@Test
public void test1(){
Session s = HibernateUtil.getCurrentSession();
Transaction tx = s.beginTransaction();
Customer c = s.get(Customer.class, 1L);
System.out.println(c.toString());
System.out.println(c.getLinkmans().size());
System.out.println(c.getLinkmans());
tx.commit();
}

@Test
public void test2(){
Session s = HibernateUtil.getCurrentSession();
Transaction tx = s.beginTransaction();
LinkMan l = s.get(LinkMan.class, 1L);
System.out.println(l.toString());
System.out.println(l.getCustomer());
tx.commit();
}
}

4、多对多关系:
使用的示例:用户和角色
第一步:明确用户和角色之间的关系是多对多
第二步:在数据库中如何实现多对多的关系建立:
靠中间表。
任何一方和中间表之间的关系都是一对多。
第三步:实现实体类中多对多描述
各自包含对方的一个集合引用
第四步:映射配文件的配置


细节:多对多关系映射:涉及的标签:set属性: name:指定集合元素的名称 table:指定中间表的名称涉及的子标签:

key作用:指定外键字段属性: column:指定当前实体在中间表的外键字段名称涉及的子标签:

many-to-many作用:指定当前实体和集合元素之间的关系是多对多属性: class:指定的是集合元素所对应的实体类 column:指定集合元素所对应的实体在中间表的外键字段名称