基于Hibernate的Spring Data中,懒加载对象及集合元素是否依附会话?
针对你在Spring Data + Hibernate环境下的几个疑问,我来逐一拆解说明:
1. 懒加载获取的对象是否依附于Hibernate会话?
没错,懒加载得到的对象(包括实体代理、未初始化的集合)完全依附于加载它们的Hibernate Session。
懒加载的核心是延迟查询,只有当你真正访问这些对象的属性时,Hibernate才会通过当前关联的会话去数据库拉取数据。如果会话已经关闭(比如在Spring的事务外),再去访问懒加载属性就会直接抛出LazyInitializationException——因为没有会话来支撑后续的查询操作了。
2. 关于懒加载OneToMany集合的系列问题
2.1 通过ID获取实体后,懒加载集合中的元素是否依附于会话?
当你通过ID从数据库获取实体时,这个实体本身处于持久化状态,和当前会话绑定。它的懒加载OneToMany集合是Hibernate生成的代理集合(比如PersistentBag),这个集合本身也和会话关联。
当你第一次访问集合元素时,Hibernate会借助当前会话执行查询,把集合元素加载进来——这些被加载的元素同样会处于持久化状态,依附于当前会话。
2.2 查询集合内的实体,Hibernate是否返回缓存实例?
会的。Hibernate的**一级缓存(会话缓存)**会存储当前会话中所有被加载的持久化实体。如果你通过ID查询集合内的某个实体(比如调用session.get(YourEntity.class, entityId)),只要这个实体已经被加载到一级缓存里,Hibernate会直接返回缓存中的实例,不会再去数据库执行查询。
另外,如果你的项目开启了二级缓存,并且为该实体配置了缓存策略,Hibernate还会优先从二级缓存中查找,找不到才会走一级缓存或数据库。
2.3 将同ID的瞬时实体附加到该会话,是否会抛出EntityExistsException?
是的,大概率会抛出这个异常。
原因是:当前会话的一级缓存中已经存在同ID的持久化实体(就是你之前加载的那个实体,包括懒加载出来的集合元素)。当你尝试把一个瞬时状态的实体(未被任何会话管理,但数据库中存在对应ID记录)通过session.persist()这类方法附加到会话时,Hibernate发现缓存里已有同ID的持久化对象,就会抛出EntityExistsException。
不过有例外:如果你用session.merge()方法,它会把瞬时实体的属性合并到缓存中的持久化实体上,不会抛出异常;session.saveOrUpdate()如果瞬时实体带有ID,会尝试执行更新操作,也不会触发这个异常(除非有其他数据冲突)。
内容的提问来源于stack exchange,提问作者user2080472

