JAEE学习笔记(28)Hibernate(2)

Hibernate

今日内容

  • Hibernate持久化对象的状态
  • Hibernate的一级缓存
  • Hibernate操作持久化对象的方法
  • Hibernate 关联关系映射

回顾

1.Hibernate框架的概述:
 就是一个持久层的ORM框架.
 ORM:对象关系映射.将Java中实体对象与关系型数据库中表建立一种关系.Hibernate中可以通过操作对象的方式,从而操作数据库的表.
 常见的持久层框架:
 Hibernate
MyBatis
 JPA
 DBUtils
 Hibernate3.x和Hibernate4.x

--------------------------------------------------------------------

2.Hibernate快速入门:
2.1下载Hibernate开发包.
2.2Hibernate开发包目录结构:
* 文档:
* 开发包:
* 操作字节码:
* 必须的
* 可选的
* jpa
* 项目:
2.3创建一个java项目 导入相应jar包.
2.4创建数据库表:
2.5创建一个实体类:
2.6建立映射:
2.7创建Hibernate核心配置文件:
2.8编写一个测试类:

--------------------------------------------------------------------

3.Hibenrate的CRUD的操作:
* save();
* update();
* delete();
* get()/load();
* 区别:
* get   :采用是立即检索,马上发送SQL查询.返回的是真实对象.检索一个找不到的对象的时候NullPointException
* load  :采用延迟加载技术,当真正使用这个对象的时候,才会发送SQL.返回代理对象.检索一个找不到的对象的时候ObjectNotFoundException

--------------------------------------------------------------------

4.Hibernate的常见配置及API:
* 4.1核心配置:
* 两种方式;
* 属性文件的方式:
* 在src下创建一个hibernate.properties.
***** 手动加载映射文件.
* XML格式的配置:
* 在src下创建一个hibernate.cfg.xml

* 必须的配置:
* 数据库连接信息.
* Hibernate的方言.
* 可选配置:
* 显示SQL
* 格式化SQL
* hbm2ddl.auto
* create/create-drop/update/validate
* 映射文件:
* <mapping resource=””/>
* 4.2映射配置:
* <class>建立类与表映射
* name  :类的全路径
* table :表名称
* <id>
* name
* column
* type
* length
* <property>
* name
* column
* type
* length

--------------------------------------------------------------------

5.Hibernate的API
* Configuration:管理配置信息.
* 属性文件:
* 直接创建.
* XML
* new Configuration().configure();

* SessionFactory:
* 维护二级缓存,线程安全的对象.
* 抽取工具类.

* Session:
* 维护一级缓存,线程不安全的对象.

* Transaction:
***** 事务是默认不自动提交,手动提交事务.
* Query:
* Criteria:

--------------------------------------------------------------------

6.持久化类编写:
* 持久化类:就是一个实体类 + XML映射.
* 编写原则:
* 无参数构造:
* 属性提供set/get方法
* 提供为一个标识:
* 尽量使用包装类型:
* 这个类尽量不要使用final修饰.

* 自然主键和代理主键:
* Hibernate提供主键生成策略:
* increment :
* identity  :
* sequence  :
* uuid      :
* native        :
* assgined  :

1.2 Hibernate的持久化类状态:

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

持久态 persistent  :

脱管态 detached    :(离线态)
1.2.2 三种持久化对象的状态:
Transient瞬时态:
特点:持久化对象没有唯一标识OID.没有纳入Session的管理.

Persistent持久态:
特点:持久化对象有唯一标识OID.已经纳入到Session的管理.

***** 结论:持久化持久态对象有自动更新数据库的能力.
Detached脱管态:
特点:持久化对象有唯一标识OID,没有纳入到Session管理.
1.2.3 区分三种持久化对象的状态:
@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关联.
}
1.2.4 三种状态对象转换:
瞬时态:
获得:
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);
1.2.5 持久态对象有自动更新数据库的能力;
    @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);
        
        // 3.提交事务
        tx.commit();
        // 4.关闭资源
        session.close();
    }

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

1.3 Hibernate的一级缓存:(重要)

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

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

Hibernate分成两个基本的缓存:
* 一级缓存:Session级别的缓存.一级缓存与session的生命周期一致.自带的.不可卸载.
* 二级缓存:SessionFactory级别的缓存.不是自带的.

