疯狂java


您现在的位置: 疯狂软件 >> 新闻资讯 >> 正文

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 kittenSet = new HashSet();

  public Set getKittenSet() {

  return kittenSet;

  }

  public void setKittenSet(Set 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)

  瞬时(Transient) — 由 new 操作符创建,且尚未与Hibernate Session 关联的对象被认定为瞬时(Transient)的。

  瞬时(Transient)对象不会被持久化到数据库中,也不会被赋予持久化标识(identifier)。

  如果瞬时(Transient)对象在程序中没有被引用,它会被垃圾回收器(GC)销毁。

  使用 Hibernate Session可以将其变为持久(Persistent)状态。(Hibernate会自动执行必要的SQL语句)。

  持久(Persistent)

  持久(Persistent) — 持久(Persistent)的实例在数据库中有对应的记录,并拥有一个持久化标识(identifier)。

  持久(Persistent)的实例可能是刚被保存的,或刚被加载的,无论哪一种,按定义,它存在于相关联的Session作用范围内。

  Hibernate会检测到处于持久(Persistent)状态的对象的任何改动,在当前操作单元执行完毕时,会将对象数据与数据库同步,开发者不需要手动执行UPDATE。将对象从持久(Persistent)状态变成瞬时(Transient)状态同样也不需要手动执行 DELETE 语句。

  脱管(Detached)

  脱管(Detached) — 与持久(Persistent)对象关联的Session被关闭后,对象就变为脱管(Detached)的。对脱管(Detached)对象的引用依然有效,对象可继续被修改。

  脱管(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),默认会在下面的时间点执行:

  在某些查询执行之前

  在调用 org.hibernate.Transaction.commit() 的时候

  在调用 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。

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

  

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

  

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

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

  级联(cascade)在一对一或一对多关联中常常是有用的。

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

  所有的操作,如果允许,都在操作被执行的时候级联到可触及的关联实体上。

  然而,save-upate 和 delete-orphan 是在Session flush 的时候才作用到所有可触及的被关联对象上的。

  以上。。。