我们都知道,Java对象的生命周期,是从通过new语句创建开始,到不再被任何引用变量引用结束,结束后它占
用的内存将被JVM垃圾回收机制收回。在Hibernate持久化对象可以划分为三种状态,瞬时对象(Transient
Objects)、持久化对象(Persistent Objects)和离线对象(Detached Objects也叫做脱管对象)。
瞬时对象(Transient Objects)
使用new操作符初始化的对象不是立刻就持久的。它们的状态是瞬时的,也就是说它们没有任何跟数据库表相关
联的行为,只要应用不再引用这些对象(不再被任何其它对象所引用),它们的状态将会丢失,并由垃圾回收机制回
收。
持久化对象(Persist Objects)
持久实例是任何具有数据库标识的实例。它有持久化管理器Session统一管理,持久实例是在事务中进行操作的
——它们的状态在事务结束时同数据库进行同步。当事务提交时,通过执行SQL的INSERT、UPDATE和DELETE语句
把内存中的状态同步到数据库中。
离线对象(Detached Objects)
Session关闭之后,持久化对象就变为离线对象。离线表示这个对象不能再与数据库保持同步,它们不再受
Hibernate管理。
持久化对象的三状态解析:
瞬时状态
瞬时状态(Transient),也叫临时状态。处于这种状态的对象具备的特征如下:不在Session的缓存中,不与任何
的Session实例相关联;在数据库中没有与之相对应的记录。
由Java的new命令开辟内存空间的Java对象也就是普通的Java对象,如果没有变量引用它它将会被JVM收回。临
时对象在内存中是孤立存在的,它的意义是携带信息载体,不和数据库中的数据由任何的关联。通过Session的save()
方法和saveOrUpdate()方法可以把一个临时对象和数据库相关联,并把临时对象携带的信息通过配置文件所做的映
射插入数据库中,这个临时对象就成为持久化对象。
持久状态
持久状态(Persistent),处于这种状态的对象具备的特征如下:在Session的缓存中,与Session实例相关联;在数
据库中存在与之相对应的记录。
持久化对象在数据库中有相应的记录,持久化对象可以是刚被保存的,或者刚被加载的,但都是在相关联的
session声明周期中保存这个状态。如果是直接数据库查询所返回的数据对象,则这些对象和数据库中的字段相关联,
具有相同的id,它们马上变成持久化对象。如果一个临时对象被持久化对象引用,也立马变为持久化对象。
如果使用delete()方法,持久化对象变为临时对象,并且删除数据库中相应的记录,这个对象不再与数据库有任
何的联系。
持久化对象总是与Session和Transaction关联在一起,在一个session中,对持久化对象的操作不会立即写到数据
库,只有当Transaction(事务)结束时,才真正的对数据库更新,从而完成持久化对象和数据库的同步。在同步之
前的持久化对象成为脏对象。
当一个session执行close()、clear()、或evict()之后,持久化对象就变为离线对象,这时对象的id虽然拥有数据库
的识别值,但已经不在Hibernate持久层的管理下,他和临时对象基本上一样的,只不过比临时对象多了数据库标识
id。没有任何变量引用时,JVM将其回收。
脱管状态
脱管状态(Detached),也叫游离状态。处于这种状态的对象具备的特征如下:不在Session的缓存中,不与任何
的Session实例相关联;在数据库中存在与之相对应的记录。(前提条件是没有其他Session实例删除该条记录)。
Session关闭之后,与此Session关联的持久化对象就变成为脱管对象,可以继续对这个对象进行修改,如果脱管
对象被重新关联到某个新的Session上,会在此转成持久对象。
脱管对象虽然拥有用户的标识id,所以通过update()、saveOrUpdate()等方法,再次与持久层关联。
持久化对象的三种状态是可以相互转化的,具体转换过程如图所示:
实例
下面我们就通过使用Hibernate框架,实现对数据库的增删改查来体现三种状态之间的转换过程。
我们新建的项目实例的HIbernate核心配置文件:
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- 连接数据库参数 -->
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/hibernate</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">root</property>
<!-- MySQL数据库方言 -->
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- 输出SQL语句到控制台 -->
<property name="hibernate.show_sql">true</property>
<property name="hibernate.format_sql">true</property>
<!-- 自动将hbm映射文件生成ddl语句 -->
<property name="hibernate.hbm2ddl.auto">update</property>
<!-- 使用getCurrentSession获取session -->
<property name="hibernate.current_session_context_class">thread</property>
<!-- 对象关系映射文件地址 -->
<mapping resource="com/demo/domain/User.hbm.xml"/>
<!--
<mapping resource="com/demo/domain/User1.hbm.xml"/>
<mapping resource="com/demo/domain/User2.hbm.xml"/>
<mapping resource="com/demo/domain/User3.hbm.xml"/>
-->
</session-factory>
</hibernate-configuration>
实体类User:
package com.demo.domain;
import java.util.Date;
/**
* User实体类
* @author Administrator
* @date 2016年12月4日
*/
public class User {
private String id;
private String name;
private String password;
private Date createTime;
private Date expireTime;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public Date getExpireTime() {
return expireTime;
}
public void setExpireTime(Date expireTime) {
this.expireTime = expireTime;
}
@Override
public String toString() {
return "User [id=" + id + ", name=" + name + ", password=" + password + ", createTime=" + createTime
+ ", expireTime=" + expireTime + "]";
}
}
对象关系映射文件:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- 对象关系映射配置文件 -->
<hibernate-mapping>
<!-- 通过User实体类映射出user表 -->
<class name="com.demo.domain.User" table="user">
<!-- 映射主键 -->
<id name="id">
<!-- 主键生成策略机制 -->
<generator class="uuid"/>
</id>
<!-- 映射普通字段 -->
<property name="name"/>
<property name="password"/>
<property name="createTime"/>
<property name="expireTime"/>
</class>
</hibernate-mapping>
当我们建立Session都要实例化SessionFactory,所以我们把重复的代码进行封装,并且session是单线程的。我
们把对session的管理,打开session,关闭session等封装到工具类HibernateUtils中,代码如下:
package com.demo.domain;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
/**
* 得到会话工厂的工具类
* @author Administrator
* @date 2016年12月8日
*/
public class HibernateUtils {
//静态变量
private static SessionFactory factory;
//静态代码块,只会装载一次
static {
try {
//读取hibernate.cfg.xml文件
Configuration cfg = new Configuration().configure();
//建立SessionFactory
factory = cfg.buildSessionFactory();
}catch(Exception e) {
e.printStackTrace();
}
}
//通过静态方法得到session
public static Session getSession() {
return factory.openSession();
}
//通过静态方法关闭session
public static void closeSession(Session session) {
if (session != null) {
if (session.isOpen()) {
session.close();
}
}
}
//通过静态方法得到会话工厂
public static SessionFactory getSessionFactory() {
return factory;
}
}
测试类:
package com.demo.test;
import java.util.Date;
import junit.framework.TestCase;
import org.hibernate.Session;
import org.hibernate.Transaction;
import com.demo.domain.HibernateUtils;
import com.demo.domain.User;
public class SessionTest extends TestCase {
public void testSave1() {
Session session = null;
Transaction tx = null;
try {
session = HibernateUtils.getSession();
tx = session.beginTransaction();
//user对象刚创建时为Transient状态
User user = new User();
user.setName("张三");
user.setPassword("123456");
user.setCreateTime(new Date());
user.setExpireTime(new Date());
/*
* 进行保存,执行save则对session进行管理了. 处于Persistent状态
* Persistent状态的对象,当对象的属性发生改变的时候
* hibernate在清理缓存(脏数据检查)的时候,会和数据库同步
*/
session.save(user);//insert语句
//更新user对象的name值李四
user.setName("李四");//update语句
//可以显示的调用update方法,因为此时为持久状态,调用update没有什么意义
//session.update(user);
//提交事务
tx.commit();
}catch(Exception e) {
e.printStackTrace();
if (tx != null) {
//回滚事务
tx.rollback();
}
}finally {
//关闭session.当关闭session时处于Detached状态.
HibernateUtils.closeSession(session);
}
}
public void testSave2() {
Session session = null;
Transaction tx = null;
User user = null;
try {
session = HibernateUtils.getSession();
tx = session.beginTransaction();
//Transient状态
user = new User();
user.setName("陈曦");
user.setPassword("123456");
user.setCreateTime(new Date());
user.setExpireTime(new Date());
/*
* 进行保存,执行save则对session进行管理了. 处于Persistent状态
* Persistent状态的对象,当对象的属性发生改变的时候
* hibernate在清理缓存(脏数据检查)的时候,会和数据库同步
*/
session.save(user);
//更新
user.setName("陈艾");
tx.commit();
}catch(Exception e) {
e.printStackTrace();
if (tx != null) {
tx.rollback();
}
}finally {
//Detached状态
HibernateUtils.closeSession(session);
}
//已经不能用以前的session了
user.setName("陈成");
try {
//得到新的session
session = HibernateUtils.getSession();
session.beginTransaction();
//将Detached状态的对象重新纳入session管理
//此时将变为Persistent状态的对象
//Persistent状态的对象,在清理缓存是会和数据库同步
session.update(user);
session.getTransaction().commit();
}catch(Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally {
HibernateUtils.closeSession(session);
}
}
}
testSave1()方法
首先是建立对象与表的会话session,开启事务session.beginTransaction(),实例化User对象,当我们User user
= new User()的时候,当我们new一个对象的时候数据库是没有的,所以是Transient对象(临时对象),然后给
user赋值,设置名称和密码以及其他属性。 为对象的所有属性赋值完毕,接下来保存到会话session中,拿到session
执行save(user)方法。 当我们执行session的save()方法时,这个对象就被session管理了,session中有个
map,会把对象放到map中,此时的对象我们就成为Persistent状态(持久状态)。接下来我们又把user中的name
属性设置为“李四”,之后提交事务。我们先再会话中存储的“张三”,之后改为“李四”。try catch来扑捉异常,
当执行完毕,关闭session后,对象处于detached状态(离线状态)。
控制台输出:
数据库显示:
testSave2()方法:
只是解释后面第二次更新,也就是把"陈艾"改为"陈成",取得Detached状态的user对象,改变这个对象的name
值,user.setName("陈成");之后我们再new一个新的session,通过session开启事务,之后更新操作,
session.update(user),也就是把离线的对象(或脱管对象)再纳入session管理,这样就会和数据库同步,因为
session.update()就把user对象纳入session管理,user对象由离线状态变为Persistent状态。
控制台输出:
数据库显示: