代码之家  ›  专栏  ›  技术社区  ›  user156888

Monotouch数据同步-为什么我的代码有时会导致sqlite错误?

  •  3
  • user156888  · 技术社区  · 16 年前

    我有以下几个调用(实际上比这个多一些—这里讨论的是整个方法):

    ThreadPool.QueueUserWorkItem(Database.Instance.RefreshEventData);
    ThreadPool.QueueUserWorkItem(Database.Instance.RefreshLocationData);
    ThreadPool.QueueUserWorkItem(Database.Instance.RefreshActData);
    

    上面调用的一个刷新方法的示例是(它们都遵循相同的模式,只需调用不同的服务并填充不同的表):

    public void RefreshEventData (object state)
            {
                Console.WriteLine ("in RefreshEventData");
                var eservices = new AppServicesClient (new BasicHttpBinding (), new EndpointAddress (this.ServciceUrl));
    
                //default the delta to an old date so that if this is first run we get everything
                var eventsLastUpdated = DateTime.Now.AddDays (-100);
    
                try {
                    eventsLastUpdated = (from s in GuideStar.Data.Database.Main.Table<GuideStar.Data.Event> ()
                        orderby s.DateUpdated descending
                        select s).ToList ().FirstOrDefault ().DateUpdated;
    
                } catch (Exception ex1) {
                    Console.WriteLine (ex1.Message);
                }
    
                try {
                    eservices.GetAuthorisedEventsWithExtendedDataAsync (this.User.Id, this.User.Password, eventsLastUpdated);
                } catch (Exception ex) {
                    Console.WriteLine ("error updating events: " + ex.Message);
                }
    
                eservices.GetAuthorisedEventsWithExtendedDataCompleted += delegate(object sender, GetAuthorisedEventsWithExtendedDataCompletedEventArgs e) {
    
                    try {
    
                        List<Event> newEvents = e.Result.ToList ();
    
                        GuideStar.Data.Database.Main.EventsAdded = e.Result.Count ();
    
                        lock (GuideStar.Data.Database.Main) {
                            GuideStar.Data.Database.Main.Execute ("BEGIN");
    
                            foreach (var s in newEvents) {
    
                                GuideStar.Data.Database.Main.InsertOrUpdateEvent (new GuideStar.Data.Event { 
                                    Name = s.Name, 
                                    DateAdded = s.DateAdded, 
                                    DateUpdated = s.DateUpdated, 
                                    Deleted = s.Deleted, 
                                    StartDate = s.StartDate,
                                    Id = s.Id, 
                                    Lat = s.Lat, 
                                    Long = s.Long   
                                });
    
                            }
    
                            GuideStar.Data.Database.Main.Execute ("COMMIT");
                            LocationsCount = 0;
                        }
                    } catch (Exception ex) {
                        Console.WriteLine("error InsertOrUpdateEvent " + ex.Message);
                    } finally {
                        OnDatabaseUpdateStepCompleted (EventArgs.Empty);
                    }
    
                };
            }
    

    第一次就可以了,但有时不适用于: http://monobin.com/__m6c83107d

    我想第一个问题是-这一切都好吗?我不习惯使用线程和锁,所以我徘徊在新的领域为我。像这样使用QueueUserWorkItem可以吗?在执行批量插入/更新之前,我是否应该使用lock?例如:

    public void InsertOrUpdateEvent(Event festival){
    
                try {
                    if (!festival.Deleted) {
                        Main.Insert(festival, "OR REPLACE");
                    }else{
                        Main.Delete<Event>(festival);
                    }
                } catch (Exception ex) {
                    Console.WriteLine("InsertOrUpdateEvent failed: " + ex.Message);
                }
    
            }
    

    接下来的问题是-我做错了什么导致了这些sqlite问题?

    2 回复  |  直到 16 年前
        1
  •  0
  •   Nic Wise    16 年前

    抱歉,没有具体的答案,但有一些想法:

    SqlLite是线程安全的吗?我不确定-可能是因为它不是(包装器不是)。你能锁定一个更全局的对象,这样就不会有两个线程同时插入了吗?

    您能以线程方式获取数据,然后将所有内容排队并将它们插入单个线程吗?至少作为一个测试。

        2
  •  3
  •   miguel.de.icaza    16 年前

    Sqlite不是线程安全的。

    如果您想从多个线程访问Sqlite,那么在访问任何Sqlite相关结构之前,必须先锁定。

    lock (db){
          // Do your query or insert here
    }
    
    推荐文章