美文网首页技术干货
Hibernate干货笔记——第二天

Hibernate干货笔记——第二天

作者: 深海鱼Q | 来源:发表于2017-06-15 20:08 被阅读0次

目录

1. Hibernate的持久化类状态
  • 1.1 三种持久化对象的状态
  • 1.2 区分三种持久化对象的状态
  • 1.3 三种状态对象转换
  • 1.4 持久态对象有自动更新数据库的能力
2. Hibernate的一级缓存:(重要)
  • 2.1 一级缓存快照区
  • 2.2 Hibernate管理一级缓存
3. 操作持久化对象的方法
4. Hibernate关联关系的映射
  • 4.1 实体之间的关系
  • 4.2 Hibernate中一对多的配置
  • 4.3 Hibernate中级联保存的效果
  • 4.4 Hibernate中级联删除的效果
  • 4.5 Hibernate中的级联取值
  • 4.6 双向维护产生多余的SQL
  • 4.7 Hibernate的多对多的配置

Hibernate的持久化类状态

持久化类:就是一个实体类与数据库表建立了映射.
Hibernate为了方便管理持久化类,将持久化类分成了三种状态.

  • 瞬时态 transient
  • 持久态 persistent
  • 脱管态 detached
三种持久化对象的状态
  • Transient瞬时态
    特点:持久化对象没有唯一标识OID.没有纳入Session的管理.
  • Persistent持久态:
    特点:持久化对象有唯一标识OID.已经纳入到Session的管理.
    结论:持久化持久态对象有自动更新数据库的能力.
  • Detached脱管态:
    特点:持久化对象有唯一标识OID,没有纳入到Session管理.
区分三种持久化对象的状态
    @Test
    // 区分持久化对象的三种状态:
    public void demo1(){
        // 1.创建Session
        Session session = HibernateUtils.openSession();
        // 2.开启事务
        Transaction tx = session.beginTransaction();
        // 向数据库中保存一本图书:
        Book book = new Book(); // 瞬时态:没有唯一标识OID,没有与session关联.
        book.setName("Hiernate开发");
        book.setAuthor("孙XX");
        book.setPrice(65d);
        session.save(book); // 持久态:有唯一标识OID,与session关联.
        // 3.事务提交
        tx.commit();
        // 4.释放资源
        session.close();
        book.setName("Struts2开发"); // 脱管态:有唯一的标识,没有与session关联.
    }
三种状态对象转换
  • 瞬时态
    获得:Book book = new Book();
    瞬时--->持久
    save(book);
    save()/saveOrUpdate();
    瞬时--->脱管
    book.setId(1);

  • 持久态
    获得:Book book = (Book)session.get(Book.class,1);get()/load()/find()/iterate();
    持久--->瞬时:
    delete(book);
    特殊状态:删除态.(被删除的对象,不建议去使用.)
    持久--->脱管:
    session.close();
    close()/clear()/evict();

  • 脱管态
    获得:Book book = new Book();book.setId(1);
    脱管--->持久:
    session.update();
    update()/saveOrUpdate()/lock()
    脱管--->瞬时:
    book.setId(null);

持久态对象有自动更新数据库的能力
@Test
    // 测试持久态的对象自动更新数据库
    public void demo2(){
        // 1.创建Session
        Session session = HibernateUtils.openSession();
        // 2.开启事务
        Transaction tx = session.beginTransaction();
        
        // 获得一个持久态的对象.
        Book book = (Book) session.get(Book.class, 1);
        book.setName("Struts2开发");
        
        // session.update(book); 不需要使用update方法更新
        
        // 3.提交事务
        tx.commit();
        // 4.关闭资源
        session.close();
    }

自动更新数据库的能力依赖了Hibernate的一级缓存

Hibernate的一级缓存:(重要)

什么是缓存
缓存将数据库/硬盘上文件中数据,放入到缓存中(就是内存中一块空间).当再次使用的使用,可以直接从内存中获取.

