使用SQLite+Dapper+UnitOfWork多Repository操作报Database locked错误
问题原因
- 重复释放同一连接:Controller层已经通过
using包裹了unitOfWork.Connection,但Repository层又对同一个连接对象套了using块,using执行结束后会直接释放连接。SQLite的事务绑定在连接上,连接被中途释放会导致锁无法正常释放,触发数据库锁定报错。 - 异步方法调用未等待:
CreateStuff是异步方法,但Controller调用时没有加await,异步操作未完成就执行后续逻辑,会导致多个写操作同时争抢SQLite的排他写锁,直接触发锁定。 - 事务未传递给Dapper操作:调用
ExecuteAsync时没有将UnitOfWork中开启的事务作为参数传入,Dapper会默认开启新事务,多个事务争抢同一个连接资源会引发锁库。 - 方法签名不合法:
CreateStuff方法内部用到了await,但方法返回值定义为void且没有加async关键字,会导致异步状态机异常,连接提前被释放。 - 重复打开连接:连接已经在Controller层调用
Open()打开,Repository层重复调用Open()会干扰连接和事务的绑定关系,增加异常概率。
修复方案
1. 调整Controller代码
public async Task MyMethodAsync() { // 注入UnitOfWork,此处仅为示例实现 var unitOfWork = new UnitOfWork(new SQLiteConnection($"Data Source=TestDb;Mode=Memory;Cache=Shared")); try { unitOfWork.Connection.Open(); unitOfWork.Begin(); var myFirstRepository = new MyFirstRepository(unitOfWork); var mySecondRepository = new MySecondRepository(unitOfWork); await myFirstRepository.CreateStuff(); await mySecondRepository.CreateOtherStuff(); unitOfWork.Commit(); } catch(Exception e) { unitOfWork.Rollback(); throw; } finally { unitOfWork.Connection.Dispose(); } }
2. 调整Repository代码
public class MyFirstRepository { private IUnitOfWork _unitOfWork; public MyFirstRepository(IUnitOfWork unitOfWork) { _unitOfWork = unitOfWork; } public async Task CreateStuff() { // 不要套using释放连接,不要重复Open连接 await _unitOfWork.Connection.ExecuteAsync( "INSERT INTO ...", param, // 传入当前UnitOfWork开启的事务 transaction: _unitOfWork.Transaction ).ConfigureAwait(false); } }
3. 补充UnitOfWork约定
确保IUnitOfWork接口暴露Transaction属性,Begin()方法执行后会将开启的事务对象存入该属性。
内容的提问来源于stack exchange,提问作者Joel Wiklund
相关产品推荐
相关产品推荐

