如何修复Java中的LazyInitializationException?

问题描述 投票:0回答:2

我在一个小项目上工作,我有2个表,用户和应用程序。用户可以拥有多个应用程序,并且多个用户可能会使用某个应用程序,因此它们之间存在多对多的关系。每个表都有一些字段(id,名称,密码,技术等),我还在User和Application类中使用@ManyToMany注释声明了2个arraylists。问题是,在我的业务层中,我编写了一个方法,该方法应该向用户添加应用程序,当我尝试执行user.getListOfApplications()时,添加(app)它会给我异常...

public class ManagerHibernate {private 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
2个回答
2
投票

使用以下方法managerHibernate.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类中将延迟加载更改为急切加载(因为您使用多对多关系不建议使用这种方式)


1
投票

由于没有用于在用户中获取惰性listofApplication的事务,因此您需要先获取它。为此,您可以更改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);

        });
© www.soinside.com 2019 - 2024. All rights reserved.