介绍
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)
- 瞬时(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。
如果你希望一个操作被顺着关联关系级联传播,你必须在映射文件中指出这一点。例如:
<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 的时候才作用到所有可触及的被关联对象上的。
以上。。。