Hibernate 三种对象状态详解

hibernate 对象有三种状态,瞬时状态Transient,持久状态Persistent,脱管状态(Detached)。那这三种状态之间是如何进行转换的呢,我们通过例子来理解和学习,转换过程中会发送多少条sql,发怎样的sql。
先看一张图来理解三种状态之间的转换
Hibernate 三种对象状态详解_第1张图片
1、瞬时状态

/**
 * *瞬时状态Transient
 */
	@Test
	public void Transient() {
		Girl girl = new Girl();
		girl.setName("aaa");
		/*
		 * 以上的girl对象就是一个Transient(瞬时)状态,此时user并没有被session进行托管,
		 *  即在session的 缓存中还不存在user这个对象当执行完save方法后,此时user被session托管,
		 * 并且数据库中存在了该对象user就变成了一个Persistent(持久化对象)
		 */
		session.save(girl);
		tx.commit();
	}

控制台:发送一条插入语句,执行完save方法后,girl对象就变为持久化对象了
Hibernate:
Insert intot_girl (name, stu_id, id) values(?, ?, ?)

2、持久状态:
①、

@Test
	public void Persistent1() {
		Girl girl = new Girl();
		//girl就是Transient(瞬时状态),表示没有被session管理并且数据库中没有
		//执行save之后,被session所管理,而且,数据库中已经存在,此时就是Persistent状态
		girl.setName("aaa");
		//此时girl是持久化状态,已经被session所管理,当在提交时,会把session中的对象和目前的对象进行比较
		session.save(girl);
		//如果两个对象中的值不一致就会继续发出相应的sql语句
		girl.setName("bbb");
		//此时会发出2条sql,一条用户做插入,一条用来做更新
		tx.commit();
	}

小结:在调用了save方法后,此时girl已经是持久化对象了,被保存在了session缓存当中,这时girl又重新修改了属性值,那么在提交事务时,此时hibernate对象就会拿当前这个girl对象和保存在session缓存中的girl对象进行比较,如果两个对象相同,则不会发送update语句,否则,如果两个对象不同,则会发出update语句。

控制台输出:
Hibernate:
insert intot_girl(name, stu_id, id) values(?, ?, ?)
Hibernate:
updatet_girl set name=?,stu_id=? Where id=?

在调用save方法后,girl此时已经是持久化对象了,记住一点:如果一个对象以及是持久化状态了,那么此时对该对象进行各种修改,或者调用多次update、save方法时,hibernate都不会发送sql语句,只有当事物提交的时候,此时hibernate才会拿当前这个对象与之前保存在session中的持久化对象进行比较,如果不相同就发送一条update的sql语句,否则就不会发送update语句

②、

@Test
	public void Persistent2() {
		Girl girl = (Girl) session.load(Girl.class, 1);
		 //此时girl是Persistent
		girl.setName("ccc");
		 //由于girl这个对象和session中的对象不一致,所以会发出sql完成更新
		tx.commit();
	}

小结:当session调用load、get方法时,此时如果数据库中有该对象,则该对象也变成了一个持久化对象,被session所托管。因此,这个时候如果对对象进行操作,在提交事务时同样会去与session中的持久化对象进行比较,因此这里会发送两条sql语句

控制台输出:
Hibernate: select girl0_.id as id0_0_, girl0_.name as name0_0_, girl0_.stu_id as stu3_0_0_ from t_girl girl0_ where girl0_.id=?

Hibernate: update t_girl set name=?, stu_id=? where id=?

③、

@Test
	public void Persistent3() {
		Girl girl = (Girl) session.load(Girl.class,2);
		//此时girl是Persistent
		girl.setName("666");
		session.clear();
		//清空session
		tx.commit();
	}

小结:当我们load出user对象时,此时user是持久化的对象,在session缓存中存在该对象,此时我们在对user进行修改后,然后调用session.clear()方法,这个时候就会将session的缓存对象清空,那么session中就没有了user这个对象,这个时候在提交事务的时候,发现已经session中已经没有该对象了,所以就不会进行任何操作,因此这里只会发送一条select语句

