Hibernate 的缓存有三种,
Session级别的缓存,也可以说是事务级别。对当前事务中的对象进行缓存,不同的事务有不同的缓存。
查询缓存,查询缓存是所有事务共享的,是为了减少查询的数据库操作,以查询语句和参数值为key。
Second level cache, 二级缓存,为了在事务直接共享对象。比如事务1已经从数据库获得对象A,事务2用这个ID再去查找直接从二级缓存返回。
Session Cache 是默认打开的,而且是不能关闭的,其他两种则需要配置。本文以下只讨论Session Cache.
一般而言,Cache的第一个作用就是减少数据库操作,把磁盘的物理操作转化为内存的电位操作。然而我认为Hibernate的Session Cache似乎有更重要的作用。除了减少频繁的IO操作之外,他的一个很大的作用是保证同一个Session中同一个对象的引用的唯一性。另外Session Cache还是事务提交前的一个缓冲区。
并不是所有的操作都会把对象进入Session Cache,参考:
http://apmblog.dynatrace.com/2009/02/16/understanding-caching-in-hibernate-part-one-the-session-cache/
Hibernate 中一个常见的错误:
a different object with the same identifier value was already associated with the session
字面意思就很明显,一个session中不能有两个ID相同的对象。很容易理解,这也是因为Session Cache的存在,为了保证一个事务中的一致性,保证最终保存到数据库时不发生冲突。网上的各种解决办法有session.clear(); session.merge();等。其实我觉得最重要的时从代码结构保证不要出现这种情况,不要出现同一个session中两个相同ID的对象。比如把一个对象用参数的形式传入一个方法,这个方法被注明是一个单独的事务。那么就是把这个对象传进了这个session,当在这个session中把这个对象set到其他对象中,然后save 或者update就会出发这个错误。如果对象不是从其他地方传进来的就不会。这里用merge可能好一些,没有验证。