缓存的好处
提升程序运行的效率.缓存技术是Hibernate的一个优化的手段.

Hibernate分成两个基本的缓存

  • 一级缓存:Session级别的缓存.一级缓存与session的生命周期一致.自带的.不可卸载.
  • 二级缓存:SessionFactory级别的缓存.不是自带的.

在 Session 接口的实现中包含一系列的 Java 集合, 这些 Java 集合构成了 Session 缓存. 只要 Session 实例没有结束生命周期, 存放在它缓存中的对象也不会结束生命周期

一级缓存快照区
    @Test
    // 深入理解一级缓存结构:快照区:
    public void demo4(){
        // 1.创建Session
        Session session = HibernateUtils.openSession();
        // 2.开启事务
        Transaction tx = session.beginTransaction();
        
        // 获得一个持久态的对象.
        Book book = (Book) session.get(Book.class, 1);
        book.setName("Spring3开发");
        
        // 3.提交事务
        tx.commit();
        // 4.关闭资源
        session.close();
    }

结论:向一级缓存存入数据的时候,放入一级缓存区和一级缓存快照区,当更新了一级缓存的数据的时候,事务一旦提交,比对一级缓存和快照区,如果数据一致,不更新,如果数据不一致,自动更新数据库.

Hibernate管理一级缓存

一级缓存是与session的生命周期相关的.session生命周期结束,一级缓存销毁了.

  • clear()/evict()/flush()/refresh()管理一级缓存.
  • clear() :清空一级缓存中所有的对象.
  • evict(Object obj) :清空一级缓存中某个对象.
  • flush() :刷出缓存.
  • refresh(Object obj):将快照区的数据重新覆盖了一级缓存的数据.

操作持久化对象的方法

  • save():保存一条记录:将瞬时态对象转成持久态对象.
  • update()更新一条记录:将脱管态对象转成持久态对象.
    在<class>标签上设置select-before-update="true"在更新之前先去查询
  • saveOrUpdate():
    根据对象状态的不同执行不同的save获得update方法.
  • 如果对象是一个瞬时态对象:执行save操作.
  • 如果对象是一个脱管态对象:执行update操作.
  • 设置id不存在,就会报错,可以在<id>上设置一个unsaved-value=”-1”,执行保存的操作.
  • delete():将持久态对象转成瞬时态.
  • get()/load():获得一个持久态对象.

Hibernate关联关系的映射

实体之间的关系

实体之间有三种关系:

  • 一对多:
    一个用户,生成多个订单,每一个订单只能属于一个用户.
    建表原则:在多的一方创建一个字段,作为外键,指向一的一方的主键.
  • 多对多:
    一个学生可以选择多门课程,一个课程可以被多个学生选择.
    建表原则:创建第三张表,中间表至少有两个字段,分别作为外键指向多对多双方主键.
  • 一对一:(特殊.最少.)
    一个公司只能有一个注册地址,一个注册地址,只能被一个公司使用.(否则将两个表建到一个表.)
    建表原则:
  • 唯一外键:一对一的双方,假设一方是多的关系.需要在多的一方创建一个字段,作为外键.指向一的一方的主键.但是在外键添加一个unique.
  • 主键对应:一对一的双方,通过主键进行关联.
Hibernate中一对多的配置

第一步:创建两个实体:

  • 客户实体:
public class Customer {
    private Integer cid;
    private String cname;
    // 一个客户有多个订单.
    private Set<Order> orders = new HashSet<Order>();
    public Integer getCid() {
        return cid;
    }
    public void setCid(Integer cid) {
        this.cid = cid;
    }
    public String getCname() {
        return cname;
    }
    public void setCname(String cname) {
        this.cname = cname;
    }
    public Set<Order> getOrders() {
        return orders;
    }
    public void setOrders(Set<Order> orders) {
        this.orders = orders;
    }
}
  • 订单实体:
