C# Xamarin中SQLite.Net序列化模式无法正常工作?
嘿,我之前在SQLite.Net-PCL上也踩过一模一样的坑!你对SQLite序列化模式的理解其实有点偏差,咱们来掰扯清楚:
核心误解:序列化模式≠连接实例线程安全
SQLite文档说序列化模式下可安全用于多线程,这个没错,但它指的是数据库级别的线程安全——也就是说,当多个线程通过不同的连接实例操作同一个数据库时,SQLite内核会自动处理并发冲突,不会出问题。
但SQLite.Net-PCL的
SQLiteConnection对象本身并不是线程安全的!哪怕数据库开了序列化模式,你在多个线程间共享同一个连接实例,并发调用Insert这类方法时,还是会因为连接内部的状态(比如语句句柄、事务上下文)被并发修改而触发SQLiteException: Misuse错误。
两种正确的解决方案
方案1:每个操作/线程使用独立连接
SQLite的连接实例本身非常轻量,创建和销毁的开销几乎可以忽略。所以最稳妥的方式是,每次数据库操作都创建新连接,用完就释放:
// 并发插入的示例 Parallel.For(0, 100, i => { // 每个线程创建独立连接 using (var conn = new SQLiteConnection(new SQLitePlatformAndroid(), "your_db_path.db")) { conn.Insert(new YourModel { Id = i, Content = $"Test {i}" }); } });
Android和iOS平台都适用这个方案,完全避免了共享连接的线程安全问题。
方案2:使用线程安全的SQLiteConnectionWithLock
如果确实需要复用连接(比如出于性能优化的考量),SQLite.Net-PCL提供了SQLiteConnectionWithLock类——它内部已经封装了线程锁,确保同一时间只有一个线程能操作连接。你可以全局共享这个实例,在多线程里直接调用方法:
// 初始化时创建一次,全局复用 var threadSafeConn = new SQLiteConnectionWithLock( new SQLitePlatformiOS(), new SQLiteConnectionString("your_db_path.db", storeDateTimeAsTicks: true) ); // 多线程并发操作 Parallel.For(0, 100, i => { threadSafeConn.Insert(new YourModel { Id = i, Content = $"Test {i}" }); });
这个方案既满足了连接复用,又不用自己手动加锁,省心很多。
额外提醒
千万不要自己手动给普通的SQLiteConnection加锁后共享使用——虽然看起来能解决问题,但很容易因为遗漏某些操作(比如事务中的嵌套调用)导致死锁或者其他隐藏问题,不如直接用官方提供的SQLiteConnectionWithLock靠谱。
内容的提问来源于stack exchange,提问作者user4878754

