【问题标题】:Hibernate error "database is locked". How do i correctly close session?休眠错误“数据库已锁定”。我如何正确关闭会话?
【发布时间】:2011-11-10 01:07:27
【问题描述】:

在我的应用程序中,我打开会话,创建条件但不关闭它。然后在其他方法中我再次打开会话,更新对象并在tr.commit() 上接收database is locked

如果我将session.close() 放在第一个实例中,我会收到

无法初始化代理 - 没有会话。

如何正确关闭和打开会话?还是我需要将代理对象复制到我创建的那些,然后close()

Session session = HibernateUtil.getSessionFactory().openSession();
        Transaction tr=session.beginTransaction();

        Criteria criteria = session.createCriteria(MyDocument.class);
        criteria.add(Expression.like("isMainDoc", 1));

        List docs = criteria.list();

        tr.commit();
        session.close();

我是一个完全的初学者。我使用sqlite。任何帮助,将不胜感激。提前致谢。

【问题讨论】:

    标签: java hibernate sqlite session


    【解决方案1】:

    Hibernate Session 通常绑定到一个线程。

    因此,也许您应该重构代码以在处理开始时获取会话(例如,在 Web 应用的 ServletFilter 实例中)。

    然后在每个方法中,你可以使用同一个会话对象,开始一个新的事务(当然,也可以结束事务。

    public void doWork(){
      Transaction tx = null;
       try{
         tx = session.beginTransaction();  
       }catch(){
       } finally {
         // if tx != null then.. close transaction, or rollback?
       }
    }
    

    编辑:然后当然,在处理完成后关闭会话(在 web-app 中,也可能在同一个 ServletFilter 中) Google:“在视图中打开会话”模式。

    【讨论】:

    • 感谢您的回答。与我裸露。我正在制作桌面应用程序。您能否进一步解释如何获得会话。我是否在主窗体初始化时进行会话?如何以其他形式使用它?
    • 我认为在桌面应用程序中,每个事件都会启动一个新线程,例如按钮单击。因此,也许应该在单击按钮时打开新会话。 1. sessionFactory 应该在应用程序加载时创建。 2. 在启动新线程时,应创建会话(使用您正在使用的相同 API)。所以也许你需要在 EventHandlers 中创建一个会话。
    • 感谢您的解释。如何检索会话工厂和会话。我让它们成为静态的吗?我是这方面的初学者。
    • HibernateUtil.getSessionFactory() 工作正常。我需要调用一次吗?
    • 是的,应用程序启动时只调用一次 HibernateUtil.getSessionFactory()。您可能是一个负责启动应用程序的类。在 Java 中,这将是具有方法的类:public static void main(String[] args)。所以,在那个类中,这应该只被调用一次:调用 HibernateUtil.getSessionFactory()
    【解决方案2】:

    原因

    当您尝试访问查询返回的MyDocument 类实例的属性时,您可能会遇到错误。

    Hibernate 默认是 lazy。它为您返回一个对象的proxy,而不是在访问引用属性时访问数据库。此行为可以在需要时被覆盖。 永远记住无法初始化代理 - 当代码尝试访问 proxy 属性(通过访问数据库)并发现会话不可用时没有收到会话(当 Hibernate 使用此接口访问数据库时需要会话)

    解决方案

    确保当 Hibernate 尝试加载尚未加载的对象时,您的会话处于打开状态。你是怎样做的?

    (简单来说)Hibernate有两种思路:

    1. 在关闭会话之前获取您可能访问的所有数据或
    2. 在您处理对象的整个过程中保持会话打开。

    我希望您复习一下诸如 Hibernate 中的工作单元之类的主题。 Hibernate 提供了一个很好的接口来定义数据库访问的边界。必须在这些边界之间访问(读/写)数据。 Check Here

    hibernate.current_session_context_class 在休眠配置中可以取值 jta |线程 |托管 |自定义类。这个变量定义了Session 的工作单元。

    最后但最重要的是尝试使用Contextual Sessions(你一定遇到过.getCurrentSession() 这可以帮助您获得在您的代码中随时随地打开的相同会话。 Hibernate 在幕后处理一切。

    希望这个答案可以指导您正确地使用 Hibernate,而不仅仅是解决这个特定问题。

    【讨论】:

      【解决方案3】:

      当您使用hibernate transactions 时,请按照以下步骤阅读API here

      Session session = sessionFactory.openSession();
      Transaction tx = session.beginTransaction();
      
      //Or any other operation.
      session.save(a);
      
      tx.commit();
      session.close();
      

      【讨论】:

      • 感谢您的回答。如果只是从会话中创建标准怎么办。我没有。我要保存什么?
      • 无法初始化代理 - 没有会话也可能是因为其他一些原因。因此,请验证您收到错误的位置。您的新代码似乎没问题。
      • 我在使用从标准中获得的数据填充表时使用列表文档,无法初始化代理 - 表的构造函数中没有会话。
      猜你喜欢
      • 2011-01-23
      • 1970-01-01
      • 2018-07-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-27
      • 2012-03-10
      • 1970-01-01
      相关资源
      最近更新 更多