时间戳和事务

 

开发平台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:40
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;
}
}

 

 

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

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

 
 


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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值