【问题标题】:How to fix LazyInitializationException in Java?如何修复 Java 中的 LazyInitializationException?
【发布时间】:2019-03-27 01:44:26
【问题描述】:

我从事一个小项目,我有 2 个表,用户和应用程序。一个用户可以有多个应用程序,一个应用程序可能被多个用户使用,所以它们之间是多对多的关系。每个表都有一些字段(id、名称、密码、技术等),我还在 User 和 Application 类中声明了 2 个数组列表,并带有 @ManyToMany 注释。问题是,在我的业务层中,我编写了一个应该向用户添加应用程序的方法,当我尝试执行 user.getListOfApplications().add(app) 时,它给了我这个异常......

公共类ManagerHibernate { 私有 SessionFactory sessionFactory;

public void setup()
{
     sessionFactory = new Configuration().configure().buildSessionFactory();
}

public void exit()
{
    sessionFactory.close();
}

public void create(Object obj)
{
    Session session = sessionFactory.openSession();
    session.beginTransaction();

    session.save(obj);

    session.getTransaction().commit();
    session.close();
}

public Object read(Class<?> c, int idObj)
{
    Session session = sessionFactory.openSession();
    session.beginTransaction();

    Object obj = session.get(c, idObj);

    System.out.println(obj);

    session.getTransaction().commit();
    session.close();
    return obj;
}

public void update(Object obj)
{
    Session session = sessionFactory.openSession();
    session.beginTransaction();

    session.update(obj);

    session.getTransaction().commit();
    session.close();
}

public void delete(Object obj)
{
    Session session = sessionFactory.openSession();
    session.beginTransaction();

    session.delete(obj);

    session.getTransaction().commit();
    session.close();
}

public <T> List<T> loadAllData(Class<T> type)
{
    Session session = sessionFactory.openSession();
    session.beginTransaction();

    CriteriaBuilder builder = session.getCriteriaBuilder();
    CriteriaQuery<T> criteria = builder.createQuery(type);
    criteria.from(type);
    List<T> data = session.createQuery(criteria).getResultList();

    session.getTransaction().commit();
    session.close();
    return data;
}

}

public Boolean addNewApplicationToUser(String userUserName, String applicationName)
{
    int okUser = 0;
    int okApp = 0;

     listOfApplications = managerHibernate.loadAllData(Application.class);
     listOfUsers = managerHibernate.loadAllData(User.class);
     User user = null;
     Application app = null;

    for(Application index: listOfApplications)
    {
        if(index.getApplicationName().equals(applicationName))
            {
                okApp = 1;
                app = index;
            }
    }

    for(User index: listOfUsers)
    {
        if(index.getUserUserName().equals(userUserName))
            {
                okUser = 1;
                user = index;
            }
    }

    if(okUser == 0  || okApp == 0)
        return false;
    else
    {   
        user.getListOfApplications().add(app);
        //app.getUserList().add(user);
        return true;
    }
}

方法 addNewApplicationToUser 写在另一个名为 ControllerHibernate 的类中。只有else分支很重要,剩下的就是检查参数是否确实存在于数据库中

【问题讨论】:

    标签: java hibernate lazy-initialization


    【解决方案1】:

    当您使用以下方法加载数据时问题开始 ma​​nagerHibernate.loadAllData

    public <T> List<T> loadAllData(Class<T> type)
    {
            // New session was opened here
            Session session = sessionFactory.openSession();
            session.beginTransaction();
    
            CriteriaBuilder builder = session.getCriteriaBuilder();
            CriteriaQuery<T> criteria = builder.createQuery(type);
            criteria.from(type);
            List<T> data = session.createQuery(criteria).getResultList();
    
            session.getTransaction().commit();
            session.close();
            //session is close here
            return data;
        }
    

    因此,当您加载数据时,hibernate 框架只会加载用户对象。由于您选择在模型类中使用延迟加载,因此只有在您尝试访问列表时才会加载应用程序值。由于您已经关闭了会话,因此框架无法再获取应用程序列表,从而导致延迟加载异常。

    listOfApplications = managerHibernate.loadAllData(Application.class);
    //loading user data and close the session associated with it
    listOfUsers = managerHibernate.loadAllData(User.class);
    User user = null;
    Application app = null;
    
    for(Application index: listOfApplications)
    {
      if(index.getApplicationName().equals(applicationName))
          {
              okApp = 1;
              app = index;
          }
    }
    
    for(User index: listOfUsers)
    {
      if(index.getUserUserName().equals(userUserName))
          {
              okUser = 1;
              user = index;
          }
    }
    
    if(okUser == 0  || okApp == 0)
      return false;
    else
    {   
      // when you run this line the hibernate framework will try to retrieve the application data.Since you have the closed session lazy load exception occurs 
      user.getListOfApplications().add(app);
      return true;
    }
    

    解决这个问题的方法

    1) 尝试保持会话打开,以便您的框架可以获取应用程序数据

    2) 在您的模型 pojo 类中将延迟加载更改为急切加载(由于您使用的是多对多关系,因此不建议使用这种方式)

    【讨论】:

    • 我设法通过在 setup() 和 exit() 方法中移动 session.openSession() 和 session.close() 并将 Session 对象声明为实例变量来修复异常。显然,向用户添加新应用程序的方法有效,我通过调用然后 printAllAppsForaUser() 方法检查了这一点,但仍然存在问题。我的数据库不会在由 @ManyToMany 注释创建的 application_user 表中添加条目 (user_id, app_id)。有什么想法吗?
    • @ManyToMany(mappedBy="userlist") private List applist = new ArrayList(); @ManyToMany private List userlist = new ArrayList();这就是我在 User 和 Application 类中声明 2 个列表的人
    【解决方案2】:

    由于没有用于获取用户中的惰性应用程序列表的事务,因此您需要先获取它。为此,您可以按如下方式更改 loadAllData:

    public interface CriteriaSpec 
    {
    public void joinFetch(CriteriaBuilder builder, CriteriaQuery criteria, Root root);
    }
    
    public <T> List<T> loadAllData(Class<T> type, Optional<CriteriaSpec> spec)
    {
    Session session = sessionFactory.openSession();
    session.beginTransaction();
    
    CriteriaBuilder builder = session.getCriteriaBuilder();
    CriteriaQuery<T> criteria = builder.createQuery(type);
    Root root = criteria.from(type);
    if(spec.isPresent())
        spec.joinFetch(builder, criteria, root);
    List<T> data = session.createQuery(criteria).getResultList();
    
    session.getTransaction().commit();
    session.close();
    return data;
    }
    

    然后使用它:

    managerHibernate.loadAllData(Application.class, Optional.empty());
    listOfUsers = managerHibernate.loadAllData(User.class, (rootEntity, query, 
    criteriaBuilder) -> {
                rootEntity.fetch("listOfApplications", JoinType.Left_OUTER_JOIN);
    
            });
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-06-27
      • 1970-01-01
      • 1970-01-01
      • 2023-03-12
      • 1970-01-01
      • 1970-01-01
      • 2018-03-14
      • 2013-03-01
      相关资源
      最近更新 更多