我的设置:用户有一个页面,他执行一些操作和数据转换 我将这些操作存储在数据集中(在会话中) 然后,在按钮单击时,我需要执行一些更多转换并调用自定义数据库函数,该函数将每个数据表中的每一行插入到数据库中。我已经解决了所有这些问题并且效果非常好。
但是,现在,我需要做的是修改按钮单击事件不要立即运行,而是将该操作放入队列(这是所有用户的公共队列)。因此,如果user1单击该按钮,则user2单击该按钮,然后我们需要获取user1数据集并在其上运行方法,并且仅在此之后获取user2数据集并在其上运行方法。所有的一个队列。
private void btnclick()
{
DataSet ds = Session["test"] as DataSet;
PerformFinalTransformation(ds);
foreach (DataTable dt in ds.Tables)
{
foreach (DataRow dr in dt.Rows)
{
CallCustomSqlFunction(dr);
}
}
}
我想避免在可能的情况下将数据集存储在数据库中,因为它们对于每个用户(表/列的数量)并不相同。我正在寻找关于如何在asp.net / c#中完成此任务的任何指示。 (石英网是我应该考虑的吗?)。我应该寻找什么概念?并行编程?还是asp.net队列?或者是其他东西?甚至无法启动,因为不知道该从什么开始。顺便说一句,如果有所帮助,我会在我的应用程序中使用最新的DotNetNuke。
答案 0 :(得分:2)
要重新启动,您必须将队列存储在数据库中。您可以通过将每个数据集序列化为xml并将生成的xml存储在nvarchar(max)
列中来克服数据差异。
运行队列的最佳方法是使用单独的Windows服务,一次选择一个项目并进行处理。您可以对IIS执行相同的操作(只需在Application_Start
中启动另一个线程),但我不建议将其作为不可扩展的(并且需要重新启动IIS,池再循环等)。
答案 1 :(得分:2)
从架构的角度来看,您的解决方案很好。队列是要走的路。但是,解决方案并非易事。需要考虑的一些事情:
根据你的答案,我给你一些选择:
内存中的队列,使用[ConcurrentQueue][1]
,在一个线程中上升。可能使用Singleton来启用对队列的访问。我不建议你这样做。
创建服务,通过WCF公开接口并从ASP.Net应用程序访问它。该服务也应该包含[ConcurrentQueue][2]
,访问数据库等将是服务职责(您仍然会遇到崩溃和数据丢失的问题)。
使用MSMQ。还有一些服务来封装从ASP.Net接收调用的功能(如果你不想让ASP.Net直接访问MSMQ)并访问数据库(MSMQ调用这个服务)。
这些只是我的头脑。请随时发表评论,我会尽可能回答(我现在正在工作)。
答案 2 :(得分:0)
由于我对这些问题知之甚少,WCF和MSMQ都是很好的解决方案,在你的场景中肯定会有所帮助。如果你做得好,编写你想要的数据库实现并不是很糟糕。您可以在每次插入后将字段设置为AutoIncrement
,将数据添加到数据库中。
然而,要使用队列来解决这个问题,下面是几个指南和示例:
一些示例项目实施:
希望你发现它们有用。祝你好运。
答案 3 :(得分:0)
是否可以使用table value parameter提交数据,而不是为每一行调用函数将其插入数据库?这是SQL Server 2008及更高版本的一项功能,它允许您在单个语句中完全提交表。
使用这种解决方案,您可能不需要队列。我发现当我切换到表参数时,我的代码在性能上有了很大提高,因此没有必要批处理语句。
以下是您的代码的工作方式:
private void btnclick()
{
DataSet ds = Session["test"] as DataSet;
PerformFinalTransformation(ds);
using (SqlConnection conn = new SqlConnection(my_connection_string)) {
conn.Open();
using (SqlCommand cmd = new SqlCommand("insert_multiple_tables", conn)) {
cmd.CommandType = CommandType.StoredProcedure;
SqlParameter param = new SqlParameter("@table0", SqlDbType.Structured);
param.Value = ds.Tables[0];
cmd.Parameters.Add(param);
SqlParameter param = new SqlParameter("@table1", SqlDbType.Structured);
param.Value = ds.Tables[1];
cmd.Parameters.Add(param);
cmd.ExecuteNonQuery();
}
}
}
然后,您可以像这样定义存储过程:
CREATE TYPE udt_mytable0 AS TABLE (
col1 int,
col2 varchar(255),
col3 datetime,
-- and so on
)
CREATE TYPE udt_mytable1 AS TABLE (
col1 bigint
)
CREATE PROCEDURE insert_multiple_tables
@mytable0 udt_mytable0 READONLY,
@mytable1 udt_mytable1 READONLY
AS
INSERT INTO mydatabase0
(col1, col2, col3)
SELECT
col1, col2, col3
FROM
@mytable0
INSERT INTO mydatabase1
(col1)
SELECT
col1
FROM
@mytable1
答案 4 :(得分:0)
如果我应该这样做,我可能最终会采用以下方式:
队列存储
如果您不想将队列保留在内存中(这可能是个坏主意,请参阅其他答案)您需要在服务器上安装某种数据库或其他存储,而这些存储在服务器重置时未清除和那样的东西。为此,您当然可以使用像SQL Server这样的传统数据库,但也可以使用其他选项。
如果您已经在服务器上没有SQL Server或类似的商业数据库,我建议使用像RavenDB这样的文档数据库,或者只是将队列存储为一系列带有时间戳的文件(XML序列化)(请记住在文件名中使用某种随机性,这样你就不会得到两个具有相同时间戳的文件,这是不太可能的,但它会发生)。这两种情况都存在问题,但我认为没有完美的解决方案,因此可以归结为您希望用户使用您的服务的频率。
清空队列
根据您使用的队列的存储类型,我只需将控制台应用程序设置为每5分钟运行一次的服务器上的计划任务,或者运行所需的频率。计划任务检查队列中是否有新作业,并继续处理最高作业。
<强>结论强>
以上描述是“简单”的方法。它不需要很多技能,也不需要你进入一种全新的框架和类似的东西。
如果是我的话,我会选择文件和计划任务的解决方案,因为它很容易实现和测试。如果您遇到大量流量,您可以随时更改存储队列的方式,使其更加友好。
作为最后一句话:记得在从队列处理作业时进行记录以帮助您进行调试;)
答案 5 :(得分:0)
我认为你应该看看并行库中的“任务”......
http://msdn.microsoft.com/en-us/library/dd537609.aspx
处理asinc队列非常好。
虽然我建议你使用某种持久性来避免数据丢失,不管是在db中的另一个表中,还是在文件或任何其他方法中序列化。
您不应该只信任内存存储。 IIS重置或Windows重启,即使在appPool中回收也会破坏未处理的数据。
答案 6 :(得分:-1)
我认为您可以使用缓存来实现这一目标。创建包含每个会话数据的队列,并将队列存储在缓存中。然后使用缓存执行自定义数据库操作。当您使用队列时,它将是FCFS。因此,只有在使用用户1之后才会使用用户2的数据。