Hibernate的三态

一、瞬时态

一个对象刚被创建(实例化——new)的时候,还未与数据库进行关联的操作。
这时候的状态就被称为瞬时态。

特点

  • 不和 Session 实例关联
  • 在数据库中没有和瞬时对象关联的记录

二、持久态

持久化对象就是已经被保存进数据库的实体对象,并且这个实体对象现在还处于Hibernate的Session缓存管理之中
这时对该实体对象的任何修改,都会在清理缓存时同步到数据库中。

特点

  • 持久的实例在数据库中有对应的记录,并拥有一个持久化标识(identifier)。
  • 和session相关联的对象

三、游离态

游离态就犹如它的名字一样,像个无依无靠的孤儿。当一个持久化对象,脱离开Hibernate的缓存管理后,它就处于游离状态
游离对象和自由对象的最大区别在于,游离对象在数据库中可能还存在一条与它对应的记录,只是现在这个游离对象脱离了Hibernate的缓存管理,而自由对象不会在数据库中出现与它对应的数据记录。

特点

  • 本质上和瞬时对象相同
  • 只是比瞬时对象多了一个数据库记录标识值id。

四、三态的转化图

通过以下的转换图就可以明白三态之间是如何转换的:
这里写图片描述

五、实例解说

Test1:

session = HibernateUtil.openSession();  
       session.beginTransaction();  
       User user = new User();  
       user.setUsername("aaa");  
       user.setPassword("aaa");  
       user.setBorn(new Date());  
       /* 
        * 以上user就是一个Transient(瞬时状态),此时user并没有被session进行托管,即在session的 
        * 缓存中还不存在user这个对象,当执行完save方法后,此时user被session托管,并且数据库中存在了该对象 
        * user就变成了一个Persistent(持久化对象) 
        */  
       session.save(user);  
       session.getTransaction().commit();

这时hibernate会发出一条insert的语句,执行完save方法后,该user对象就变成了持久化的对象了。

Hibernate: insertinto t_user (born, password, username) values (?, ?, ?)

Test2

session = HibernateUtil.openSession();  
           session.beginTransaction();  
           User user = new User();  
           user.setUsername("aaa");  
           user.setPassword("aaa");  
           user.setBorn(new Date());  
           //以上u就是Transient(瞬时状态),表示没有被session管理并且数据库中没有  
           //执行save之后,被session所管理,而且,数据库中已经存在,此时就是Persistent状态  
           session.save(user);  
           //此时u是持久化状态,已经被session所管理,当在提交时,会把session中的对象和目前的对象进行比较  
           //如果两个对象中的值不一致就会继续发出相应的sql语句  
           user.setPassword("bbb");  
           //此时会发出2条sql,一条用户做插入,一条用来做更新  
           session.getTransaction().commit(); 

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

Hibernate: insertinto t_user (born, password, username) values (?, ?, ?)  
Hibernate: updatet_user set born=?, password=?, username=? where id=? 

Test3:

session = HibernateUtil.openSession();  
           session.beginTransaction();  
           //此时u是Persistent  
           User u =(User)session.load(User.class, 4);  
           u.setUsername("123");  
           //清空session  
           session.clear();  
           session.getTransaction().commit(); 

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

Hibernate: selectuser0_.id as id0_0_, user0_.born as born0_0_, user0_.password as password0_0_,user0_.username as username0_0_ from t_user user0_ where user0_.id=?  

Test4

session = HibernateUtil.openSession();  
            session.beginTransaction();  
            //此时u是一个离线对象,没有被session托管  
            User u = new User();  
            u.setId(4);  
           u.setPassword("hahahaha");  
            //当执行save的时候总是会添加一条数据,此时id就会根据Hibernate所定义的规则来生成  
            session.save(u);  
            session.getTransaction().commit();  

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

Hibernate: insertinto t_user (born, password, username) values (?, ?, ?) 

所以对于离线对象,如果要使其变成持久化对象的话,我们不能使用save方法,而应该使用update方法

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");  
           session =HibernateUtil.openSession();  
           session.beginTransaction();  
           User u = new User();  
           u.setId(5);  
           //完成update之后也会变成持久化状态  
           session.update(u);  
          u.setBorn(sdf.parse("1998-12-22"));  
           u.setPassword("world");  
           u.setUsername("world");  
           //会发出一条sql  
           session.update(u);  
           session.getTransaction().commit(); 

此时Hibernate会发送一条update语句,对象转换成持久态

Hibernate: updatet_user set born=?, password=?, username=? where id=?

Test5

session = HibernateUtil.openSession();  
           session.beginTransaction();  
           User u = new User();  
           u.setId(4);  
           u.setPassword("zhaoliu");  
           //如果u是离线状态就执行update操作,如果是瞬时状态就执行Save操作  
           //但是注意:该方法并不常用  
           session.saveOrUpdate(u);  
           session.getTransaction().commit();

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

Hibernate: updatet_user set born=?, password=?, username=? where id=?

如果此时我将u.setId(4)这句话注释掉,那么此时u就是一个瞬时的对象,那么此时就会执行save操作,就会发送一条insert语句

Hibernate: insertinto t_user (born, password, username) values (?, ?, ?)

Test6:

session = HibernateUtil.openSession();  
           session.beginTransaction();  
           //u1已经是持久化状态  
           User u1 =(User)session.load(User.class, 3);  
          System.out.println(u1.getUsername());  
           //u2是离线状态  
           User u2 = new User();  
           u2.setId(3);  
          u2.setPassword("123456789");  
           //此时u2将会变成持久化状态,在session的缓存中就存在了两份同样的对象,在session中不能存在两份拷贝,否则会抛出异常  
           session.saveOrUpdate(u2);

此时我们的u1已经是持久化的对象了,保存在session缓存中,u2通过调用saveOrUpdate方法后也变成了一个持久化的对象,此时也会保存在session缓存中,这个时候session缓存中就存在了一个持久化对象有两个引用拷贝了,这个时候hibernate就会报错

一个session中不能存在对一个持久化对象的双重copy的,要解决这个方法,我们这里又要介绍session的另一个方法 merge方法,这个方法的作用就是解决一个持久化对象两分拷贝的问题,这个方法会将两个对象合并在一起成为一个对象。

session = HibernateUtil.openSession();  
            session.beginTransaction();  
            //u1已经是持久化状态  
            User u1 =(User)session.load(User.class, 3);  
           System.out.println(u1.getUsername());  
            //u2是离线状态  
            User u2 = new User();  
            u2.setId(3);  
           u2.setPassword("123456789");  
            //此时u2将会变成持久化状态,在session的缓存中就存在了两份同样的对象,在session中不能存在两份拷贝,否则会抛出异常  
            //session.saveOrUpdate(u2);  
            //merge方法会判断session中是否已经存在同一个对象,如果存在就将两个对象合并  
            session.merge(u2);  
            //最佳实践:merge一般不用  
            session.getTransaction().commit(); 

此时会将session中的两个持久化对象合并为一个对象,但是merge方法不建议被使用

Hibernate: selectuser0_.id as id0_0_, user0_.born as born0_0_, user0_.password as password0_0_,user0_.username as username0_0_ from t_user user0_ where user0_.id=?  
zhangsan  
Hibernate: updatet_user set born=?, password=?, username=? where id=?

转载自:Hibernate之三态篇
作者:liu_yujie2011com

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值