问题两个
1 时间戳如何传递?
2 我的代码是否可行?
以上虽然是两个问题,但是实质是一个昨天,在csdn和google  baidu,搜索了一下午
大都一笔带过,所以我想多问问开发平台vs2005+sqlserver2005
vs2003+sqlserver2000
我想用时间戳来处理并发
就是最常见的一种情况:
user1 取出了row1
user2 也取出了row1
user1 修改后,点击button,向数据库提交修改数据
user2 也做了修改,在user1之后,这个时候,要告诉user2,如果你修改,则将把user1的数据覆盖
是否继续修改,等等一些类似这样的操作。
总结起来,大概就是这样:
1 select 时间戳   
2 保存到前台的某个隐藏控件中
3 送回数据库的时候,将隐藏空间中的时间戳送回去
进行比对:如果等,更新,否则,报错
网上的例句是 sql = "update ... where id=" & id & " and tmstmp=" & tmstmp
这样出来的问题是,如何将隐藏控件中的值,转换为时间戳?因为在比对的时候,string型和时间戳的类型铁定不能比对
面对这个问题,我只能这么做,所以想求证,如下做可以吗?代码如下:1 取出时间戳
string sql = "select AdminAccount,AdminPwd,convert(bigint,optimistic) as optimistic from Admin";
或者 string sql = "select AdminAccount,AdminPwd,optimistic+0 as optimistic from Admin";2 保存到隐藏控件中,我的是gridview的某一隐藏列
3 送回数据库,此处是重点:public int AdminUpdate(string id, string pwd, string timestamp)//我说过了,因为无法比对时间戳类型,所以我只能比对string
    {
        //timestamp:从隐藏控件中传回来的值
int rowsAffected = 10;
        string ts = tstamp(id);//在更新之前,再次通过id取得时间戳
        if (string.Compare(ts, timestamp).Equals(0))
        {
            string sql = string.Format("update Admin set AdminPwd = '{0}' where AdminAccount = '{1}'", pwd, id);
            using (SqlConnection conn = new SqlConnection(constring))
            {
                SqlCommand cmd = new SqlCommand(sql, conn);
                conn.Open();
                //cmd.ExecuteNonQuery();
                rowsAffected = cmd.ExecuteNonQuery();
                cmd.Dispose();
            }
        }
        return rowsAffected;
    }
private string tstamp(string id)
    {
        string ts;
        string sql = string.Format("select convert(bigint,optimistic) as optimistic from Admin where AdminAccount = '{0}'",id);
        using (SqlConnection conn = new SqlConnection(constring))
        {
            SqlCommand cmd = new SqlCommand(sql, conn);
            conn.Open();
            SqlDataReader reader = cmd.ExecuteReader();
            cmd.Dispose();
            if (reader.Read())
            {
                ts = reader[0].ToString();
            }
            else
            {
                ts = "0";
            }
            reader.Close();
            return ts;
        }
    }

解决方案 »

  1.   

    user1 取出了row1 
    user2 也取出了row1 
    user1 修改后,点击button,向数据库提交修改数据 
    user2 也做了修改,在user1之后,这个时候,要告诉user2,如果你修改,则将把user1的数据覆盖 
    是否继续修改,等等一些类似这样的操作。用事务处理怎么样?
      

  2.   

    and cast(tmstmp as varchar(100))=" & tmstmp 
      

  3.   

    理论上没什么问题。时间戳本来记载的就是数据操作的时间。
    但是如果user1和user2同时打开这个页面,
    按照楼主的思路会将时间戳的值保存在user1和user2打开的页面上。并且值是相同的;
    在user1修改时,会先去数据库查询当前记录的时间戳,
    正巧user2这时候也修改,而user1还来不及执行update,那user2查到的时间戳就和user1是一样了。
    那这时候比较的话。就不知道已经被user1修改过了。如果再更新就会覆盖user1的更新了。。问题就是查询时间戳操作和更新操作中间间隔越长,出现这种并发的可能性越大
    建议将查询和更新操作不要分开操作。可以
    Update Admin set AdminPwd = '{0}' where AdminAccount = '页面上隐藏控件的时间戳'SQL SERVER默认在更新时会加上排它锁,所以在这里不用担心有其他用户与之产生并发。
    如果更新操作后,受影响行数为0,说明已经被人更改过了,如果受影响行数大于0,则修改成功。
      

  4.   

    转换成bigint也是可以的.
      

  5.   

    SqlParameter[] signOnParms = GetSignOnParameters(); 
    SqlParameter[] accountParms = GetAccountParameters(); 
    SqlParameter[] profileParms = GetProfileParameters(); signOnParms[0].Value = acc.UserId; 
    signOnParms[1].Value = acc.Password; SetAccountParameters(accountParms, acc); 
    SetProfileParameters(profileParms, acc); using (SqlConnection conn = new SqlConnection(SQLHelper.CONN_STRING_NON_DTC)) { 
    conn.Open(); 
    using (SqlTransaction trans = conn.BeginTransaction()) { 
    try { 
    SQLHelper.ExecuteNonQuery(trans, CommandType.Text, SQL_INSERT_SIGNON, signOnParms); 
    SQLHelper.ExecuteNonQuery(trans, CommandType.Text, SQL_INSERT_ACCOUNT, accountParms); 
    SQLHelper.ExecuteNonQuery(trans, CommandType.Text, SQL_INSERT_PROFILE, profileParms); 
    trans.Commit(); }catch { 
    trans.Rollback(); 
    throw; 


    }