并发数量多时,造成.net网站数据错乱

stephen_deng 2014-06-24 05:47:27
网站近期日均PV有18000,用的是.net三层架构+mssql2005.订单量一多时,
偶尔产生三两条错乱的数据,A用户输入的的商品 被B用户打上自己订单号,造成商品出货发给了B,两人操作的时间相差两个小时,不是同时操作.
A用户操作detail.aspx页面插入加入商品到表detail中,
用户B操作header.aspx 1>生成订单号并保存订单信息到表header中,2>更新对应的子商品的信息(加订单号,备注要求出货)到表detail,
A用户和B用户的操作时会用到数据层的方法execute_simple

//conn是经操作层到业务层传来的
public static int execute_simple(string sql,SqlConnection conn)
{
try
{
SqlCommand com = new SqlCommand(sql, conn);
com.ExecuteNonQuery();
com.Dispose();
return 1;
}
catch (Exception e)
{
//AppException errlog = new AppException();
//errlog.ExceptionLog("execute_simple sqlmake层错误", e.Message);
string fileName = DateTime.Now.ToString("yyyyMMddhhmmss") + ".txt";
write_error_tolog.ErrorLog("sqlmaker_forcycle.execute_simple错误位置\r" + e.ToString(), fileName, "/ErrorLog/");
return 0;
}
}

请教朋友们,是不是因为用了static造成并发问题还是因为没有加事务处理?整个网站系统都没有加事处理,
更奇怪的是A用户和B不是同时操作造成的问题,非常不解.
...全文
517 20 打赏 收藏 转发到动态 举报
写回复
用AI写文章
20 条回复
切换为时间正序
请发表友善的回复…
发表回复
zglover 2016-10-09
  • 打赏
  • 举报
回复
同意楼上的,楼主你应该把相关联的几个表的结构关系和值贴出来,这样才有助于分析
greatbody 2016-10-09
  • 打赏
  • 举报
回复
使用guid没有。否则可能会有产生重复的id等等。
jmcooler 2016-10-09
  • 打赏
  • 举报
回复
static 本身不会有问题,有问题的是,在同一个 SQL 连接上,同时并发执行 Insert 操作。 这里有几点思路: 1、了解下,SQL 相关的类,是否是线程安全的,特别是 SQL 连接对象,是否是线程安全的 2、你自己的代码,是否是线程安全的。也即静态函数中,绝对不要使用全局变量 3、如果你的插入操作,需要涉及到多个表,那么必须使用事务。 4、如果对并发要求比较高,你可以建立一个 SQL 连接池,该池子中有若干数据库连接,每次请求,都从连接池中 拿出一个来,执行完 SQL,再放进去。 不过操作连接池时,需要加锁
圣殿骑士18 2016-10-09
  • 打赏
  • 举报
回复
怎么这么多坟贴
  • 打赏
  • 举报
回复
没看到你贴出任何有用的代码、结构。所谓的”商品、detail、head”的关键结构和值是如何设计的?所谓的“1>...... 2>...... 代码如何设计的”?
闭包客 2016-10-08
  • 打赏
  • 举报
回复
我个人认为你的 sql 命令里面有获取最新的自增 id 这种操作。 如果获取的自增 id 不正确,订单明细(detail)就记录在错误的订单头(head)中。
闭包客 2016-10-08
  • 打赏
  • 举报
回复
定位这种问题最好是有日志。 记录下传入的 sql 这个变量,有可能在组合 sql 字符串的时候引用了静态变量。
闭包客 2016-10-08
  • 打赏
  • 举报
回复
偶发的问题只看代码是较难定位的。 不过至少可以确定这个静态方法没有问题,里面没有引用静态变量,可以排除这个。 如果时间相差两小时也不可能是事务的问题,问题是你怎么确定相差两小时?因为用户会新建订单,也会修改订单。
wolf198 2016-10-08
  • 打赏
  • 举报
回复
参数 SqlConnection 是否有共用?
stephen_deng 2014-06-25
  • 打赏
  • 举报
回复
感谢各位回复,问题出在哪里仍没答案.
stephen_deng 2014-06-24
  • 打赏
  • 举报
回复
回复 请叫我官人 我一楼的是方法,不是变量哦,呵
stephen_deng 2014-06-24
  • 打赏
  • 举报
