当前位置: 首页 > 面试题库 >

org.hibernate.LazyInitializationException:如何正确使用Hibernate的延迟加载功能

郎喜
2023-03-14
问题内容

使用Hibernate和lazy = true模式从数据库加载对象列表时遇到了一些麻烦。希望有人可以在这里帮助我。

我这里有一个称为UserAccount的简单类,它看起来像这样:

public class UserAccount {
    long id;
    String username;
    List<MailAccount> mailAccounts = new Vector<MailAccount>();

    public UserAccount(){
        super();
    }

    public long getId(){
        return id;
    }

    public void setId(long id){
        this.id = id;
    }

    public String getUsername(){
        return username;
    }

    public void setUsername(String username){
        this.username = username;
    }

    public List<MailAccount> getMailAccounts() {
        if (mailAccounts == null) {
            mailAccounts = new Vector<MailAccount>();
        }
        return mailAccounts;
    }

    public void setMailAccounts(List<MailAccount> mailAccounts) {
        this.mailAccounts = mailAccounts;
    }
}

我正在通过以下映射文件在Hibernate中映射此类:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <class name="test.account.UserAccount" table="USERACCOUNT">

        <id name="id" type="long" access="field">
            <column name="USER_ACCOUNT_ID" />
            <generator class="native" />
        </id>

        <property name="username" />

        <bag name="mailAccounts" table="MAILACCOUNTS" lazy="true" inverse="true" cascade="all">
            <key column="USER_ACCOUNT_ID"></key>
            <one-to-many class="test.account.MailAccount" />
        </bag>

    </class>
</hibernate-mapping>

如您所见,在bag映射元素中,lazy设置为“ true”。

将数据保存到数据库可以正常工作:

通过调用也可以加载loadUserAccount(String username)(请参见下面的代码):

public class HibernateController implements DatabaseController {
    private Session                 session         = null;
    private final SessionFactory    sessionFactory  = buildSessionFactory();

    public HibernateController() {
        super();
    }

    private SessionFactory buildSessionFactory() {
        try {
            return new Configuration().configure().buildSessionFactory();
        } catch (Throwable ex) {
            System.err.println("Initial SessionFactory creation failed." + ex);
            throw new ExceptionInInitializerError(ex);
        }
    }

    public UserAccount loadUserAccount(String username) throws FailedDatabaseOperationException {
        UserAccount account = null;
        Session session = null;
        Transaction transaction = null;
        try {
            session = getSession();
            transaction = session.beginTransaction();
            Query query = session.createQuery("FROM UserAccount WHERE username = :uname").setParameter("uname", username));
            account = (UserAccount) query.uniqueResult();
            transaction.commit();
        } catch (Exception e) {
            transaction.rollback();
            throw new FailedDatabaseOperationException(e);
        } finally {
            if (session.isOpen()) {
                // session.close();
            }
        }

        return account;
    }

    private Session getSession() {
        if (session == null){
            session = getSessionFactory().getCurrentSession();
        }
        return session;
    }
}

问题只是:当我访问“ mailAccounts”列表中的元素时,出现以下异常:

org.hibernate.LazyInitializationException:无法延迟初始化角色集合:test.account.UserAccount.mailAccounts,没有会话或会话被关闭

我认为发生此异常的原因是会话已关闭(不知道原因和方式),因此Hibernate无法加载列表。如您所见,我什至session.close()从该loadUserAccount()方法中删除了该调用,但该会话似乎仍被关闭或被另一个实例替换。如果设置了lazy=false,那么一切都会顺利进行,但这不是我想要的,因为由于性能问题,我需要“按需”加载数据的功能。

因此,如果我不确定在方法loadUserAccount(String username)终止后我的会话仍然有效,那么具有该功能的意义何在?该如何解决?

谢谢你的帮助!

附:我是一个hibernate初学者,所以请原谅我的肥胖。

更新: 这是我的hibernateconfig.cfg.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="hibernate.connection.password">foo</property>
        <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/mytable</property>
        <property name="hibernate.connection.username">user</property>
        <property name="hibernate.dialect">org.hibernate.dialect.MySQLInnoDBDialect</property>

        <!-- Auto create tables -->
