我正在寻找处理多用户访问C#-Sql服务器应用程序的建议。 C#程序从日期为空的表中选择前5行,然后根据用户的输入更新这些记录。如果有多个人正在使用该应用程序,我该如何确保数据保持一致?我正在使用网格控件来显示数据和一个调用SaveToDataBase过程的按钮。这是零件代码
protected void Page_Load(object sender, EventArgs e)
{
string sqlSel = @" SELECT TOP 5 r.[keyid], name
FROM db1.Table1 r where date is null
GROUP BY r.keyid, name; ";
if (!IsPostBack)
{
using (SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["SQLConnectionString"].ConnectionString))
{
connection.Open();
SqlCommand cmdSel = new SqlCommand(sqlSel, connection);
SqlDataReader reader1 = cmdSel.ExecuteReader();
while (reader1.Read())
{
DataSet ds = GetData(sqlSel);
if (ds.Tables.Count > 0)
{
GridView1.DataSource = ds;
GridView1.DataBind();
}
else
{
Response.Write("Unable to connect to the database.");
}
}
connection.Close();
}
}
protected void SaveToDatabase()
{
string datenow = DateTime.Now.ToString(@"MM\/dd\/yyyy h\:mm tt");
string sqlUpd = @"UPDATE [db1].[Table1] set DateVerified=@datenow where KeyID=@keyID and name=@name";
try
{
using (SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["SQLConnectionString"].ConnectionString))
{
connection.Open();
SqlCommand cmdUpd = new SqlCommand(sqlUpd, connection);
cmdUpd.Parameters.Add("@datenow", SqlDbType.DateTime);
cmdUpd.Parameters["@datenow"].Value = datenow;
Int32 rowsAffected = 0;
rowsAffected = cmdUpd.ExecuteNonQuery();
connection.Close();
}
private DataSet GetData(string cmdSel)
{
String strConnString = System.Configuration.ConfigurationManager.ConnectionStrings["SQLConnectionString"].ConnectionString;
DataSet ds = new DataSet();
try
{
SqlConnection con = new SqlConnection(strConnString);
SqlDataAdapter sda = new SqlDataAdapter(cmdSel, con);
sda.Fill(ds);
由于 Rashmi
答案 0 :(得分:1)
您可以使用乐观并发和版本ID之类的内容,每当有人更改行时都应该更新,例如:
// Table User
create table User(
Id int primary key,
Name varchar(300) not null,
Version long not null default 0
);
// the select code
select Id, Name, Version
from User
where Id = ?
// the update code
update User
set
Name = ?
Version = Version + 1
where
Id = ?
and Version = ?
想象一下,两个用户进入一个屏幕,您可以在其中更新用户名。想象一下您的代码的以下顺序:
UserA: select Id, Name, Version from User where Id = 1; // (1, John Doe, 0)
UserB: select Id, Name, Version from User where Id = 1; // (1, John Doe, 0)
UserA: update User set Name = 'Jane Doe' Version = Version + 1 where Id = 1 and Version = 0; // 1 row updated
UserA: commit;
UserB: update User set Name = 'Mr John Doe' Version = Version + 1 where Id = 1 and Version = 0; // 0 row updated which means someone updated the row
UserB: rollback; // you should rollback and send an info to the user that someone changed the information he was seeing (refresh the screen)
使用这种方法可以防止锁定行。每次更新o删除某些内容并且受影响的行数与您预期的不同时,应该应用乐观并发。 大多数ORM框架已经通过使用版本或时间戳实现了这种方法,但逻辑是相同的。请记住,应始终执行版本字段的更新。
你应该知道如何使用这个实际的例子来实现ORM(在这种情况下是实体框架)如何在这里实现这个逻辑:http://www.asp.net/mvc/tutorials/getting-started-with-ef-5-using-mvc-4/handling-concurrency-with-the-entity-framework-in-an-asp-net-mvc-application
答案 1 :(得分:0)
有几种不同的方法:
您可以将WHERE条件添加到update语句中。第一个用户更新记录将受到影响 - 行= 5,下一个影响行= 0,因此您知道他的数据无法保存,但必须重新加载(并最终合并)。
或者您可以在获取数据时将记录设置为分配给用户,以便下一个记录获得不同的记录(WHERE (AssignedUser <> @MYUSER)
)。
如果您真的想要锁定 - 这意味着在第一个用户保存之前,另一个应用程序无法读取前5个记录 - 您可以使用非常严格的IsolationLevel在一个事务中进行读写。
答案 2 :(得分:0)
防止更新分配了日期的值
update table set value = 1, date = getdate()
where id = 1 and date is null
如果date为null,我想你会更新0行 所以你可以提供用户反馈
但是一次只有5个问题,因为这会增加碰撞的可能性(日期不为空)
我会有某种类型的锁定
可能在更新前指定日期为1/1/1900
update table set value = 1, date = getdate()
where id = 1 and (date is null or date = '1/1/1900')
然后有一些机制将1/1/1900设置为定期为孤立