hibernate 对象有三种状态,瞬时状态Transient,持久状态Persistent,脱管状态(Detached)。那这三种状态之间是如何进行转换的呢,我们通过例子来理解和学习,转换过程中会发送多少条sql,发怎样的sql。
先看一张图来理解三种状态之间的转换
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所托管