定时任务场景下如何在普通类中访问数据库?
解决普通类中定时任务访问数据库的问题
嘿,我来帮你搞定这个问题!你已经把定时任务的逻辑搭好了,接下来只需要补上数据库访问的部分就行,给你几个实用的方案,都是C#场景下的常用做法:
方式一:依赖注入(推荐)
如果你的项目用了依赖注入框架(比如ASP.NET Core自带的DI),这是最规范的做法——把数据库上下文或者数据库访问服务注入到定时任务类里,既符合设计原则,也方便后续维护和测试。
举个Entity Framework Core的例子:
首先定义你的数据库上下文:
public class AppDbContext : DbContext { public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { } // 替换成你的实体集合 public DbSet<User> Users { get; set; } }
然后修改你的定时任务类,通过构造函数注入服务范围工厂(因为DbContext不是线程安全的),同时把定时间隔改成1小时(3600000毫秒):
public class DisconnectingUsers { private readonly IServiceScopeFactory _scopeFactory; private Timer _timer; public DisconnectingUsers(IServiceScopeFactory scopeFactory) { _scopeFactory = scopeFactory; TimerCallback tm = new TimerCallback(Disconnect); _timer = new Timer(tm, null, 0, 3600000); // 调整为每小时运行一次 } public void Disconnect(object state) { // 创建临时服务范围,确保DbContext使用完后被正确释放 using (var scope = _scopeFactory.CreateScope()) { var dbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>(); // 这里写你的数据库操作逻辑,比如标记 inactive 用户为已断开 var inactiveUsers = dbContext.Users.Where(u => !u.IsActive).ToList(); foreach (var user in inactiveUsers) { user.IsDisconnected = true; } dbContext.SaveChanges(); } } }
最后在项目的配置类里(比如Program.cs)注册DbContext和定时任务类:
// .NET 6+ 的 Program.cs 示例 var builder = WebApplication.CreateBuilder(args); // 注册数据库上下文 builder.Services.AddDbContext<AppDbContext>(options => options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection"))); // 注册定时任务类为单例 builder.Services.AddSingleton<DisconnectingUsers>(); var app = builder.Build(); // 其他配置... app.Run();
方式二:直接创建数据库连接(适合小型项目)
如果你的项目没用到DI,也可以在Disconnect方法里直接创建数据库连接,比如用SqlConnection:
public void Disconnect(object state) { // 从配置文件读取连接字符串,不要硬编码! string connectionString = ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString; // 使用using语句确保连接被正确释放 using (SqlConnection conn = new SqlConnection(connectionString)) { conn.Open(); // 执行你的数据库操作,比如更新用户状态 string updateSql = "UPDATE Users SET IsDisconnected = 1 WHERE IsActive = 0"; using (SqlCommand cmd = new SqlCommand(updateSql, conn)) { cmd.ExecuteNonQuery(); } } }
重要提醒
- 定时任务的
Timer是在后台线程运行的,EF Core的DbContext默认不是线程安全的,所以不要直接在单例类里注入Scoped的DbContext,一定要用IServiceScopeFactory创建临时范围(就是方式一里的做法)。 - 记得把定时间隔改成3600000毫秒(1小时),你原来的代码是10秒,别忘记调整哦!
内容的提问来源于stack exchange,提问作者Tempos
相关产品推荐
相关产品推荐

