如何使用Autofac为Dapper创建IDbConnection工厂解决并行操作问题
问题根因
你之前使用InstancePerLifetimeScope注册IDbConnection的方式,会导致同一个生命周期作用域内仅存在一个SqlConnection实例,而SqlConnection本身是非线程安全的,多线程并行操作时争抢同一个连接实例就会出现并发冲突、操作异常等问题。
实现方案
你可以通过以下两种方式实现连接工厂,解决并行操作的问题:
方案一:自定义连接工厂(更易扩展、易测试)
1. 定义工厂接口与实现
// 工厂接口 public interface IDbConnectionFactory { IDbConnection Create(); } // SqlServer连接工厂实现 public class SqlConnectionFactory : IDbConnectionFactory { private readonly string _connectionString; public SqlConnectionFactory(string connectionString) { _connectionString = connectionString; } public IDbConnection Create() { // 每次调用都返回新的连接实例 return new SqlConnection(_connectionString); } }
2. Autofac 注册配置
// 工厂本身无状态,可注册为单例 builder.RegisterInstance(new SqlConnectionFactory(_connectionString)) .As<IDbConnectionFactory>() .SingleInstance();
3. 使用示例
public class YourDataService { private readonly IDbConnectionFactory _connectionFactory; // 注入工厂 public YourDataService(IDbConnectionFactory connectionFactory) { _connectionFactory = connectionFactory; } public async Task ParallelQueryDemo() { // 每个并行任务独立获取连接 var task1 = Task.Run(async () => { using var conn = _connectionFactory.Create(); return await conn.QueryAsync<EntityA>("SELECT * FROM TableA"); }); var task2 = Task.Run(async () => { using var conn = _connectionFactory.Create(); return await conn.QueryAsync<EntityB>("SELECT * FROM TableB"); }); await Task.WhenAll(task1, task2); // 处理查询结果 } }
方案二:Autofac委托工厂(无额外类定义,适合简单场景)
不需要额外定义工厂接口,直接注册委托类型的工厂:
// 1. 注册IDbConnection为瞬时模式,每次请求都返回新实例 builder.Register<IDbConnection>(c => new SqlConnection(_connectionString)) .InstancePerDependency(); // 2. 注册连接创建委托作为工厂 builder.Register<Func<IDbConnection>>(c => { var context = c.Resolve<IComponentContext>(); return () => context.Resolve<IDbConnection>(); });
使用时直接注入Func<IDbConnection>即可:
public class YourDataService { private readonly Func<IDbConnection> _connFactory; public YourDataService(Func<IDbConnection> connFactory) { _connFactory = connFactory; } // 后续使用逻辑和方案一完全一致,调用_connFactory()获取新连接 }
注意事项
- 每次从工厂获取的连接用完后要及时释放,建议配合
using语句自动释放,避免连接池泄漏 - 同一事务内的操作需要复用同一个连接,不要在事务范围内多次调用工厂创建新连接,避免触发不必要的分布式事务
- 如果需要支持多种数据库类型,扩展自定义工厂接口的实现即可,适配性更强
内容的提问来源于stack exchange,提问作者DiPix
相关产品推荐
相关产品推荐

