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

时间:2010-07-13 19:01:26

标签: iphone sqlite xamarin.ios

我有以下电话(实际上比这更多 - 这是这里有问题的整体方法):

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

第一点是 - 可以调用这样调用WCF服务的方法吗?我尝试菊花链接它们,这是一团糟。

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

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);
                }

            };
        }

OnDatabaseUpdateStepCompleted - 只需在调用时迭代一个updateComplete计数器,当它知道所有服务都已经恢复正常时它会移除等待的微调器并继续运行。

这可以在第一次'回合 - 但有时它不会与其中一个:http://monobin.com/__m6c83107d

我认为第一个问题是 - 这一切都好吗?我不习惯使用穿线和锁定,所以我正在为我徘徊。是否正常使用QueueUserWorkItem?在进行批量插入/更新之前,我是否应该使用锁?一个例子:

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 个答案:

答案 0 :(得分:3)

Sqlite不是线程安全的。

如果要从多个线程访问Sqlite,则必须先锁定,然后才能访问任何与SQLite相关的结构。

像这样:

lock (db){
      // Do your query or insert here
}

答案 1 :(得分:0)

对不起,没有具体的答案,但有些想法:

SqlLite甚至线程安全吗?我不确定 - 它可能不是(包装器不是)。你能锁定一个更全局的对象,所以没有两个线程同时插入吗?

MT GC有可能变得过热,并在使用之前释放你的琴弦。也许在插入期间保持对它的本地引用?我已经在视图控制器中发生了这种情况,我将它们放在一个数组中(特别是tabcontrollers),但是如果我没有使用引用保留一个成员变量,那么它们就会得到GC。

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