回复
回复bwangel 我的业务逻辑层都是简单的逻辑,

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Data.SqlClient;
using DAL;
namespace BLL
{
    public class receivedlist_bll
    {
        public DataTable getexcomitem()
        {
            receivedlist_dal receivelistdal = new receivedlist_dal();
            return receivelistdal.getexcomitem();
        }

        public DataTable getcutorderitems(string weblogin)
        {
            receivedlist_dal receivelistdal = new receivedlist_dal();
            return receivelistdal.getcutorderitems(weblogin);
        }
        public bool getoneitem(string tmpkey)
        {
            receivedlist_dal sysdal = new receivedlist_dal();
            return sysdal.getoneitem(tmpkey);
        }
        public string getoneitem2(string tmpkey)
        {
            receivedlist_dal sysdal = new receivedlist_dal();
            return sysdal.getoneitem2(tmpkey);
        }
        public bool getoneitem3(string tmpkey)
        {
            receivedlist_dal sysdal = new receivedlist_dal();
            return sysdal.getoneitem3(tmpkey);
        }
        public int retreccount(string weblogin)
        {
            receivedlist_dal receivelistdal = new receivedlist_dal();
            return receivelistdal.retreccount(weblogin);
        }
        public DataTable getdataset_curentpage(string weblogin, int pageIndex, int pageSize)
        {
            receivedlist_dal rettable = new receivedlist_dal();
            return rettable.getdataset_curentpage(weblogin, pageIndex, pageSize);
        }
        public bool addexpress(string tmpexnum,string tmpexcom,string weblogin)
        {
            receivedlist_dal dal = new receivedlist_dal();
            return dal.addexpress(tmpexnum, tmpexcom,weblogin);
        }
        public bool delorderitem(int itemid)
        {
            receivedlist_dal dal = new receivedlist_dal();
            return dal.delorderitem(itemid);
        }
        public bool updateitem(string cutremark,int itemid)
        {
            receivedlist_dal dal = new receivedlist_dal();
            return dal.updateitem(cutremark,itemid);
        }
        
    }
}
请叫我官人 2014-06-24
  • 打赏
  • 举报
回复
貌似静态的全局变量会发生这种情况~~~~因为我以前也是这样.....本来是A用户下创建的东西 在没有提交的时候 我用B用户登录 然后再提交A用户的那个界面.....不是同一浏览器 然后数据库出现就是B用户的东西了 只因一个Static int Uid......
stephen_deng 2014-06-24
  • 打赏
  • 举报
回复
回复bwangel 连着一个星期访问量少的时候,一个数据都没有混乱,又这难以解释,第二个星期一,访问量突然大了,到星期一晚上我发现出现了两条混乱数据,访问量大的时候才出错,我是可以肯定的,
bwangel 2014-06-24
  • 打赏
  • 举报
回复
日pv18000这个不算是高访问量。问题极有可能出现在本身的业务逻辑的bug.而和并发没关系。你自己都说了操作时间相差两小时。哪有横跨两小时的并发操作? 而且你的数据层方法传入的是sql, 这意味着从业务逻辑传入的也是 sql 语句,这根本没体现出分层的特点。
stephen_deng 2014-06-24
  • 打赏
  • 举报
回复
回复bo1112002: 我的是单服务器,你的是用多情程是多用户的意思吗? 还有 [MethodImpl(MethodImplOptions.Synchronized)]是什么意思?
品铭工作室 2014-06-24
  • 打赏
  • 举报
回复
控制好多个线程下只一个写入实例,并且是只允许同一时间点上只有一个线程访问 如果是多服务器下或多进程下,你做个全局队列了, 参考相关资料
品铭工作室 2014-06-24
  • 打赏
  • 举报
回复
[MethodImpl(MethodImplOptions.Synchronized)] public static int execute_simple(string sql,SqlConnection conn)
stephen_deng 2014-06-24
  • 打赏
  • 举报
回复
访问量小的时候,是没有这情况的
smthgdin_020 2014-06-24
  • 打赏
  • 举报
