【问题标题】:SQLite problem "unable to open the database file"SQLite 问题“无法打开数据库文件”
【发布时间】:2011-09-07 18:01:41
【问题描述】:

在谷歌搜索和阅读 StackOverflow 上有关 SQLite 的其他讨论后,我来找你,但我绝对找不到任何解释我的问题,所以这里是:

  • 背景:
    我正在为 iPad 开发一个应用程序,它必须多次处理一些“大量”数据。在其中一个中,我必须将点坐标从 .kml 文件(Google 用于地理数据的 xml)导入到我的数据库中,以便稍后使用 MKMapView 重用它们,并在需要显示特定时比通过解析 xml 更快地加载它们层。

  • 详情:
    导入很简单:处理这些文件时,我只关心 2 个表:

    • 一个包含区域定义和详细信息:目前,integer 作为 id,text 用于命名。
    • 一个包含两个real 用于坐标存储,一个integer 引用第一个表以了解哪个区域点是其中的一部分。
      因此,只要读取我的文件,我首先为新区域创建一个条目,然后将点插入到第二个表中,并在第一个表中创建最后一个区域的 ID……没什么复杂的!

    但是……

  • 问题:
    运行良好一段时间后,我从 SQLite 收到一个异常,并显示著名的消息“无法打开数据库文件”,然后我就无法对数据库做更多的事情了。此异常可能在区域创建或点插入方法中随机发生。

  • 我的反应:
    考虑到这些文件中的许多点,我怀疑内存或磁盘饱和,但我的应用程序的其他部分丢弃了这些点(在我看来)。
    首先,内存:当异常发生时,应用程序正在使用大约 10 或 12 MB 的 RAM。它可能看起来相当大,但这是由于内存中加载了约 10MB 的 .kml 文件,所以它是可以解释的。最重要的是,我的应用程序中的 MKMapView 可以处理地图上方的大量高分辨率切片图层,因此会导致内存峰值达到 20 甚至 25MB 而不会导致 iPad 崩溃。
    二、磁盘:重置我的数据库并只填充上述2个表时,发生异常时的db文件大小始终约为2.2或2.5MB,但是当我填充其他表时(我的应用程序的其他部分运行良好!) db 文件大约 6 或 7MB,设备完全没有抱怨。

  • 那又怎样?!
    CPU 愤怒和恐慌?我不这么认为,因为我的数据库的其他一些表以相同的节奏填充而没有问题......并且在模拟器中运行我的应用程序也会崩溃,核心 i7 只是在嘲笑这项工作。
    SQLite不好用?我们去吧!在我看来,这是唯一的解决方案!但我真的不明白这里发生了什么,因为我处理我的请求的方式与我在其他应用程序部分的处理方式相同——重复我自己——就像一个魅力!

  • SQLite 详细信息:
    我有一个 DB 类,这是一个单例,我使用它来避免在每次请求时创建/释放 SqliteConnection 对象,并且我处理数据库的所有方法都包含在这个类中,以确保我不玩在不知情的情况下连接其他任何地方。以下是该类的相关方法:

    public void     saveZone(ObjZone zone)  { //at this point, just creates an entry with a name and let sqlite give it a new id
        lock (connection) { //SqliteConnection object
            try {
                openConnection();
                SqliteCommand cmd = connection.CreateCommand();
                cmd.CommandText = zone.id == 0 ?
                    "insert into ZONES (Z_NAME) values (" + format(zone.name) + ") ;" :
                    "update ZONES set Z_NAME = " + format(zone.name) + " where Z_ID = " + format(zone.id) + " ;";
                cmd.ExecuteNonQuery();
                if (zone.id == 0) {
                    cmd.CommandText = "select Z_ID from ZONES where ROWID = last_insert_rowid() ;";
                    zone.id = uint.Parse(cmd.ExecuteScalar().ToString());
                }
                cmd.Dispose();
            }
            catch (Exception e) {
                Log.failure("DB.saveZone(" + zone.ToString() + ") : [" + e.GetType().ToString() + "] - " +
                    e.Message + "\n" + e.StackTrace); //custom Console.WriteLine() method with some formating
                throw e;
            }
            finally {
                connection.Close();
            }
        }
    }
    
    public void     setPointsForZone(List<CLLocationCoordinate2D> points, uint zone_id) { //registers points for a given zone
        lock (connection) {
            try {
                openConnection();
                SqliteCommand cmd = connection.CreateCommand();
                cmd.CommandText = "delete from ZONESPOINTS where Z_ID = " + format(zone_id);
                cmd.ExecuteNonQuery();
                foreach(CLLocationCoordinate2D point in points) {
                    cmd.CommandText = "insert into ZONESPOINTS values " +
                        "(" + format(zi_id) + ", " + format(point.Latitude.ToString().Replace(",", ".")) + ", "
                        + format(point.Longitude.ToString().Replace(",", ".")) + ");";
                    cmd.ExecuteNonQuery();
                    cmd.Dispose();
                }
            }
            catch (Exception e) {
                Log.failure("DB.setPointsForZone(" + zone_id + ") : [" + e.GetType().ToString() + "] - " + e.Message);  
                throw e;
            }
            finally {
                connection.Close();
            }
        }
    }
    

    为了尽可能清楚,这里是上面两个中引用的一些方法(我使用这个自定义的openConnection() 方法,因为我在我的大多数表中都使用了外键约束并且级联行为未被启用默认,但我需要它们。):

    void openConnection() {
        try {
            connection.Open();
            SqliteCommand cmd = connection.CreateCommand();
            cmd.CommandText = "PRAGMA foreign_keys = ON";
            cmd.ExecuteNonQuery();
            cmd.Dispose();
        }
        catch (Exception e) {
            Log.failure("DB.openConnection() : [" + e.GetType().ToString() + "] - " + e.Message);
            throw e;
        }
    }
    
    public static string format(object o) {
        return "'" + o.ToString().Replace("'", "''") + "'";
    }
    

