Hibernate学习之对象的状态及其转换

介绍

Hibernate 是完整的对象/关系映射解决方案,它提供了对象状态管理的功能,使开发者不再需要理会底层数据库系统的细节。也就是说,相对于常见的 JDBC/SQL 持久层方案中需要管理 SQL 语句,Hibernate 采用了更自然的面向对象的视角来持久化 Java 应用中的数据。

换句话说,使用 Hibernate 的开发者应该总是关注对象的状态(state),不必考虑 SQL 语句的执行。这部分细节已经由 Hibernate 掌管妥当。只有开发者在进行系统性能调优的时候才需要进行了解。

将在下面使用的两个类

Kitten.java(多方)

public class Kitten implements Serializable {

    private static final long serialVersionUID = -4355590460524700915L;
    private long kid;
    private String kname;
    private String Color;
    //维护多对一关系
    private MotherCat mothercat;

    public MotherCat getMothercat() {
        return mothercat;
    }
    public void setMothercat(MotherCat mothercat) {
        this.mothercat = mothercat;
    }
    public long getKid() {
        return kid;
    }
    public void setKid(long kid) {
        this.kid = kid;
    }
    public String getKname() {
        return kname;
    }
    public void setKname(String kname) {
        this.kname = kname;
    }
    public String getColor() {
        return Color;
    }
    public void setColor(String color) {
        Color = color;
    }
}

MotherCat.java(一方)

public class MotherCat implements Serializable {

    private static final long serialVersionUID = 5903592525972293730L;

    private long mid;
    private String mname;
    private String Color;

    /*private Set<Kitten> kittenSet = new HashSet<Kitten>();

    public Set<Kitten> getKittenSet() {
        return kittenSet;
    }
    public void setKittenSet(Set<Kitten> kittenSet) {
        this.kittenSet = kittenSet;
    }*/
    public long getMid() {
        return mid;
    }
    public void setMid(long mid) {
        this.mid = mid;
    }
    public String getMname() {
        return mname;
    }
    public void setMname(String mname) {
        this.mname = mname;
    }
    public String getColor() {
        return Color;
    }
    public void setColor(String color) {
        Color = color;
    }

}

使用单向多对一关联关系

Hibernate 对象状态(object states)

Hibernate 定义并支持下列对象状态(state):

瞬时(Transient)

  1. 瞬时(Transient) — 由 new 操作符创建,且尚未与Hibernate Session 关联的对象被认定为瞬时(Transient)的。
  2. 瞬时(Transient)对象不会被持久化到数据库中,也不会被赋予持久化标识(identifier)。
  3. 如果瞬时(Transient)对象在程序中没有被引用,它会被垃圾回收器(GC)销毁。
  4. 使用 Hibernate Session可以将其变为持久(Persistent)状态。(Hibernate会自动执行必要的SQL语句)。

持久(Persistent)

  1. 持久(Persistent) — 持久(Persistent)的实例在数据库中有对应的记录,并拥有一个持久化标识(identifier)。
  2. 持久(Persistent)的实例可能是刚被保存的,或刚被加载的,无论哪一种,按定义,它存在于相关联的Session作用范围内
  3. Hibernate会检测到处于持久(Persistent)状态的对象的任何改动,在当前操作单元执行完毕时,会将对象数据与数据库同步,开发者不需要手动执行UPDATE。将对象从持久(Persistent)状态变成瞬时(Transient)状态同样也不需要手动执行 DELETE 语句。

脱管(Detached)

  1. 脱管(Detached) — 与持久(Persistent)对象关联的Session被关闭后,对象就变为脱管(Detached)的。对脱管(Detached)对象的引用依然有效,对象可继续被修改。
  2. 脱管(Detached)对象如果重新关联到某个新的 Session 上, 会再次转变为持久(Persistent)的(在Detached其间的改动将被持久化到数据库)。

接下来我们来细致地讨论下状态(states)及状态间的转换(state transitions)(以及触发状态转换的 Hibernate 方法)。

对象持久化

eg:

public void objectPersistent() {
    Session session = HibernateUtil.getSessionFactory().getCurrentSession();
    session.beginTransaction();
    /*
     *K,m对象是瞬时状态的 
     */
    Kitten k = new Kitten();
    k.setKname("叮当");
    k.setColor("蓝色");

    MotherCat m = new MotherCat();
    m.setMname("叮当的妈妈");
    m.setColor("蓝色");

    k.setMothercat(m);
    /*
     * save方法持久化实例对象和其相关联的实例对象,并返回一个标识符。
     */
    long generatedId = (long) session.save(k);
    System.out.println(generatedId);        

    //事物提交后,会自动关闭当前session
    session.getTransaction().commit();
}

装载对象

如果你知道某个实例的持久化标识(identifier),你就可以使用 Session 的 load() 方法来获取它。本方法会创建指定类的持久化实例,并从数据库加载其数据