回复
程序控制不好吧,可能是某种操作下才会出现,正常操作就不会。
为什么区块链必须是高并发的? 1. 摩尔定律早已结束目前,提高并发性是解决人类计算能力的主要方向了。但是并发的编程模型一直受到来自上下两方的压力。2000年开始之际,人们已经意识到摩尔定律失效了。你不太可能期待着今年写的C代码在明年的时候能够被更快的处理器运行了。因为处理器性能的提升主要是通过堆积更多的core来完成。所以为了编写更快的代码,你要做的是编写并发式的程序,同时使用更多的核、更多的CPU、更多的机器。对于并发式的编程模型这就是来自于下方的压力。当今的主流商业应用软件都是跑在web端的,7乘24小时百万级以上的并发访问。人们已经无法想象一个运行在桌面的单机程序实现同样的商业价值。对于编程模型来说,这是来自于上方的压力。所以当我们谈论区块链时,我们需要明白支持并发性才能满足市场的需求。2. 线程模型并不理想线程模型是上世纪90年代提出的并发模型,线程模型广泛应用在Java虚拟机、CLR、.net虚拟机中,甚至应用于Erlang这样更高级的系统。线程模型失败的地方在于如果你在读一段Java或C sharp代码,你无法明白有多少个线程在里面。我们可以讨论并行性和并发性,也可以讨论并发式和分步式,前提是我们必须搞清这几个概念。并行性指同步进行的多项活动之间并不共享信息。就像一条八车道的公路,根本没有换道,那就是并行。当你开始允许换道时,不同的活动和线程之间出现交互,那就是并发。分布式就是把每一笔交易想像成一辆车,换道就是切换到不同的处理器上。分布式必然需要面对故障模式,如果允许单独某个任务失败,就带来了本地(local)的概念。线程有不同的概念,包括有操作系统线程和cpu内核的物理线程等等。我谈论的是虚拟机上提供并发性的编程模型。线程模型的问题是本质上在编程语言的语义层面并没有提供并发性的支持。我用语言集成查询作为一个例子,证明语言集成将最终胜出。语言集成查询开始于微软的函数式编程大牛Eric Meyer。数据存储的两个方法是:1,提供一个支持数据存储的库;2,提供一个查询的语言特性。在第一种情况下,并没有类型系统(type system)帮助你对查询进行语义检查。在后一种情况下,类型系统和编译器参与检查确保查询处于良好状态并且不会中断。在过去的十五年中,语言集成查询已经是最热门的话题之一。所以时间将会证明,语言整合的方法会稳步胜出。回到并发的话题,采用库的方法就是线程模式的思路。在语义层面的扩展就是Rholang、 Pict 或者Vim等移动进程演算(mobile process calculi )的思路。type system保证了你在读一段Rholang程序时,能够看到有多少个进程在进行。同样的,如果你采用 pi calculus 或者 ambient calculus也可以具有同样的优势。3. DAO事件其实是一个并发问题并发性成为一种语法现象。因为它是语法,是可以对代码进行分析并检查各种并发属性的语法。一个非常好的示例是竞争条件(race condition):两个事件是否有可能以任意顺序发生?DAO事件其实是一个并发问题,是竞争条件。如果有对应的语言表示,就可以通过语法分析(也称为静态分析),捕获这些错误。即使是熟悉并发问题的老程序员,仍然会不时地搞错,例如用餐哲学家(dining philosophers)或其他类型的问题,所在为并发编写算法是非常困难的。当我在八十年代末和九十年代初期在Rosette工作时,我注意到即使使用非常强大的编程语言,并发编程也是非常困难的事情。不幸的是编程理论停止了二三十年,市场好像卡住了。我惊诧于Javascript一直统治着浏览器平台。我计划开发一个基于Rholang的浏览器语言,使用Rholang从头编写浏览器。4.现在的区块链都错了大多数交易是孤立不相关的。大多数人的财务状况都是彼此分开的。当你去喝咖啡时,地球另一面的人在买菜,你们的交易不相关,在区块链世界中,这一点非常重要。如果我们必须对这些交易进行系列化,我们就走进了死胡同。所有的交易都必须经过一个虚拟机。如果那个虚拟机是顺序的(sequential),Transaction将不得不按线性排列,这正是以太坊虚拟机的模式。在这种情况下,无论是DAG还是区块,那都无所谓了。在区块链上使用序列化模型时,不可能有语言层面的并发的显式表示。因此无法使用静态分析来获得并发行为,并发都隐藏在幕后。这就像一个干净和纯粹的函数式语言和Java之间的区别。使用与lambda演算接近的函数式语言,你所看到的就是你所获得的。所有执行实际上都在代码中。而对于Java来说,程序中存在着一堆隐藏的状态:堆栈、线程数以及类似的东西都在代码中。 

110,571

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

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