public class Order {
    private Integer oid;
    private String addr;
    // 订单属于某一个客户.放置一个客户的对象.
    private Customer customer;
    public Integer getOid() {
        return oid;
    }
    public void setOid(Integer oid) {
        this.oid = oid;
    }
    public String getAddr() {
        return addr;
    }
    public void setAddr(String addr) {
        this.addr = addr;
    }
    public Customer getCustomer() {
        return customer;
    }
    public void setCustomer(Customer customer) {
        this.customer = customer;
    }   
}

第二步:建立映射Customer.hbm.xml

<hibernate-mapping>
    <class name="cn.itcast.hibernate3.demo2.Customer" table="customer">
        <!-- 配置唯一标识 -->
        <id name="cid" column="cid">
            <generator class="native"/>
        </id>
        <!-- 配置普通属性 -->
        <property name="cname" column="cname" length="20"/>
        
        <!-- 建立映射 -->
        <!-- 配置一个集合 <set>的name Customer对象中的关联对象的属性名称. -->
        <set name="orders">
            <!-- <key>标签中column:用来描述一对多多的一方的外键的名称. -->
            <key column="cno"></key>
            <!-- 配置一个<one-to-many>标签中class属性:订单的类的全路径 -->
            <one-to-many class="cn.itcast.hibernate3.demo2.Order"/>
        </set>
    </class>
</hibernate-mapping>

Order.hbm.xml

<hibernate-mapping>
    <class name="cn.itcast.hibernate3.demo2.Order" table="orders">
        <!-- 配置唯一标识  -->
        <id name="oid" column="oid">
            <generator class="native"/>
        </id>
        <!-- 配置普通属性 -->
        <property name="addr" column="addr" length="50"/>
        <!-- 配置映射 -->
        <!-- 
        <many-to-one>标签
            name    :关联对象的属性的名称.
            column  :表中的外键名称.
            class   :关联对象类的全路径
        -->
        <many-to-one name="customer" column="cno" class="cn.itcast.hibernate3.demo2.Customer"/>
    </class>
</hibernate-mapping>

第三步:将映射放到核心配置文件中.

Hibernate中级联保存的效果

级联:操作当前对象的时候,关联的对象如何处理.
cascade=”save-update”

级联方向性

  • 保存客户的时候,选择级联订单.
  • 保存订单的时候,选择级联客户.
Hibernate中级联删除的效果

cascade=”delete”

Hibernate中的级联取值

none :不使用级联
dave-update :保存或更新的时候级联
delete :删除的时候级联
all :除了孤儿删除以外的所有级联.

delete-orphan :孤儿删除(孤子删除).

  • 仅限于一对多.只有一对多时候,才有父子存在.认为一的一方是父亲,多的一方是子方.
  • 当一个客户与某个订单解除了关系.将外键置为null.订单没有了所属客户,相当于一个孩子没有了父亲.将这种记录就删除了.

all-delete-orphan:包含了孤儿删除的所有的级联.

双向维护产生多余的SQL

配置inverse=”true”:在那一端配置.那么那一端放弃了外键的维护权.一般情况下,一的一方去放弃.
cascade:操作关联对象.
inverse:控制外键的维护.

Hibernate的多对多的配置

第一步:创建实体类:
学生的实体:

public class Student {
    private Integer sid;
    private String sname;
    // 一个学生选择多门课程:
    private Set<Course> courses = new HashSet<Course>();
    public Integer getSid() {
        return sid;
    }
    public void setSid(Integer sid) {
        this.sid = sid;
    }
    public String getSname() {
        return sname;
    }
    public void setSname(String sname) {
        this.sname = sname;
    }
    public Set<Course> getCourses() {
        return courses;
    }
    public void setCourses(Set<Course> courses) {
        this.courses = courses;
    }
    
}

课程的实体:

