62,046
社区成员
发帖
与我相关
我的任务
分享
using System;
using System.Web.UI;
public partial class _Default : System.Web.UI.Page
{
private static object flag = new object();
protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack)
{
var key = string.Format("交易号_{0} & 明细行号_{1} 已经存在", this.TextBox1.Text, this.TextBox2.Text);
object r;
lock (flag)
{
r = Cache[key];
if (r == null)
Cache.Insert(key, true, null, DateTime.Now.AddSeconds(5), System.Web.Caching.Cache.NoSlidingExpiration);
}
if (r == null)
ScriptManager.RegisterStartupScript(this, this.GetType(), "判断重复提交", "alert('没有重复提交!');", true);
else
ScriptManager.RegisterStartupScript(this, this.GetType(), "判断重复提交", "alert('重复提交了!');", true);
}
}
}
你在问题中所写的 lock(this) 语句,首先对于并发的2个页面提交而言,其 this 完全不同,因此不会起任何作用;另外就算是起作用,也丝毫不能说明这样的lock 语句怎么就会极大延迟调用“远程服务交互操作”的问题。不明确的说法就不能作为编程依据。例如你说要整一个 Sleep(n) 语句,那么这个n 应该是多少才能明确保证逻辑上没问题呢?——你只敢于给一个“大得离谱”的时间才能说是明确的,否则时间稍短(但是不明确短到多少)就会出问题。这种思路,就是一个失败者的设计。而一个成功者的设计,总是从原理上彻底解决了问题,而不走这种“尝试修改 Sleep 参数”的思路。<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title></title>
</head>
<body>
<form id="form1" runat="server">
<asp:TextBox ID="TextBox1" runat="server" PlaceHolder="交易号" Text="29239"></asp:TextBox>
<asp:TextBox ID="TextBox2" runat="server" PlaceHolder="明细行号" Text="1"></asp:TextBox>
<asp:Button ID="Button1" runat="server" Text="Button" />
</form>
</body>
</html>
要防止“相同交易号相同明细行号”的记录被重复提交,服务器需要校验此情况发生。例如可以“数据缓存”机制保存主键值的5秒钟的一个“快照”,然后每一次提交页面是都判断快照中是否有重复数据。例如:using System;
using System.Web.UI;
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack)
{
var key = string.Format("交易号_{0} & 明细行号_{1} 已经存在", this.TextBox1.Text, this.TextBox2.Text);
var r = Cache[key];
if (r == null)
{
Cache.Insert(key, true, null, DateTime.Now.AddSeconds(5), System.Web.Caching.Cache.NoSlidingExpiration);
ScriptManager.RegisterStartupScript(this, this.GetType(), "判断重复提交", "alert('没有重复提交!');", true);
}
else
ScriptManager.RegisterStartupScript(this, this.GetType(), "判断重复提交", "alert('重复提交了!');", true);
}
}
}
你可以测试一下,程序根据5秒钟内是否有重复点button的情况而给出不同提示!
而你所说的 lock 是用在防止“刚好”极端并发的情况,也就是说使用了它就能更好地“确保”不会出现重复点击问题。此时可以这样写using System;
using System.Web.UI;
public partial class _Default : System.Web.UI.Page
{
private static object flag = new object();
protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack)
{
var key = string.Format("交易号_{0} & 明细行号_{1} 已经存在", this.TextBox1.Text, this.TextBox2.Text);
object r;
lock (flag)
{
r = Cache[key];
}
if (r == null)
{
Cache.Insert(key, true, null, DateTime.Now.AddSeconds(5), System.Web.Caching.Cache.NoSlidingExpiration);
ScriptManager.RegisterStartupScript(this, this.GetType(), "判断重复提交", "alert('没有重复提交!');", true);
}
else
ScriptManager.RegisterStartupScript(this, this.GetType(), "判断重复提交", "alert('重复提交了!');", true);
}
}
}
请仔细对比两段代码!只有一条语句需要lock,其它语句不需要lock。如果lock区域过大,包括了完全不需要lock的代码,会眼中影响程序性能。
因此 lock 虽然是“线程同步”的机制,它也是双刃剑。你明白lock为何只需要针对这样一条语句而操作,才应该使用 lock。