代码之家  ›  专栏  ›  技术社区  ›  Mark Bell

尝试在ASP.NET MVC应用程序中打开db4o数据库时,是什么导致了此databasefilelockedException?

  •  2
  • Mark Bell  · 技术社区  · 14 年前

    我正在用ASP.NET MVC 2构建一个小型Web应用程序,使用DB4O作为数据存储。

    我添加了一个HTTPmodule_ the example here _“,让应用程序访问db4o数据库,在VS2008 ASP.NET Development Server下的开发机器上,一切都正常工作。

    但是,当我将应用程序部署到我的Web主机并尝试访问它时,我会得到一个 DatabaseFileLockedException 在httpmodule尝试打开数据库文件的行。但是访问该文件应该没有其他内容;实际上,在应用程序首次运行时,只有在引发此异常时才会创建该文件。

    Web主机的服务器正在Windows Server 2008上运行IIS 7,应用程序正在完全信任下运行。它是一个子应用程序,以防产生任何差异。

    我不明白为什么这个错误发生在Live服务器上,而不是在我的开发服务器上。有人能帮我吗,或者建议我下一步该怎么做?

    3 回复  |  直到 14 年前
        1
  •  3
  •   Mark Bell    14 年前

    这是示例代码中的一个错误。它假定httpmodule.init只调用一次,这不一定是真的。根据应用程序的配置方式,可以多次调用它。要解决此问题,请签入httpmodule处理程序(如果实例已经存在):

    using System;
    using System.Configuration;
    using System.Web;
    using Db4objects.Db4o;
    
    namespace Db4oDoc.WebApp.Infrastructure
    {
        public class Db4oProvider : IHttpModule
        {
            private const string DataBaseInstance = "db4o-database-instance";
            private const string SessionKey = "db4o-session";
    
            // #example: open database when the application starts
            public void Init(HttpApplication context)
            {
                if (null==HttpContext.Current.Application[DataBaseInstance])
                {
                    HttpContext.Current.Application[DataBaseInstance] = OpenDatabase();
                }
                RegisterSessionCreation(context);
            }
    
            private IEmbeddedObjectContainer OpenDatabase()
            {
                string relativePath = ConfigurationSettings.AppSettings["DatabaseFileName"];
                string filePath = HttpContext.Current.Server.MapPath(relativePath);
                return Db4oEmbedded.OpenFile(filePath);
            }
            // #end example
    
            // #example: close the database when the application shuts down
            public void Dispose()
            {
                IDisposable toDispose = HttpContext.Current.Application[DataBaseInstance] as IDisposable;
                if (null != toDispose)
                {
                    toDispose.Dispose();
                }
            }
            // #end example
    
            // #example: provide access to the database
            public static IObjectContainer Database
            {
                get { return (IObjectContainer)HttpContext.Current.Items[SessionKey]; }
            }
            // #end example
    
            // #example: A object container per request
            private void RegisterSessionCreation(HttpApplication httpApplication)
            {
                httpApplication.BeginRequest += OpenSession;
                httpApplication.EndRequest += CloseSession;
            }
    
            private void OpenSession(object sender, EventArgs e)
            {
                IEmbeddedObjectContainer container =
                    (IEmbeddedObjectContainer)HttpContext.Current.Application[DataBaseInstance];
                IObjectContainer session = container.OpenSession();
                HttpContext.Current.Items[SessionKey] = session;
            }
    
            private void CloseSession(object sender, EventArgs e)
            {
                if (HttpContext.Current.Items[SessionKey] != null)
                {
                    IObjectContainer session = (IObjectContainer)HttpContext.Current.Items[SessionKey];
                    session.Dispose();
                }
            }
            // #end example
        }
    }
    

    作为替代方案,您可以使用从global.apsx启动的应用程序,该应用程序肯定只调用一次。

        2
  •  2
  •   Simon Randy Burden    14 年前

    你还有一个问题。

    当AppPool重新启动时,旧AppPool正在完成请求,而新AppPool正在为新请求提供服务时,可能会有重叠。

    在此期间,您将有两个进程尝试访问同一db4o文件。

    为了解决这个问题,你可以使用下面的黑客。

    注意使用 Db4oFactory.OpenServer 而不是 Db4oEmbedded.OpenFile . 这允许在更细粒度的基础上使用事务。

    public IObjectServer OpenServer()
    {
        Logger.Debug("Waiting to open db4o server.");
        var attempts = 0;
        do
        {
            try
            {
                return Db4oFactory.OpenServer(fileName, 0);
            }
            catch (DatabaseFileLockedException ex)
            {
                attempts++;
                if (attempts > 10)
                {
                    throw new Exception("Couldn't open db4o server. Giving up!", ex);
                }
    
                Logger.Warn("Couldn't open db4o server. Trying again in 5sec.");
                Thread.Sleep(5.Seconds());
            }
        } while (true);
    }
    

    希望这有帮助

        3
  •  0
  •   John Farrell    14 年前

    如果它在dev上工作的话,听起来像是权限问题。将一个记事本文件放在同一个目录中,并尝试用一些简单的文件代码打开它。我打赌你也会有同样的问题。