hibernate系列二:hibernate中java对象的三种状态及数据更新的4种方式

一.  hibernate中java对象的三种状态

1.1 Java对象的三种状态介绍

    当应用通过调用Hibernate API与框架发生交互时,需要从持久化的角度关注应用对象的生命周期。持久化生命周期是Hibernate中的一个关键概念,正确地理解生命周期,可以更好地了解Hiberate的实现原理,掌握Hibernte的正确用法。Hibernate框架通过Session来管理Java对象的状态,在持久化生命周期中,Java对象存在着如下三种状态。
    1.瞬时状态( Transient)
    通过new创建对象后,对象并没有立刻持久化,它并未与数据库中的数据有任何的关联,此时Java对象的状态为瞬时状态。Session对于瞬时状态的Java对象是一无所知的,当对象不再被其他对象引用时,它的所有数据也就丢失了,对象将会被Java虚拟机按照垃圾回收机制处理。
    2.持久状态( Persistent)
  当对象与Session关联,被Session管理时,它就处于持久状态。处于持久状态的对象拥有数据库标识(数据库中的主键值)。那么,对象是什么时候与Session发生关联的呢?有两种方式:第一种,通过Session的查询接口,或者get()方法,或者load()方法从数据库中加载对象的时候,加载的对象是与数据库表中的一条记录关联的,此时对象与加载它的Session发生关联;第二种,瞬时状态的对象,通过调用Session的save()方法或SaveOrUpdate()方法时,Java对象也与Session发生关联。对于处于持久状态的对象,Session会持续跟踪和管理它们,如果对象的内部状态发生了任何变更,Hibernate会选择合适的时机(如事务提交时)将变更固化到数据库中。
    3.游离状态( Detached)
    处于持久状态的对象,脱离与其关联的Session的管理后,对象就处于游离状态。处于游离状态的对象,Hibernate无法保证对象所包含的数据与数据库中的记录一致,因为Hibernate已经无法感知对该对象的任何操作。Session提供了两个方法(update()、merge()),将处于游离状态的对象,与—个新的Session发生关联。这时,对象的状态就从游离状态重新转换为持久状态。

1.2 三种状态之间的转换
    在Hibemate应用中,不同的持久化操作会导致对象状态的改变。图1.20描述了对象状态的转换。

hibernate系列二:hibernate中java对象的三种状态及数据更新的4种方式_第1张图片

使用new关键字构建对象,该对象的状态是瞬时状态。
    1.瞬时状态转为持久状态
    使用Session对象的save()或saveOrUpdate()方法保存对象后,该对象的状态由瞬时状态转换为持久状态。
    使用Session对象的get()或load()方法获取对象,该对象的状态是持久状态。
    2.持久状态转为瞬时状态
    执行Session对象的delete()方法后,对象由原来的持久状态变为瞬时状态,因为此时该对象没有与任何的数据库数据关联。
    3.持久状态转为游离状态
    执行了Session对象的evict()--清除单个对象、clear()--清除所有对象或close()方法,对象由原来的持久状态转为游离状态。
    4.游离状态转为持久状态
    重新获取Session对象,执行Session对象的update()或saveOrUpdate()方法,对象由游离状态转为持久状态,该对象再次与Session对象相关联。
  5.游离状态转为瞬时状态
  执行Session对象的delete()方法,对象由游离状态转为瞬时状态。
  处于瞬时状态或游离状态的对象不再被其他对象引用时,会被Java虚拟机按照垃圾回收机制处理。

=======================================================

二.   数据更新的四种方式

2.1   利用脏检查进行数据更新

概念——脏对象:  如果持久状态的对象的属性发生了改变,例如调用了set方法,那么它就和数据库中的数据不一致了,则该对象就是脏对象.

package com.obtk.test;

import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;

import com.obtk.entitys.UserEntity;

