最近维护一个别人的项目,里面用到hibernate,顺便学习hibernate,也解决了一些坑,记录下来。
hibernate是一个orm框架,与mybatis不同的是,它通过对象实体来管理数据库。那么在hibernate中对象也分为三种状态

  • 瞬时态(transient)
  • 持久态(persistent)
  • 离线(detached)

这三种状态贯串实体的整个生命周期内,与jvm的垃圾回收不同。


瞬时状态是对象刚创建完成,没有用hibernate进行持久化操作,简而言之就是对象刚new出来,没有进行任何操作。

1
2
3
User user = new User();
user.setUsername("bingzzz");
user.setPassword("zzz");

上面这种对象在hibernate中就是瞬时状态。


持久化状态是通过hibernate操作将对象数据保存在数据库中的操作,从瞬时态转到持久化状态可以通过save or saveorUpdate操作

1
2
getSession.save(user);
getSession.saveorUpdate(user);

save和saveOrUpdate的区别是save只是单纯的保存实体对象到数据库中,saveOrUpdate如果session中存在此对象,则进行更新操作,不存在则保存操作。当进行持久化操作时,会将对象实体保存在session缓存中,这时候就有一个问题了,当保存到缓存中后,我修改了对象中某个字段的值,如果一个对象以及是持久化状态了,那么此时对该对象进行各种修改,或者调用多次update、save方法时,hibernate都不会发送sql语句,只有当事物提交的时候,此时hibernate才会拿当前这个对象与之前保存在session中的持久化对象进行比较,如果不相同就发送一条update的sql语句,否则就不会发送update语句。


离线状态的含义是对象在数据库中持久化过,但是没有在sesion缓存中,那么如何从离线状态变成持久化状态呢,这里必须使用update lock saveOrUpdate操作才可以。

1
2
3
4
5
6
//此时u是一个离线对象,没有被session托管
User u = new User();
u.setId(4);
u.setPassword("zzz");
//完成update之后也会变成持久化状态
session.update(u);
1
2
3
4
5
User u = new User();
u.setId(5);
//现在u就是transient对象
ession.delete(u);
//此时u已经是瞬时对象,不会被session和数据库所管理
1
2
3
4
5
6
//u1已经是持久化状态
User u1 = (User)session.load(User.class, 3);
User u2 = new User();
u2.setId(3);
u2.setPassword("123456789");
ession.saveOrUpdate(u2);

此时u2将会变成持久化状态,在session的缓存中就存在了两份同样的对象,在session中不能存在两份拷贝,否则会抛出异常。


现在分析完了,那么在项目中遇到的问题是,之前一个同事需要做一个加密功能,从前端传过来的数据进行加密存储到数据库中,他是这样写的

1
2
3
public void encodeDate(List data){
//循环将list中的数据加密
}

那么这样做,会将session中对象的值改变,并且存在多次查询,会导致下一次查询还是加密之后的数据。造成对象状态混乱,不应该直接改变对象的值,应加密后返回对象较好。