public class Course {
    private Integer cid;
    private String cname;
    // 一个课程被多个学生选择:
    private Set<Student> students = new HashSet<Student>();
    public Integer getCid() {
        return cid;
    }
    public void setCid(Integer cid) {
        this.cid = cid;
    }
    public String getCname() {
        return cname;
    }
    public void setCname(String cname) {
        this.cname = cname;
    }
    public Set<Student> getStudents() {
        return students;
    }
    public void setStudents(Set<Student> students) {
        this.students = students;
    }
    
}

第二步建立映射:
Student.hbm.xml

<hibernate-mapping>
    <class name="cn.itcast.hibernate3.demo3.Student" table="student">
        <!-- 配置唯一标识 -->
        <id name="sid" column="sid">
            <generator class="native"/>
        </id>
        <!-- 配置普通属性 -->
        <property name="sname" column="sname" length="20"/>
        
        <!-- 配置关联映射 -->
        <!-- <set>标签 name:对应学生中的课程集合的名称   table:中间表名称. -->
        <set name="courses" table="stu_cour">
            <!-- <key>中column写 当前类在中间表的外键.-->
            <key column="sno"></key>
            <!-- <many-to-many>中class:另一方类的全路径. column:另一方在中间表中外键名称-->
            <many-to-many class="cn.itcast.hibernate3.demo3.Course" column="cno"/>
        </set>
    </class>
</hibernate-mapping>

Course.hbm.xml

<hibernate-mapping>
    <class name="cn.itcast.hibernate3.demo3.Course" table="course">
        <!-- 配置唯一标识 -->
        <id name="cid" column="cid">
            <generator class="native"/>
        </id>
        <!-- 配置普通属性 -->
        <property name="cname" column="cname" length="20"/>
        <!-- 配置与学生关联映射 -->
        <!-- <set>中name:对应当前类中的学生的集合的名称  table:中间表的名称-->
        <set name="students" table="stu_cour">
            <!-- <key>中column:当前类在中间表中外键 -->
            <key column="cno"></key>
            <!-- <many-to-many>中class:另一方的类全路径. column:另一方在中间表中外键名称 -->
            <many-to-many class="cn.itcast.hibernate3.demo3.Student" column="sno"/>
        </set>
    </class>
</hibernate-mapping>

第三步:将映射文件加入到核心配置文件中:

相关文章

  • Hibernate干货笔记——第二天

    目录 1. Hibernate的持久化类状态 1.1 三种持久化对象的状态 1.2 区分三种持久化对象的状态 1....

  • day02

    Hibernate框架第二天 课程回顾:Hibernate框架的第一天 今天内容 Hibernate的持久化类 什...

  • Hibernate入门

    慕课网Hibernate学习笔记 开发环境 eclipse mars hibernate toos 最简单的例子 ...

  • 【Hibernate】二、核心接口

    笔记来自网络整合 一.Hibernate的6个核心接口 1.Configuration接口:配置Hibernate...

  • Hibernate框架(第二天笔记)

    第一天重点回顾 HIbernate的开发环境的搭建建包导入jar包编写JavaBean实体类 创建类与表结构的映射...

  • Hibernate笔记

    JavaEE的三层结构 web层:struts2框架 service层:spring框架 dao层:hiberna...

  • hibernate笔记

    一对多 注解:@OneToMany(cascade = CascadeType.ALL, orphanRemova...

  • Hibernate干货笔记——第一天

    目录 1. Hibernate框架的概述 1.1 Hibernate简介 1.2 为什么要学习Hibernate ...

  • Hibernate--day03

    非本人总结的笔记,抄点笔记复习复习。感谢传智博客及黑马程序猿记笔记啊记笔记 Hibernate的查询操作 Hibe...

  • Hibernate--day01

    非本人总结的笔记,抄点笔记复习复习。感谢传智博客及黑马程序猿记笔记啊记笔记 Hibernate的简介 什么是Hib...

网友评论

    本文标题:Hibernate干货笔记——第二天

    本文链接:https://www.haomeiwen.com/subject/sfxeqxtx.html