50个客户端对Sql Server根本不成问题
应该是用了悲观锁的问题吧把你提交sql语句的代码贴出来看看吧包括你的测试语句,和实际程序中的语句

解决方案 »

  1.   

    这个问题还是挺好玩的首先能否让我对你的软件架构先做一个假设?
    假定能,我建议你采用三层结构。测试语句例如 Insert into a(col1,col2)value(var1,var2);
    for (int i=0; i < 20000;i++)
    {
        数据库连接请求 
        事物处理语句块
        完成后,关闭数据库连接
    }能否把这个“事物处理语句块”去掉?换成中间层来处理
    前台只是调用中间层的接口程序,事务在中间层启动,
    去除“数据库连接请求”
    去除“完成后,关闭数据库连接”
    针对抢劫问题,建议中间层采用回调函数往客户端发送已经被抢了的记录的标示和新增的记录的标示回调函数:
      回调函数是一个很有用,也很重要的概念。当发生某种事件时,系统或其他函数将会自动调用你定义的一段函数。回调函数在windows编程使用的场合很多,比如Hook回调函数:MouseProc,GetMsgProc以及EnumWindows,DrawState的回调函数等等,还有很多系统级的回调过程。本文不准备介绍这些函数和过程,而是谈谈实现自己的回调函数的一些经验。   之所以产生使用回调函数这个想法,是因为现在使用VC和Delphi混合编程,用VC写的一个DLL程序进行一些时间比较长的异步工作,工作完成之后,需要通知使用DLL的应用程序:某些事件已经完成,请处理事件的后续部分。开始想过使用同步对象,文件影射,消息等实现DLL函数到应用程序的通知,后来突然想到可不可以在应用程序端先写一个函数,等需要处理后续事宜的时候,在DLL里直接调用这个函数即可。于是就动手,写了个回调函数的原形。在VC和Delphi里都进行了测试。 http://www.legalsoft.com.cn/Articles/ArticleBrowse.asp?idArticle=369关于回调函数,你可以在Google上搜索,还有好多更详细的解释
      

  2.   

    我知道50客户端对sql来说应该没有什么问题,但是同一时刻并发50个用户就不行了,原来我们也以为没有问题,但是测试下来结果让我们大为失望,不知道是我们的代码有问题,还是本身sql有问题,或者服务器性能不够好(服务器型号:Dell2600),程序中没有锁,明天早上我会补帖代码
      

  3.   

    其实没有必要每次连接数据库和关闭数据库,这样纯粹耗费SQL服务器资源
      

  4.   

    每次关闭数据库连接是因为我们想模拟用户一次完整的操作,因为在程序中,用户是单独操作的,只是同时使用的用户比较多而已。cnming老大,能不能提供一个用了回调函数的三层结构程序的样码呢?网上对于三层结构的样码很少,使用三层结构的就更加少了。我的电子邮件:[email protected],谢谢!
      

  5.   

    http://msdn.microsoft.com/library/chs/default.asp?url=/library/CHS/cpguide/html/cpconUsingCallbackFunctions.asp还没有细看,感觉好像很简单,你自己看看
      

  6.   

    cnming老大,我之所以会在程序中操作数据完成后关闭连接主要基于两点:第一:记得一次我去微软咨询问题,那个外国老大特意提醒我,叫我每次数据操作完成后断开,说这样可以提高服务器资源的利用率(未经考证,如果你有更加明确的答案可以告诉我)。第二:程序中需要操作数据的地方太多,很多操作的前提就是必须要我先把数据库链接关闭,所以我不但在操作数据库完成后关闭链接,很多时候在链接前,我要先执行关闭数据库连接的命令,这点我也没有搞懂为什么有些数据库操作在ado.net里面没有被关闭干净(即使使数据操作成功的情况下)。希望老大指正!谢谢
      

  7.   

    Introduction to Data Concurrency in ADO.NET:
    http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vbcon/html/vbtskPerformingOptimisticConcurrencyChecking.aspHandling Data Concurrency Using ADO.NET:
    http://msdn.microsoft.com/msdnmag/issues/04/09/datapoints/
      

  8.   

    http://msdn.microsoft.com/library/chs/default.asp?url=/library/CHS/vbcon/html/vbtskPerformingOptimisticConcurrencyChecking.asp
      

  9.   

    >>第一:记得一次我去微软咨询问题,那个外国老大特意提醒我,叫我每次数据操作完成后断开,说这样可以提高服务器资源的利用率(未经考证,如果你有更加明确的答案可以告诉我)。第二:程序中需要操作数据的地方太多,很多操作的前提就是必须要我先把数据库链接关闭,所以我不但在操作数据库完成后关闭链接,很多时候在链接前,我要先执行关闭数据库连接的命令,这点我也没有搞懂为什么有些数据库操作在ado.net里面没有被关闭干净(即使使数据操作成功的情况下)。希望老大指正!
    SQL中的连接使用缓冲池,假使真的有的操作非要关闭这个连接,你也完全可以在你运行
    for (int i=0; i < 20000;i++)
    {
        数据库连接请求 
        事物处理语句块
        完成后,关闭数据库连接
    }
    的时候不去关闭数据库连接,因为这时候根本没有时间去动作其他的数据库操作其次,你可以把你说的非要重新连接的地方贴出来,我到现在根本没有遇到
    还有,只要连接的缓冲不超过SQL的极限,不存在要关闭连接的需要。另外,你的这个连接在你的程序中可以是全局的,无须到处申明连接。采用回调函数是解决你的问题的一种方法,因为它可以主动通知你的客户端,而无须客户端主动查询。
      

  10.   

    关于我数据库连接的简单处理过程
    首先,我会调用函数,从注册表中取出数据库链接字符串
    public string sGetPMConn()
    {
    string sDBServer = "";  // 服务器名
    string sDBName = ""; // 数据库名
    string sLoginname = ""; // 登录名
    string sLoginpassword = ""; //登录密码
    string sFullConn = "";
    RegistryKey hklm = Registry.LocalMachine;
    RegistryKey Practechkey = hklm.OpenSubKey("software\\practech",true);
    sDBServer = (string)Practechkey.GetValue("DBServername");
    sDBName = (string)Practechkey.GetValue("Databasename");
    sLoginname = (string)Practechkey.GetValue("Loginname");
    sLoginpassword = (string)Practechkey.GetValue("Password");
    sFullConn = "data source="+sDBServer+";initial catalog="+sDBName+";persist security info=False;user id="+sLoginname+";password="+sLoginpassword+";workstation id=KWAHSERVER2;packet size=4096";  //数据库连接串组合 return sFullConn; 
    }程序中的调用
    string sConn = PMCon.sGetPMConn(); // 数据库连接
    SqlConnection PMConnection = new SqlConnection(sConn); //创建公用的数据库连接
    if(_iRun != 1)
    {
    SqlCommand PMCommand = new SqlCommand(sAppendUser,PMConnection);
    try
    {
    PMConnection.Open();
    PMCommand.ExecuteNonQuery();
    Form1.panel1.DrawColor = 3;// 个性化状态栏--颜色
    Form1.panel1.Text = "Successfully!"; // 个性化状态栏--文字
    this.Close();
    }
    catch(Exception E_SQLERROR)
    {
               er.vWrLog(E_SQLERROR,er.ErrorMsg,1);// 日志处理
              }
             finally
    {
        PMConnection.Close();
    }
    }cnming老大,如果你对我这种写法有什么建议,请尽管提出来,非常高兴认识你。我要关闭数据库连接往往发生在最最普通的地方,也是你意想不到的地方,听你这么一说,我倒觉得确实是我的程序写的有问题。老大能不能给一个简历全局数据库连接的例子呢?谢谢!
      

  11.   

    不要满口的老大,我也只是一个菜鸟,不经常写代码,看到你这个寻求解决方案的就比较感兴趣全局的莫过于加一个staticpublic class ClassSQLServerWrapper
    {
        public static System.Data.SqlClient.SqlConnection PMConnection = null;
    }调用时使用ClassSQLServerWrapper.PMConnection 即可获得这个连接,无论你在哪里打开这个连接全局都通用我认为数据库连接无须每次更换,除非你有不同的数据库用户,而且每一个数据库用户有不同的权限,如果是这样,你就需要建立不同的连接
      

  12.   

    战友,这个全局的static 在哪里进行加载呢?
    还有,我觉得并发的问题仍然没有得到解决。今天晚上或者明天我会改写那个测试的自动机,争取模拟程序在数据发生碰撞时的数据库状态。
      

  13.   

    这个全局的static 在程序刚启动的时候就可以加载进行加载,在你第一次运行之前必须加载
      

  14.   

    多半是一致性问题用乐观一致性问题就不会在connect到disconnect都锁住
    你肯定是用了悲观一致性
      

  15.   

    个人几点建议:1.连接字符串可以一次取出后存在static string里,调用函数及访问注册表皆耗费大量系统资源;2.在Connection打开时,最好不要做非在连接时间做不可的事,以尽早释放连接.3.建议写成 打开连接->开始事务->执行全部任务(如循环)->提交事务->关闭连接.4.要做到解决数据冲突,要用锁定,越安全的锁定越耗资源;要做到确保操作单位是N条Sql语句,要用事务.5.我认为Sql Server在执行事务时,会锁定它所操作的相关表,直到事务提交后别的任务才能执行.所以这段时间,别的任务都在排队等候,看上去像死机.   另外,我觉得cnming的单一静态连接有点问题.如在上面执行了ExcuteDataReader之类不会立即释放连接的操作,其它的任务可能得不到及时执行或出错.正确的做法是做一个连接池.基本思路是将正在用的连接放在使用队列,不用时放到闲置队列.每次取连接都先看闲置队列是否有连接可用,没有再开始创建新连接.这样也可以限制连接数.ADO.NET里面是自带连接池管理的,默认有100连接可用,当你用Close关闭连接时,它只是被返回到池中.下次Open(同样的连接字符串)时又取出来.  不当之处,敬请指正.
      

  16.   

    cnming,你成功实现了把数据库连接放在static中的操作嘛?我尝试了好几次都失败了,关键不知道放在static里面怎么调用,给我点完整的代码好吗?LinFengCyl(林风) :我觉得你在处理数据库连接时候的思路其实是和我一样的,关键我这里更多的考虑是并发性的问题。能不能详细描述一下你所说的关于excutedatareader的问题(最好有典型代码)thantii(李博) 我觉得这不是悲观一致性的问题,而是如果这个问题无法测试通过,那么产品就无法提交给客户。
      

  17.   

    //其实没有必要每次连接数据库和关闭数据库,这样纯粹耗费SQL服务器资源我是严重的同意啊.不过要知道使用了连接池以后,你‘关闭’了连接,实际上并没有断开。如果你从tcp/ip层面断开断开连接,却是是增加负担(对于你过阵子又要使用,又要去连接的情况)。btw,‘顶’,‘学习’之类的词语就不要出现了嘛。如何?
      

  18.   

    看了一下你的代码
    Form1.panel1.DrawColor = 3;// 个性化状态栏--颜色
    Form1.panel1.Text = "Successfully!"; // 个性化状态栏--文字
    this.Close();//??关闭窗口,那finally还执行吗?
      

  19.   

    建议
    1,如果不是3层架够(即普通的c/s)如果使用连接后不关闭连接,这样对减轻server负担用处不大,同时对网络资源和客户端资源会有一定量的消耗!
    2,采用三曾架够,单独开发客户端程序中存取数据等操作剔除了连接数据库等繁杂的工作,对于中间业务逻辑层来说,不会有这种暴力测试的处理过程:for (int i=0; i < 20000;i++)
    {
        数据库连接请求 
        事物处理语句块
        完成后,关闭数据库连接
    }存在,最多会这样:数据库连接请求 
    事物处理开启
    for (int i=0; i < 需要发送的sql语句列表,不一定会连续执行某一客户端要求改变的所有语句,可能插入别的客户端提交的sql语句;i++)
    {
        执行
    }
    提交事物
    关闭数据库连接,可不关闭
      

  20.   

    Form1.panel1.DrawColor = 3;// 个性化状态栏--颜色
    Form1.panel1.Text = "Successfully!"; // 个性化状态栏--文字
    this.Close();//??关闭窗口,那finally还执行吗?finally肯定要执行的
      

  21.   

    问个不相干的问题:
    --------------------------------------------------
    Form1.panel1.DrawColor = 3;// 个性化状态栏--颜色
    --------------------------------------------------
    我这里怎么没有这个属性啊?
      

  22.   

    To BearBaBa:
    1.我提些不相干的建议只是希望你能有好的编码规范,因为习惯是平时养成的.你测试时也可以暂时注释掉不相关的代码,这样越有对比性,也越易找到问题所在(恕我多言:));
    2.关于ExcuteDataReader()和ExcuteXmlReader()之类的是因为它们都不能以连接自动关闭方式执行,所以最容易出现交叉使用连接的情况,这样会引发错误.要在程序中保证一个连接在做完一件事前不做另一件事是很难的.简单示例:
    //connection为已打开的连接
    SqlDataReader reader=connection.ExcuteDataReader();
    connection.ExcuteNonQuery();//在DataReader关闭前执行该方法将引起错误.
    reader.Close();
    所以我建议做一个数据访问层或干脆像O/R Mapping,将具体的数据库存取细节封装起来.
    3.我也在想你这种测试究竟是不是合理,因为我没有软件测试经验,所以不敢妄下评论.你测出来的结果是20台机器一台一台执行,不会交叉,那是不是涉及到计算机之间的通信及操作系统及Sql Server的问题而不会是你这里的代码问题.
    我也希望知道结果:)
      

  23.   

    我想说的是,客户的插入操作是不是和下面这个一样快?
    for (int i=0; i < 20000;i++)
    {
        数据库连接请求 
        事物处理语句块
        完成后,关闭数据库连接
    }
    且不说50个客户,5000个客户也达不到这种速度吧。
    我认为你的测试方式有问题。
      

  24.   

    To z9945() :那个panel是我自绘的控件To LinFengCyl(林风):原本我想测试的目的就是模拟同一时刻有50台以上的客户机同时想MS SQL发出数据处理请求,但是我现在碰到的问题是同时只有2台机器发出请求就会死机。我不清楚是我代码的问题还是MS SQL的问题。To Everyone: 我找到微软的关于三层结构的代码,但是我没有看明白为什么加了一个中间层或者说是数据层,在数据处理的时候就可以不需要打开数据库连接的问题。还有谁有三层结构的应用程序代码,我手上的是.net PetShop的代码。
      

  25.   

    你仔细地讲讲你测试的软硬件环境/测试的过程以及代码的结构(伪代码就可以了).我是觉得你这种测试有问题.不用说操作数据库,你让50个循环2000次的东东跑一下都可以累晕机器的.
    访问数据库我觉得这本书可以翻翻<<数据访问模式>>.
      

  26.   

    To LinFengCyl(林风):我这次测试的思路是这样的。
    测试内容:用户连续执行20000次完整一次插入操作。看看是否有编码错误。同时测试所写的代码能否支持50人同时做插入操作的情况。
    测试过程:有50台计算机(P4 2.4G 256MB)同时执行一个含有完整插入操作程序的循环,不断的向数据库添加数据。我个人认为:某个用户点击按钮一次完成插入操作,那么如果让机器自己做只要做一个循环就可以了。50个用户的插入操作就是由50台装有这种程序的机器自动执行。
    测试问题:目前是20台上线测试,前5台机器还能构获得响应,但是只有第一台机器能够执行插入操作。我觉得这个问题可能出在我在一次插入操作完成后并没有停止,而是立刻产生第二次插入操作,所以别的机器只能请求服务器响应,但是服务器无能为力提供服务。To Everyone: 希望大家加入一起讨论!我今天还会在做一个插入操作的版本。
      

  27.   

    你的服务器是什么配置?你的服务器运行状况如何?另外,for循环的循环速度很快,如果能满足你的一台机器的一个For循环,少说也可以满足100个以上的在线用户了还有,你的测试代码是如何写的,也就是for循环里头的,是否有每次都从服务器上取回所有的数据的记录?如果有,请问你的数据记录有多少?假使你真的要重新连接数据库和关闭数据库连接,你也没有必要再for循环体内打开和关闭。
       数据库连接请求 
    for (int i=0; i < 20000;i++)
    {
         事物处理语句块
    }
    完成后,关闭数据库连接,因此针对单用户来说,不存在这么快速频繁地打开和关闭数据库连接
    还有,我认为这个问题已经没有什么可以再探讨的了。
      

  28.   

    我已经最终决定采用WinForm and WebForm + Webservice + SQLServer的结构开发了。