控制台输出:
Hibernate: select girl0_.id as id0_0_, girl0_.name as name0_0_, girl0_.stu_id as stu3_0_0_ from t_girl girl0_ where girl0_.id=?

3、脱管状态
①、

/**
	 * *脱管状态(Detached)
	 */
	@Test
	public void Detached1() {
		Girl girl = new Girl();
		 //此时girl是一个离线对象,没有被session托管
		girl.setId(1);
		girl.setName("888");
		 //当执行save的时候总是会添加一条数据,此时id就会根据Hibernate所定义的规则来生成
		session.save(girl);
		tx.commit();
	}

小结:当调用了girl.setId(1)时,此时girl是一个离线的对象,因为数据库中存在id=1的这个对象,但是该对象又没有被session所托管,所以这个对象就是离线的对象,要使离线对象变成一个持久化的对象,应该调用什么方法呢?我们知道调用save方法,可以将一个对象变成一个持久化对象,但是,当save一执行的时候,此时hibernate会根据id的生成策略往数据库中再插入一条数据

控制台输出:Hibernate: insert into t_girl (name, stu_id, id) values (?, ?, ?)
所以对于离线对象,如果要使其变成持久化对象的话,我们不能使用save方法,而应该使用update方法

②、

@Test
	public void Detached2() {
		Girl girl = new Girl();
		//此时girl是一个离线对象,没有被session托管
		girl.setId(2);
		//完成update之后也会变成持久化状态
		session.update(girl);
		girl.setName("123");
		session.update(girl);
		//会发出一条sql
		tx.commit();
	}

小结:当调用了update方法以后,此时u已经变成了一个持久化的对象,那么如果此时对u对象进行修改操作后,在事务提交的时候,则会拿该对象和session中刚保存的持久化对象进行比较,如果不同就发一条sql语句

控制台输出:Hibernate: update t_girl set name=?, stu_id=? where id=?

③、

@Test
	public void Detached3() {
		Girl girl = new Girl();
		girl.setId(7);
		//现在u就是transient对象
		session.delete(girl);
		//此时u已经是瞬时对象,不会被session和数据库所管理
		girl.setName("456");
		tx.commit();
	}

小结:调用了session.delete()方法以后,此时后u就会变成一个瞬时对象,因为此时数据库中已经不存在该对象了,既然u已经是一个瞬时对象了,那么对u再进行各种修改操作的话,hibernate也不会发送任何的修改语句

控制台:Hibernate: delete from t_girl where id=?

④、

@Test
	public void Detached4() {
		Girl girl = new Girl();
		girl.setId(1);
		girl.setName("haha");
		//如果u是离线状态就执行update操作,如果是瞬时状态就执行Save操作
        //但是注意:该方法并不常用
		session.saveOrUpdate(girl);
		tx.commit();
	}

小结:saveOrUpdate这个方法,这个方法其实是一个"偷懒"的方法,如果对象是一个离线对象,那么在执行这个方法后,其实是调用了update方法,如果对象是一个瞬时对象,则会调用save方法,记住:如果对象设置了ID值,例如u.setId(4),那么该对象会被假设当作一个离线对象,此时就会执行update操作。

控制台输出:Hibernate: update t_girl set name=?, stu_id=? where id=?

最后总结一下:
①.对于刚创建的一个对象,如果session中和数据库中都不存在该对象,那么该对象就是瞬时对象(Transient)
②.瞬时对象调用save方法,或者离线对象调用update方法可以使该对象变成持久化对象,如果对象是持久化对象时,那么对该对象的任何修改,都会在提交事务时才会与之进行比较,如果不同,则发送一条update语句,否则就不会发送语句
③.离线对象就是,数据库存在该对象,但是该对象又没有被session所托管

你可能感兴趣的:(hibernate三种对象,hibernate,三种对象)