时间戳和事务

    技术2022-05-18  10

     

    开发平台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和user2同时打开这个页面, 按照楼主的思路会将时间戳的值保存在user1和user2打开的页面上。并且值是相同的; 在user1修改时,会先去数据库查询当前记录的时间戳, 正巧user2这时候也修改,而user1还来不及执行update,那user2查到的时间戳就和user1是一样了。 那这时候比较的话。就不知道已经被user1修改过了。如果再更新就会覆盖user1的更新了。。

    问题就是查询时间戳操作和更新操作中间间隔越长,出现这种并发的可能性越大。。。 建议将查询和更新操作不要分开操作。可以 Update Admin set AdminPwd = '{0}' where AdminAccount = '页面上隐藏控件的时间戳'

    SQL SERVER默认在更新时会加上排它锁,所以在这里不用担心有其他用户与之产生并发。 如果更新操作后,受影响行数为0,说明已经被人更改过了,如果受影响行数大于0,则修改成功。

     

     

    2.  另一个的回答  #6楼 得分:30回复于:2009-09-02 10:43:40SqlParameter[] 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; } } } 

     

     

    我对此还是处于研究中,对于数据库的精通变得尤其中很重要的

    对此可以参考其他的资料以及在技术群中的谈话中:

      

    http://topic.csdn.net/u/20090902/10/adb3ff6f-e793-482c-99bb-770c478753f3.html 


    最新回复(0)