任何时候都可以使用refresh()方法强迫装载对象和它的集合。如果你使用数据库触发器功能来处理对象的某些属性,这个方法就很有用了。

eg:

public void objectLoad() {
    Session session = HibernateUtil.getSessionFactory().getCurrentSession();
    session.beginTransaction();

    //返回给定带有标识符的实体类的持久化实例或代理
    Kitten k = (Kitten) session.load(Kitten.class, 1L);
    k.setColor("黑白色");

    //迫使执行update SQL语句
    /*session.flush();
    session.refresh(k);
    */
    session.getTransaction().commit();
}

修改持久化对象

事务中的持久化实例(就是通过 session 装载、保存、创建或者查询出的对象) 被应用程序操作所造成的任何修改都会在 Session 被刷出(flushed)的时候被持久化(后面会详细讨论)。

这里不需要调用某个特定的方法(比如 update())将你的对象修改为持久化状态。

所以最直接的更新一个对象的方法就是在 Session 处于打开状态时 load() 它,然后直接修改即可:

Kitten k = (Kitten) session.load(Kitten.class, 1L);
k.setColor("黑白色");
session.flush();

修改脱管(Detached)对象

Hibernate 通过提供 Session.update() 或 Session.merge() 重新关联脱管实例。

如果你确定当前 session 没有包含与之具有相同持久化标识的持久实例,使用 update()。如果想随时合并你的的改动而不考虑 session 的状态,使用 merge()。

换句话说,在一个新 session 中通常第一个调用的是 update() 方法,以便保证重新关联脱管(detached)对象的操作首先被执行。

lock() 方法也允许程序重新关联某个对象到一个新 session 上。不过,该脱管(detached)的对象必须是没有修改过的。

eg:

    /*
     *一个session和transaction 
     */
    Session session = HibernateUtil.getSessionFactory().getCurrentSession();        
    session.beginTransaction();

    MotherCat mothercat = (MotherCat) session.load(MotherCat.class, 1L);
    Kitten k = new Kitten();        

    session.save(k);

    //在表现层被修改
    k.setKname("熊熊");
    k.setColor("棕色");   
    k.setMothercat(mothercat);

    /*
     * 一个新的session与transaction
     */
    Session session2 = HibernateUtil.getSessionFactory().getCurrentSession();           
    session2.beginTransaction();

    session2.update(k);

    //session2.merge(k);

    session2.getTransaction().commit();

你只要没有尝试在某个 session 中使用来自另一 session 的实例,你就应该不需要使用 update(), saveOrUpdate(),或 merge()。

删除持久对象

使用 Session.delete() 会把对象的状态从数据库中移除。当然,你的应用程序可能仍然持有一个指向已删除对象的引用。

所以,最好这样理解:delete() 的用途是把一个持久实例变成瞬时(transient)实例

Session 刷出(flush)

每间隔一段时间,Session 会执行一些必需的 SQL 语句来把内存中的对象的状态同步到 JDBC 连接中。这个过程被称为刷出(flush),默认会在下面的时间点执行:

  1. 在某些查询执行之前
  2. 在调用 org.hibernate.Transaction.commit() 的时候
  3. 在调用 Session.flush() 的时候

有一个例外是,如果对象使用 native 方式来生成 ID(持久化标识)的话,它们一执行 save 就会被插入。

除非你明确地发出了 flush() 指令,关于 Session 何时会执行这些 JDBC 调用是完全无法保证的,只能保证它们执行的前后顺序。当然,Hibernate 保证,Query.list(..) 绝对不会返回已经失效的数据,也不会返回错误数据。

传播性持久化(transitive persistence)

每个 Hibernate session 的基本操作

包括 :persist(), merge(), saveOrUpdate(), delete(), lock(), refresh(), evict(), replicate()

对应的级联风格(cascade style):
分别命名为 create, merge, save-update, delete, lock, refresh, evict, replicate

如果你希望一个操作被顺着关联关系级联传播,你必须在映射文件中指出这一点。例如:

<one-to-one name="person" cascade="persist"/>

级联风格(cascade style)是可组合的:

<one-to-one name="person" cascade="persist,delete,lock"/>

你可以使用 cascade=”all” 来指定全部操作都顺着关联关系级联(cascaded)。默认值是 cascade=”none”,即任何操作都不会被级联(cascaded)。

在多对一或多对多关系上,启用级联(cascade)通常是没有意义的。
级联(cascade)在一对一或一对多关联中常常是有用的。

最后,注意级联的操作可能是在调用期(call time)或者写入期(flush time)作用到对象图上的。

所有的操作,如果允许,都在操作被执行的时候级联到可触及的关联实体上。
然而,save-upate 和 delete-orphan 是在Session flush 的时候才作用到所有可触及的被关联对象上的

以上。。。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值