求大神解决SQL疑难杂症,数据重复插入问题。

qq_28793289 2017-05-31 09:32:17
情况如下: 程序放置于香港服务器,提交表单操作,大致有2%的概率会出现这个问题,就是数据重复执行了SQL。

1.打开页面随机生成字符串保存于SESSION中,提交表单成功后清空SESSION以防重复提交。
2.页面中的按钮也加了JS,点击后失效也是为了防止重复提交表单。

程序功能:新用户赠送100积分,点击提交按钮,系统扣除100积分升一级,则当前等级为2级,积分余额为0
有2%左右的用户,会造成 等级为3级,积分余额为-100

而且,SQL中也加入了判断 既 积分 - 100 <0 则 return;

请问,到底是怎么回事?可能跟服务器配置有关系吗?我只能想到这一点,程序是c#.net+mssql2008r2,服务器2核4G阿里云香港

重点在于:是新注册用户,同一操作,有2%的概率发生这种情况,我做了3年的开发,真想不通。请指教。
...全文
298 10 打赏 收藏 转发到动态 举报
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
  • 打赏
  • 举报
回复
引用 3 楼 closurer 的回复:
这是一个多线程的线程安全问题。 实际上 SQL 的锁就可以完全解决这个问题。http://blog.csdn.net/closurer/article/details/54288628
你那文章没写解决方法啊
正怒月神 版主 2017-06-01
  • 打赏
  • 举报
回复
新用户赠送100积分,点击提交按钮,系统扣除100积分升一级,则当前等级为2级,积分余额为0 有2%左右的用户,会造成 等级为3级,积分余额为-100 就这句话,其实很明显,是并发的问题了。 在存储过程中加个事务
闭包客 2017-06-01
  • 打赏
  • 举报
回复
这并不是什么疑难杂症,线程安全是很普遍的问题。
闭包客 2017-06-01
  • 打赏
  • 举报
回复
这是一个多线程的线程安全问题。 实际上 SQL 的锁就可以完全解决这个问题。http://blog.csdn.net/closurer/article/details/54288628
  • 打赏
  • 举报
回复
在前端页面有一种情况会造成点击一次按钮提交两次表单。当按钮为input且类型为submit,同时js来控制表单的提交,在js中调用submit()方法前其实浏览器已经执行了input的submit事件,然后再执行js中的submit方法,提交两次表单。
  • 打赏
  • 举报
回复
写测试程序,那么显然就不需要人工“用眼睛”来判断是否出错,你的代码应该会断言。可能一个测试不能发现问题,那么就写2个、3个,把不同的纠结变为代码。信心是一点一点增长起来的。 你贴出来一大堆代码却却没有勇气和信心,也不能通常就迅速(半分钟之内)意识到问题出在哪里,这就跟开发方式有关系。你的开发是以应付差事儿的方式驱动的,而不是以测试来驱动的。那么你报 bug 时贴出的代码往往也就不是关键的出错点的代码、需要调试的代码。
  • 打赏
  • 举报
回复
SQL Server 默认会对每一个自动创建一个事务 --> SQL Server 默认会对每一个会话请求而自动创建一个事务 自己先写一个测试用例,比如说用10个线程,每一个线程分别执行20遍这个操作,最终用来证明调用你这个错误确实会产生。写测试的时候你回会动脑筋了,就能自己发现下一步该干什么。 你只是反复重复念叨“我想怎么怎么”这不是编程之道。好的程序员是会发过来破坏系统、会测试系统,而不是只会刚刚开始编写代码。
  • 打赏
  • 举报