public class TestModify {
	public static void main(String[] args) {
		SessionFactory factory=null;
		Session session=null;
		Configuration conf=null;
		Transaction tx=null;
		try {
			//读取配置文件
			conf=new Configuration();
			conf=conf.configure("hibernate.cfg.xml");
			//获得一个session工厂 
			factory=conf.buildSessionFactory();
			//获得数据库链接
			session=factory.openSession();
			tx=session.beginTransaction();
			//持久状态
			UserEntity user=(UserEntity)session.get(UserEntity.class, 6);
			//脏对象
			user.setUserName("大猩猩");
			user.setEmail("[email protected]");
			tx.commit();//进行了脏检查,commit会自动调用flush
			System.out.println("修改成功");
		} catch (HibernateException e) {
			tx.rollback();
			e.printStackTrace();
		}finally{
			if(session!=null){
				session.close();
			}
		}
	}
}
调用了tx.commit进行了脏检查,会进行更新操作。控制台会有更新语句生成。

       Session是Hibernate向应用程序提供的操纵数据库的主要接口,它提供了基本的保存、更新、删除和加载Java对象的方法。Session具有一个缓存,可以管理和跟踪所有持久化对象,对象和数据库中的相关记录对应。在某些时间点,Session会根据缓存中对象的变化来执行相关SQL语句,将对象包含的变化数据更新到数据库中,这一过程称为刷新缓存,换句话说就是将Session缓存同步刷新为与数据库一致。
当事务提交时,Hiberante会对Session中持久状态的对象进行检测,判断对象的数据是否发生了改变,这种判断称为脏检查。上面代码中user对象处于持久状态,userName属性发生改变,user对象即为脏对象。Hibernate为什么要进行脏检查呢?因为如果对象发生了改变,就需要将改变更新到数据库中,以确保内存中的对象与数据库中的数据保持一致。
    Session到底是如何进行脏检查的呢?当一个user对象被加入到Session缓存中时,Session会为user对象的值类型的属性复制一份快照。当Session刷新缓存时,会先进行脏检查,即比较user对象的当前属性与它的快照,来判断user对象的属性是否发生了变化。如果发生了变化,Session会根据脏对象的最新属性值来执行相关的SQL语句,将变化更新到数据库中。

    当Session缓存中对象的属性每次发生变化时,Session 并不会立即刷新缓存和执行相关的SQL语句,丽是在特定的时间点才刷新缓存。这使得Session能够把几条相关的SQL语句合并为一条或者一批SQL语句,减少了访问数据库的次数,从而提高应用程序的数据访问性能,
    在默认情况下,Session会在以下时间点刷新缓存。
    (1)当应用程序调用Transaction的commit()方法时,commit方法先调用Scssion的刷新缓存方法flush(),然后再向数据库提交事务。Hibernate之所以把刷新缓存的时间点安排在事务快结束时,一方面是因为可以减少访问数据库的频率,另一方面是因为可以尽可能缩短当前事务对数据库中相关资源的锁定时间。
    (2)当应用程序显式调用Session的flush()方法时,刷新缓存。
    Session的flush()方法和Transaction的commit()方法的区别:flush()方法进行刷新缓存的操作,执行一系列的SQL语句,但不会提交事务;commit ()方法会先凋用flush()方法,然后提交事务。提交事务意味着对数据库所做的更新被永久保存下来。


2. 2 利用update或saveOrUpdate更新数据

//持久状态
UserEntity user=(UserEntity)session.get(UserEntity.class, 6);
user.setUserName("大猩猩");
user.setEmail("[email protected]");
session.evict(user);  //清理一个对象
session.update(user);  //更新数据
-------------------------------------------

//瞬时状态
UserEntity user=new UserEntity();
user.setUserId(6);
user.setUserName("aaa");
user.setPassWord("123");
user.setEmail("[email protected]");
//数据库里面有就更新,没有就保存
session.saveOrUpdate(user);


2.3  merge方法

merge()方法,能够把一个游离状态对象的属性复制到一个持久化对象中,执行更新或插入(如果无法从Session缓存或数据库中加载到相应的持久化对象,则执行插入)操作并返回持久化的对象。若传人的是瞬时对象,则保存并返回其副本。无论何种情况,传人的对象状态都不受影响。

session=factory.openSession();
tx=session.beginTransaction();
//持久态
EmployeeEntity emp1=(EmployeeEntity)session.get(EmployeeEntity.class, 108);
//游离态
session.evict(emp1);
emp1.setEmpName("华哥");
//持久态
EmployeeEntity emp2=(EmployeeEntity)session.get(EmployeeEntity.class, 108);
session.merge(emp1);//把游离态的属性复制到一个持久态中,根据情况选择更新或插入操作
tx.commit();  //提交数据
    综上所述,如果当前Session缓存中没有包含具有相同OID的持久化对象(如打开Session后的首次操作),可以使用update()或saveOrUpdate()方法;如果想随时合并对象的修改而不考虑Session缓存中对象的状态,可以使用merge()方法。


















你可能感兴趣的:(hibernate)