<!--        <property name="hbm2ddl.auto">create</property>-->

        <!-- Enable Hibernate's automatic session context management -->
        <property name="current_session_context_class">thread</property>

        <!-- Mappings -->
        <mapping resource="test/account/SmampiAccount.hbm.xml"/>
        <mapping resource="test/account/MailAccount.hbm.xml"/>
    </session-factory>
</hibernate-configuration>

问题答案:

延迟加载是否工作与事务边界无关。它仅要求打开会话。

但是,何时打开会话取决于您实际上是如何设置SessionFactory的,您没有告诉我们!SessionFactory.getCurrentSession()实际执行的操作背后有配置!如果您允许使用默认版本的ThreadLocalSessionContext,而不执行任何管理生命周期的操作,则实际上确实默认是在提交时关闭会话。(因此,通常的观念是,扩展事务边界是延迟加载异常的“解决方案”。)

如果你管理你自己的会话的生命周期与sessionFactory.openSession()session.close()你将能够在会话的生命周期内延迟加载罚款,外事务边界。或者,您可以提供一个子类,ThreadLocalSessionContext该子类使用所需的边界来管理会话生命周期。还有一些容易获得的替代方法,例如OpenSessionInView过滤器,可以在Web应用程序中使用它来将会话生命周期绑定到Web请求生命周期。

编辑:当然,您也可以只初始化事务内的列表(如果适合您)。我只是认为,当您需要为实体的每个水合作用级别使用某种“标志”参数的新方法签名时,就会导致API变得笨拙。dao.getUser()dao.getUserWithMailAccounts()dao.getUserWIthMailAccountsAndHistoricalIds()等。

编辑2:您可能会发现这对于会话保持打开状态/会话范围与事务范围之间的关系的不同方法很有帮助。(特别是与分离对象的每个请求会话与每个会话的会话的想法。)

  • http://community.jboss.org/wiki/SessionsAndTransactions

对话的实际规模取决于您的要求和体系结构。



 类似资料:
  • 这是我的实体: 在我的存储库中,我有: 如果表中有任何城市,会显示用户的全部信息: 如果没有城市,我想至少得到但我什么都没有:[] 请帮帮我。

  • 问题内容: 我正在使用Spring + Hibernate。我所有的HibernateDAO都直接使用sessionFactory。 我有应用程序层->服务层-> DAO层,所有集合都被缓慢加载。 因此,问题在于,有时在应用程序层(包含GUI / swing)中,我会使用服务层方法(包含@Transactional批注)加载实体,并且我想使用此对象的惰性属性,但忽略了会话已经关闭。 解决此问题的最

  • 我正在使用slick.js构建一个旋转木马。但是,即使我将属性从更改为,在我滚动到该图像之前,图像仍然会被加载。我怀疑这是因为我的图像中有标记。我的问题是如何防止浏览器加载响应图像,或者如何正确地延迟加载响应图像。 这是我的img标签的样本

  • 描述 (Description) 延迟加载可应用于图像,背景图像和淡入效果,如下所述 - 对于图像 要在图像上使用延迟加载,请按照给定的步骤进行操作 - 使用data-src属性而不是src属性来指定图像源。 将类lazy添加到图像。 <div class = "page-content"> ... <img data-src = "image_path.jpg" class = "l

  • 问题内容: 什么是Java的延迟加载?我不明白这个过程。有人可以帮助我了解延迟加载的过程吗? 问题答案: 假设您有一个父母,而那个父母有很多孩子。Hibernate现在可以“延迟加载”子级,这意味着它在加载父级时实际上并不会加载所有子级。而是在要求时加载它们。您可以显式地请求此请求,或者,更常见的是,当您尝试访问孩子时,hibernate会自动加载它们。 延迟加载可以帮助显着提高性能,因为通常您不

  • 问题内容: 我以这样一种方式进行了JPA设置:如果我不使用延迟加载,则几乎将加载整个数据库。我也直接在模型上使用序列化,因此有时我需要初始化代理。 我只想在集合上使用延迟加载。急切地获取一些奇异实体的事实就很好了。但是,无论我如何尝试设置集合,我都永远不会得到代理集合,而我总是会得到完全加载的集合。 这是一些示例代码: 所以这里的问题是,当我检查调试器时,答复的persistantBag-list