回复
那你写个测试用例测试一下并发情况下确实会同时处理数据表吗?先自己动手写测试,不要只听别人的(包括我说的)。 SQL Server 默认会对每一个自动创建一个事务。因此当你从 c# 发送命令让Sql Server 服务器执行这个存储过程时,当它访问 YH_SystemInfo 以及 YH_Personnel 表之后,立刻就会为所访问的记录加上排它的事务锁,其它事务是不可能脏读的。除非你把默认的事务级别设置给改了(而我基本上从未碰到有这么多事儿的人喜欢去设置这个)。 除此以外,假设你在 c# 程序中在你的过程的开始和结束时是用了 DbTransaction.BeginTransaction 已经 DbTransaction.Commit,那么你显式地将你的多行代码的执行过程放在了 SQL Server 事务加锁的过程中,那么也不可能让并发情况发生(这就跟 lock 语句类似),而是只能让多进程、多线程的执行过程排队通过 DbTransaction 范围。除非你的这个事务范围定义不当。 这并不是什么“疑难杂症”。你并没有有针对性地测试,所以不知道具体问题出在那里。这里只能说几句简单的理论知识。你要学会自己写写测试程序,自己起码要知道该调试什么东西。不要翻来覆去地只是看各种理论。
freeflying1222 2017-05-31
  • 打赏
  • 举报
回复
如果是自己的源代码,就添加log吧。 把每次提交都记录下来,信息记录全一点(时间/UserId/SessionId……),看究竟是在那种情况下出现的重复提交。
qq_28793289 2017-05-31
  • 打赏
  • 举报
回复
declare @gdp_syCount bigint--剩余总额
	declare @CurrentPrice_ml decimal(18,2) /*--当前价--*/
	declare @Number decimal(18,2) /*--购买数量--*/
	declare @MoneyCompoundGold decimal(18,2) /*--当前用户总--*/
	declare @SystemInfo11 bit  ----是否自动------
	select @gdp_syCount=dbo.GetDecimal(SystemInfo16)-dbo.GetDecimal(SystemInfo46),@CurrentPrice_ml=SystemInfo17,@SystemInfo11=SystemInfo11 from YH_SystemInfo where ID=1
	if @gdp_syCount<=0 
		return
	if @CurrentPrice_ml>=4
		return
	if @SystemInfo11=0
		return
	
	select @MoneyCompoundGold=MoneyCompoundGold from YH_Personnel where ID=@PersonnelID
	
	if @MoneyCompoundGold>=@GGB_Nub
		set @Number=@GGB_Nub/@CurrentPrice_ml
	else
		set @Number=@MoneyCompoundGold/@CurrentPrice_ml
		
	if @Number<=0
		return 
	set @Number=dbo.GetInt(@Number)
	set @GGB_Nub=@Number*@CurrentPrice_ml
	if @MoneyCompoundGold-@GGB_Nub<0 --小于0则返回不执行
	    return
	
	insert into YH_GdpTransaction(yhGUID,PersonnelID,Transaction01,Transaction02,Transaction03,Transaction04,Transaction05,Transaction11)
	 values (NEWID(),@PersonnelID,@CurrentPrice_ml,@Number,@GGB_Nub,1,2,GETDATE())	
	
	update YH_Personnel set  MoneyCompoundGold=dbo.GetDecimal(MoneyCompoundGold)-@GGB_Nub,
	MoneyGDP=dbo.GetDecimal(MoneyGDP)+@Number where ID=@PersonnelID	
	
	insert into YH_TakeMoney(yhGUID,PersonnelID,EventType,Money,Currency,Remark,Status,Editor,TM01,MER02)
		values (NEWID(),@PersonnelID,52,-@GGB_Nub,5,'扣除积分:'+CONVERT(nvarchar,@GGB_Nub)+' 获得XX数量:'+CONVERT(nvarchar,@Number),2,@PersonnelID,@PersonnelID,'auto')
   --同一时间戳,执行了2次
		
	declare @s int 
	exec BuyEDA @PersonnelID,@Number,@s out

62,047

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术交流专区
javascript云原生 企业社区
社区管理员
  • ASP.NET
  • .Net开发者社区
  • R小R
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

.NET 社区是一个围绕开源 .NET 的开放、热情、创新、包容的技术社区。社区致力于为广大 .NET 爱好者提供一个良好的知识共享、协同互助的 .NET 技术交流环境。我们尊重不同意见,支持健康理性的辩论和互动,反对歧视和攻击。

希望和大家一起共同营造一个活跃、友好的社区氛围。

试试用AI创作助手写篇文章吧