在 Session 接口的实现中包含一系列的 Java 集合, 这些 Java 集合构成了 Session 缓存. 只要 Session 实例没有结束生命周期, 存放在它缓存中的对象也不会结束生命周期.
1.3.2 证明Hibernate的一级缓存的存在:
@Test
// 证明一级缓存的存在
public void demo3(){
    // 1.创建Session
    Session session = HibernateUtils.openSession();
    // 2.开启事务
    Transaction tx = session.beginTransaction();        
    
    // save方法可以向一级缓存中存放数据的.
    /*Book book = new Book();
    book.setName("JQuery开发");
    book.setAuthor("张XX");
    book.setPrice(45d);
    
    Integer id = (Integer) session.save(book);
    
    Book book2 = (Book) session.get(Book.class, id); 
    
    System.out.println(book2);*/
    
    // 分别用get执行两次查询.
    Book book1 = (Book) session.get(Book.class, 1);// 马上发生SQL去查询
    System.out.println(book1);
    
    Book book2 = (Book) session.get(Book.class, 1);// 不发生SQL,因为使用一级缓存的数据
    System.out.println(book2);
    
    // 3.提交事务
    tx.commit();
    // 4.关闭资源
    session.close();
}
1.3.3 深入理解一级缓存中快照区:
    @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();
    }

结论:向一级缓存存入数据的时候,放入一级缓存区和一级缓存快照区,当更新了一级缓存的数据的时候,事务一旦提交,比对一级缓存和快照区,如果数据一致,不更新,如果数据不一致,自动更新数据库.
1.3.4 Hibernate管理一级缓存:
一级缓存是与session的生命周期相关的.session生命周期结束,一级缓存销毁了.
* clear()/evict()/flush()/refresh()管理一级缓存.
* clear()           :清空一级缓存中所有的对象.
* evict(Object obj) :清空一级缓存中某个对象.
* flush()           :刷出缓存.
* refresh(Object obj):将快照区的数据重新覆盖了一级缓存的数据.
#####1.3.5  Hibernate一级缓存的刷出时机:(了解.)
FlushMode:
* 常量:
* ALWAYS        :每次查询的时候都会刷出.手动调用flush.事务提交的时候.
* AUTO      :默认值.有些查询会刷出.手动调用flush.事务提交的时候.
* COMMIT        :在事务提交的时候,手动调用flush的时候.
* MANUAL        :只有在手动调用flush才会刷出.

严格程度:MANUAL > COMMIT > AUTO > ALWAYS

1.4 操作持久化对象的方法:

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

1.5 Hibernate关联关系的映射:

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

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

#####1.5.3  Hibernate中级联保存的效果:
级联:操作当前对象的时候,关联的对象如何处理.

cascade=”save-update”
级联方向性:
* 保存客户的时候,选择级联订单.
* 保存订单的时候,选择级联客户.

#####1.5.4  Hibernate中级联删除的效果:
cascade=”delete”
#####1.5.5  Hibernate中的级联取值:
none                :不使用级联
dave-update     :保存或更新的时候级联
delete          :删除的时候级联
all             :除了孤儿删除以外的所有级联.
delete-orphan   :孤儿删除(孤子删除).
* 仅限于一对多.只有一对多时候,才有父子存在.认为一的一方是父亲,多的一方是子方.
* 当一个客户与某个订单解除了关系.将外键置为null.订单没有了所属客户,相当于一个孩子没有了父亲.将这种记录就删除了.
all-delete-orphan   :包含了孤儿删除的所有的级联.
#####1.5.6  双向维护产生多余的SQL:
配置inverse=”true”:在那一端配置.那么那一端放弃了外键的维护权.
* 一般情况下,一的一方去放弃.

cascade:操作关联对象.
inverse:控制外键的维护.
1.5.7 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持久化对象的状态:
* 瞬时态:
* 持久态:
* 脱管态:

* 状态之间的转换:

Hibernate一级缓存:
* Hibernate的一级缓存的存在.
* get/load/save
* Hibernate的一级缓存的结构:
* 快照区.
* Hibernate一级缓存的管理:
* clear()/evict()/flush()/refresh();
* 刷出时机(了解)

Hibernate操作持久化对象常用方法:
* save();
* update();
* saveOrUpdate();
* 瞬时:执行save
* 脱管:执行update
* delete();
* get()/load();直接获得持久对象.

Hibernate的关联关系:(*****)
* 一对多的配置:(手动配置)
* 级联.
* 多对多的配置:(手动配置)
* 级联:
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容