0

我正在尝试从 MSSQL 和 PostrgeSQL 数据库中检索数据,以定期(每小时)将其填充到 MySQL 数据库中。

根据我所做的一项研究,我想使用 C# Timer 来做到这一点。但是,我并不完全理解计时器的工作方式。我在 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();
}

这行得通,但是...

问题是这样每次加载页面时都会初始化计时器。如何创建一个仅初始化一次并从那一刻起继续运行而不重新初始化的计时器。此外,如果计时器或方法失败 - 引发异常或服务器宕机,我该如何处理?那我该如何重新启动计时器呢?

任何见解都会有所帮助!先感谢您!

4

5 回答 5

2

您不想在 ASP.NET 网页上执行此操作。ASP.NET 计时器设计用于在您离开之前在页面的生命周期内发生的操作。

如果您想做这样的长期工作(即 24/7 每小时一次的任务),您最好:

  • 使用带有 System.Timer 的 always on Windows 服务或
  • 使用具有每小时 1 次计划的 Windows 计划任务,这将启动控制台应用程序。

另一种选择,因为您的任务似乎与数据库数据传输密切相关,所以使用 SSIS 或其他替代 ETL 工具(Extract-Transform-Load)

于 2012-04-17T21:36:53.620 回答
1

其他答案涉及到这一点;我会打它的头: ASP.NET 中的计时器是一个坏主意。

原因与 ASP.NET 生命周期有关。最简单的一点是,每次页面加载都会实例化一个 Page 类的实例(您的代码隐藏)。一旦生成的页面作为 HTML 输出到客户端的浏览器,页面实例就会离开作用域并被销毁。这意味着您的计时器(设置为从现在开始运行一个小时)将在其 Tick 事件触发之前很久就消失了;对于简单页面,Page 类可以在内存中持续不到一秒。

在某些情况下,您可以通过将 Timer 存储在 Session 中来解决此问题,只要用户连接到站点,它就会持续存在。但是,会话的超时时间通常早于一个小时(15 分钟是一个常见的标准;具有大量私人数据的网站,如在线银​​行应用程序,超时速度最快可达 5 分钟)。

所以,我重申,不要在 ASP.NET 代码中使用定时器。相反,您可以在 Web 服务器(或应用服务器)上运行的 Windows 服务中使用 Timer,该服务将每小时执行一次数据提取。它可以由 Web 应用程序提供信息,例如连接了哪些用户,可能是通过访问 ASP.NET 使用的数据库来验证/授权在线用户帐户。

如果它只是必须是一个进行数据刷新的网络应用程序,那么我会在页面上的某处保留一个隐藏字段或 JavaScript 变量,以指示下次应该提取数据的时间。为文档加载时设置一个 JavaScript timeout(),这会触发一个 AJAX 回调到服务器以运行一个事件处理程序,该处理程序用来自其他两个 DB 的数据刷新 MySql。始终验证此数据刷新确实应该在您的代码隐藏中发生(可能通过在 Session 或 ViewState 中保持相同的值),否则使用 FireBug 或 Chrome 内置的插件将您自己的页面代码转换为 DoS 机制是微不足道的- 在代码编辑器中。如果更新时间已经过去,您也可以从 Page_Load 触发相同的事件,在用户禁用 JavaScript 的情况下覆盖您自己;

于 2012-04-17T21:49:13.417 回答
0

在 Global.asax 中初始化计时器。OnApplicationStart 方法.. 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

于 2012-04-17T21:37:14.157 回答
0

如果您声明所有其他变量,您可能想要将初始化程序移动到的第一件事。接下来,您可以在页面中加载一个函数,将您的间隔时间设置为到达下一小时所需的时间。这就是我所做的。

    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();
    }

授予您的情况可能会有所不同,但这可能会对您有所帮助。

于 2012-04-17T21:37:23.857 回答
0

假设您因无法访问控制台应用程序、Windows 服务或本地系统来安排任务而受到限制,一种选择是执行以下操作。当没有计时器可用时,我对模拟计时器的解决方案。

此外,您还需要假设计时器不必完全按小时触发。

  1. 将一个表添加到您的数据库中,该表记录了上次运行计时器作业的时间。
  2. 页面加载完成后,检查自上次运行计时器作业以来是否已经过了一个小时。
  3. 如果已经过了一个多小时,则在该点执行时间作业。
  4. 当作业开始时将日志记录到它启动的数据库中,从而防止另一个作业启动。

请记住,当您没有其他选项时,这是一种非常古怪的模拟计时器的方法。

于 2012-04-18T03:19:35.340 回答