【问题标题】:Fetch data from table using hibernate with fetch=FetchType.LAZY使用带有 fetch=FetchType.LAZY 的 hibernate 从表中获取数据
【发布时间】:2013-04-13 03:45:35
【问题描述】:

我正在尝试从表中获取所有用户的电子邮件。 实体用户:

     @Entity
     @Table(name = "tbl_User")
     public class User {
          @Expose
          @Id
          @GeneratedValue
          @Column(name = "id")
          private Long id;
          .....
          @OneToMany(mappedBy = "user", fetch = FetchType.LAZY)
          List<CommunicationAddress> communicationAddresses = new ArrayList<CommunicationAddress>();
          .....
     } 

在服务中,我正在获取用户并尝试查看电子邮件:

User user = userDAO.getUserById(id);
        if (user == null) {
            throw new Exception("User not found");
        } else {
            List<Email> addresses = user.getCommunicationAddresses();
        }

但我收到了下一个异常:

 org.hibernate.LazyInitializationException: could not initialize proxy - no Session
        at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:186)
        at org.hibernate.collection.internal.AbstractPersistentCollection.readSize(AbstractPersistentCollection.java:137)
        at org.hibernate.collection.internal.PersistentBag.isEmpty(PersistentBag.java:249)

获取用户的方法:

@Transactional
@Override
public User getUserById(Long userId) {
    Criteria criteria = sessionFactory.getCurrentSession().createCriteria(User.class);
    criteria.add(Restrictions.eq("id", userId));
    return (User) criteria.uniqueResult();
}

我明白,当我使用 Criteria 获取用户时,我必须获取communicationAddresses... 怎么做?谢谢大家。

【问题讨论】:

  • 服务方法是事务性的吗?会话工厂是由 Spring 在 DAO 中创建和注入的吗?
  • @JBNizet 是的。工厂注入。
  • 用户用户 = userDAO.getUserById(id);在此之后尝试 user = user.getId()。它将为您加载代理对象,然后您可以加载地址
  • @Chandu 是的。我得到了用户的属性,但是当我尝试使用调试和 IDEA 来查看通信地址时,我看到下一条消息“方法抛出了 'org.hibernate.LazyInitializationException' 异常。”
  • @Chandu 这不是真的。 load() 不会获取惰性属性;更糟糕的是:它只会返回一个代理(想想一个完全延迟加载的实体),它在事务之外没有用(除了提供 ID)。

标签: java spring hibernate hibernate-mapping


【解决方案1】:

您的服务方法似乎没有使用@Transactional 进行注释。因此,在调用userDAO.getUserById(id); 之后,不再有事务。这意味着您无法访问尚未在事务中访问/预取的已加载实体的任何延迟加载属性,而不会遇到 LazyInitializationException。
因此,您可以考虑将 LAZY 替换为 EAGER 获取(这主要取决于您面临的用例),或者您应该使用 @Transactional 注释您的 Service 方法。

我强烈建议您注释您的服务方法(而不是 DAO 方法),因为只有在与多个实体交互时,您才能建立有意义的事务边界。
此外,如果您使用延迟加载,您必须意识到离开服务层后遇到这种异常的可能性,例如渲染视图时(假设您以某种方式呈现数据)。

“预取”惰性关联

要触发延迟关联(称为“dynamic association fetching”)的即时加载,请在getUserById 中添加此行:

criteria.setFetchMode("communicationAddresses", FetchMoode.EAGER);

但是,如果你用这个特定的方法这样做,我想知道你为什么要坚持延迟加载?

【讨论】:

  • 谢谢!我用@Transactional 注释了我的服务并且它有效。但我对使用 Criteria 从 DAO 获取用户地址的可能性感兴趣。是否可以加载添加任何限制或表达式的完整用户?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-27
  • 2018-07-22
  • 2017-03-06
  • 2015-03-07
  • 1970-01-01
  • 2016-06-08
相关资源
最近更新 更多