好吧,对不起,我可能已经感谢你阅读了所有这些东西,不是吗?!无论如何,如果我错过了一些可能有用的东西,请告诉我,我会尽快记录下来。 无论如何,我希望有人能够帮助我,在此先感谢您!
(我为我可怜的法国人的英语道歉。)

编辑
我的问题“解决了”!在对调试程序进行了一些更改后,没有大的修改,也没有成功,我将代码恢复到我发布的状态......现在它可以工作了。但如果有人能给我解释可能发生的事情,我真的很感激!似乎 SQLite 行为(至少在 iPad 上 - 从未在其他任何地方使用过)有时可能非常模糊......:/

【问题讨论】:

  • 顺便说一句,如果有人能告诉我为什么 StackOverflow 不允许我以“你好”开始我的帖子?!我一直认为礼貌是获得问题答案的最佳方式!

标签: c# ipad sqlite xamarin.ios


【解决方案1】:

我不会为此祈祷,但我会尝试两件事:

  1. 如果可能,将 KML 文件预处理到第二个 SQLite 数据库并使用该数据库将数据导入主数据库(考虑到较低的内存/处理器要求)
  2. 小批量处理导入的数据。

HTH

编辑:您可能已经检查过了,但无论如何:unable to open database

【讨论】:

  • 已经检查过了,谢谢!您的第一个想法还不错,但是当我要在编辑中编写时,我“解决了”我的问题。
  • 是的,这种“神圣干预”也时不时发生在我身上,但当我想到生产环境时,它是最可怕的事情。
  • 我同意这一点,这就是我害怕的……但是我的时间不多了,所以让我们祈祷吧! ://
猜你喜欢
  • 2014-11-11
  • 2014-08-30
  • 2021-10-15
  • 2015-08-03
  • 1970-01-01
  • 2014-06-13
  • 1970-01-01
  • 2011-05-24
  • 1970-01-01
相关资源
最近更新 更多