用于填充数据库的 C# 计时器
本文关键字:计时器 数据库 填充 用于 | 更新日期: 2023-09-27 18:31:30
我正在尝试从MSSQL和PostrgeSQL数据库中检索数据,以定期(每小时)将其填充到MySQL数据库中。
根据我所做的研究,我想使用 C# 计时器来做到这一点。但是,我不完全了解计时器的工作方式。我在Page_Load中声明它,设置已用事件处理程序并从事件处理程序调用方法。
protected void Page_Load(object sender, EventArgs e)
{
int duration = 100 * 60 * 5; //milliseconds * seconds * minutes
// Create a timer with a two second interval.
System.Timers.Timer timer = new System.Timers.Timer(duration);
// Hook up the Elapsed event for the timer.
timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
timer.Enabled = true;
}
void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
cf();
}
这行得通,但是...
问题是每次加载页面时都会以这种方式初始化计时器。如何创建一个仅初始化一次并从那一刻开始继续运行的计时器而不会重新初始化。另外,如果计时器或方法失败 - 引发异常或服务器出现故障,我如何处理这种情况?那我该如何重新启动计时器呢?
任何见解都会有所帮助!提前谢谢你!
您不希望在 ASP.NET 网页上执行此操作。ASP.NET 计时器设计用于在您导航离开之前在页面的生存期内执行操作。
如果你想做这样的长时间运行的工作(即每小时 24/7 一次的任务),你会更好:
- 将始终在线的 Windows 服务与 System.Timer 或
- 使用每小时 1 次计划的 Windows 计划任务,这将启动控制台应用程序。
另一种选择,因为您的任务似乎与数据库数据传输密切相关,因此使用SSIS或其他替代ETL工具(提取 - 转换 - 加载)之类的东西
其他答案涉及这一点;我会打它:ASP.NET 中的计时器是个坏主意。
原因与 ASP.NET 生命周期有关。它的最短之处在于,每次页面加载都会实例化 Page 类(代码隐藏)的实例。将生成的页面作为 HTML 输出到客户端浏览器后,Page 实例将离开范围并销毁。这意味着您的计时器(设置为从现在起一小时后运行)将在其 Tick 事件触发之前早已消失;对于简单页面,Page 类可以在内存中保留不到一秒钟。
在某些情况下,您可以通过将计时器存储在会话中来解决此问题,只要用户与站点的连接,计时器就会持续存在。但是,会话超时通常早于一个小时(15 分钟是常见标准;具有大量私人数据的网站,如在线银行应用程序,超时速度快至 5 分钟)。
因此,我重申,不要在 ASP.NET 代码中使用计时器。相反,您可以在 Web 服务器(或应用服务器)上运行的 Windows 服务中使用计时器,该服务将每小时执行一次此数据拉取。Web 应用程序可以为其提供信息,例如连接了哪些用户,可能通过访问 ASP.NET 用于验证/授权在线用户帐户的数据库。
如果它只是一个执行数据刷新的 Web 应用程序,那么我会在页面上的某个位置保留一个隐藏字段或 JavaScript 变量,指示下次应该提取数据的时间。为文档加载时设置JavaScript timeout(),以触发对服务器的AJAX回调,以运行事件处理程序,该处理程序使用其他两个数据库中的数据刷新MySql。 始终验证此数据刷新是否确实应该在代码隐藏中发生(可能通过在会话或视图状态中保持相同的值), 否则,使用FireBug或Chrome的内置代码编辑器等插件将自己页面的代码转换为DoS机制是微不足道的。如果更新时间已过,您还可以从Page_Load触发相同的事件,在用户禁用 JavaScript 的情况下覆盖自己;如果实际上是时候这样做,用户刷新页面将提取最新数据。
您可能希望将初始值设定项移动到声明所有其他变量的第一件事。接下来,您可以在页面中加载一个函数,将间隔时间设置为到达下一个小时所需的时间。这是我所做的。
private void SetTimer()
{
timer1.Stop();
var timeOfDay = DateTime.Now.TimeOfDay;
var nextFullHour = TimeSpan.FromHours(Math.Ceiling(timeOfDay.TotalHours));
var delta = (nextFullHour - timeOfDay).TotalMilliseconds;
timer1.Interval = (int)delta;
timer1.Start();
}
当然,您的方案可能略有不同,但这可能会对您有所帮助。
假设您因无法访问控制台应用程序、Windows 服务或本地系统来计划任务而受到限制,一个选项是执行以下操作。 当没有计时器可用时,我的模拟计时器解决方案。
此外,您还需要假设计时器不必在整点准确触发。
- 向数据库添加一个表,用于记录上次运行计时器作业的时间。
- 页面加载完成后,请检查自上次运行计时器作业以来是否已过一小时。
- 如果超过一个小时,则在该点执行时间作业。 当 time 作业启动时,会
- 记录到它已启动的数据库,从而阻止另一个作业启动。
请记住,当您没有其他选择时,这是一种非常古怪的模拟计时器的方法。
在 Global.asax 中初始化计时器。应用程序启动方法..http://msdn.microsoft.com/en-us/library/1xaaS8a2(v=vs.71).aspx
这里描述了类似的方法:http://www.west-wind.com/weblog/posts/2007/May/10/Forcing-an-ASPNET-Application-to-stay-alive