执行数据操作时,由于拼接SQL存在种种弊端,早就应该抛弃了,但在现实开发时,又由于种种原因,公司一直采用这种方式(UI层和逻辑层都有严格的过滤,倒也没出现过什么问题),但昨天开发时却出现了意想不到的问题,一个简单的语句会造成严重后果。简单的语句示例如下:

更新主键为2的记录的总钱数的方法
    /// <summary>
    
/// 更新主键为2的记录的总钱数
    
/// </summary>
    
/// <param name="totalMoney">修改后的总钱数</param>
    public void UpdateTotalMoney(int totalMoney)
    {
        
int id = 2//数据库表主键
        int oldTotalMoney = 5000;       //主键为2的记录原来的总钱数
        int newTotalMoney = totalMoney; //主键为2的记录更改后的钱数
        int totalMoneyChange = oldTotalMoney - newTotalMoney; //总钱数的变化量
        string sql = string.Format("update Test1220 set totalMoney = {0},remainMoney = remainMoney-{1} where id = {2}", newTotalMoney, totalMoneyChange, id);   //总钱数变化,剩余可支配钱数也跟着编号
        SqlConnection con = new SqlConnection(sqlConnectString);
        con.Open();
        SqlCommand cmd 
= new SqlCommand(sql, con);
        cmd.ExecuteNonQuery();
        con.Close();
    }

创建表并插入测试数据
    CREATE TABLE Test1220(
        id 
int IDENTITY(1,1NOT NULL PRIMARY KEY,
        totalMoney 
int NULL,
        remainMoney 
int NULL
    )

    
insert into Test1220(totalMoney,remainMoney) values(3000,2000)
    
insert into Test1220(totalMoney,remainMoney) values(5000,5000)
    
insert into Test1220(totalMoney,remainMoney) values(1000,1000)
    
insert into Test1220(totalMoney,remainMoney) values(3000,3000)
    
insert into Test1220(totalMoney,remainMoney) values(3000,3000)
    
insert into Test1220(totalMoney,remainMoney) values(3000,3000)

 
      接下来调用方法UpdateTotalMoney()更新主键为2的记录的总钱数和剩余钱数,UpdateTotalMoney(4000)和UpdateTotalMoney(8000)更新id=2的记录,会发生什么情况呢?执行UpdateTotalMoney(4000)时正常,表中只有id=2的记录跟着更新;但执行完UpdateTotalMoney(8000)之后,却出现了意想不到的问题,所有记录的totalMoney都变成8000了,而remainMoney却一个也没有修改。是什么原因造成的呢?明明已经加了where条件id=2,怎么会更新到所有记录?

      这可把我这个菜鸟级的给难住了,简单的语句,传递不同的参数会有时正常有时异常,反复跟踪调试,才发现问题出现在SQL语句上,当参数为8000时,得到的SQL语句为“update Test1220 set totalMoney = 8000,remainMoney = remainMoney--3000 where id = 2”,原来是减运算符和负号连在一起成了SQL的注释符号,把更新时的where条件给注释掉了,真是一个危险的操作!这个错误很隐蔽,查找错误花了很长时间,如果执行数据库操作时参数化,就不会有这种情况了。

posted @ 2009-12-20 12:19 陈晨 阅读(250) | 评论(1) |  编辑

       在.NET中使用OpenFlashChart控件显示图表时,谁会想到图表显示正常与否竟然和服务器IIS是否启用了Gzip压缩有关呢?

       两个站点用着同一套程序,一个站点OpenFlashChart图表能正常显示,另一个站点却显示为“ioerror Error #2032”,而且这个问题只出现在IE6浏览器中,火狐和IE7中都能正常显示,是什么原因造成的呢?

       OpenFlashChart      OpenFlashChart 

     百度和Google一番,才查到原因是服务器上采用了Gzip压缩优化网站和no-cache同时出现造成的,解决方法是在返回的页面里增加HTTP头,示例代码如下:

解决代码示例

 

       修改之后,在IE6下OpenFlashChart图表终于正常显示出来了。

posted @ 2009-06-18 23:04 陈晨 阅读(245) | 评论(2) |  编辑
     摘要: 又一次站在十字路口,面对漫漫程序人生,不清楚下一步该走向何方,朋友的建议不能替代自己的选择,靴子未落地的日子难熬。  阅读全文
posted @ 2008-10-23 00:35 陈晨 阅读(193) | 评论(3) |  编辑
     摘要: 作为一个普通的开发人员,写程序时一定要细心再细心,尤其是在关键的流程控制语句,一点点的疏忽损失都是巨大的。  阅读全文
posted @ 2008-09-19 08:12 陈晨 阅读(274) | 评论(4) |  编辑
     摘要: ASP.NET项目中经常会遇到这样的情况:页面提交后需要很长的处理时间,用户耐心受到挑战就开始摧残页面上的提交按钮,造成了该页面重复提交多次,带来意想不到的问题。在项目实践中,采用了一种比较简单的方式解决这种问题:用户点击提交按钮后,通过JavaScript脚本将提交按钮disable掉,同时显示动画提示用户系统正在处理,并触发服务器端事件。  阅读全文
posted @ 2008-09-11 00:25 陈晨 阅读(1285) | 评论(7) |  编辑
     摘要: 正则表达式可以看做一种有特定功能的小型编程语言,它很重要的一个应用就是在文本中提取字符串,这一功能的实现主要是靠Match类和Group类,因此理解匹配和组的概念至关重要。  阅读全文
posted @ 2008-08-30 14:02 陈晨 阅读(1693) | 评论(0) |  编辑
     摘要: 使用.NET我们可以很容易的创建一个线程,但是它提供的创建线程和启动线程的方法没有明显的提供参数,假如我们要用线程来启动类里面一个带参数的方法该怎么办?本文重要介绍三种方法:1.利用类的构造函数,2.用ThreadPool类,3.利用ParameterizedThreadStart委托实例化Thread类。  阅读全文
posted @ 2008-08-28 23:38 陈晨 阅读(1322) | 评论(2) |  编辑
     摘要: VB.NET中除运算符有两种,普通除"/"和整数除"\",如果我们写程序时不注意两者的区别,很容易造成潜在的错误,这种错误很隐蔽,不容易被发现。而且VB.NET中类型转换和C#差别很大,应该引起我们足够的重视,这些看似微不足道的细节却直接关系都我们代码的健壮性。  阅读全文
posted @ 2008-08-27 00:06 陈晨 阅读(903) | 评论(0) |  编辑
     摘要: Insert是T-sql中常用语句,Insert INTO table(field1,field2,...) values(value1,value2,...)这种形式的在应用程序开发中必不可少。但我们在开发、测试过程中,经常会遇到需要表复制的情况,如将一个table1的数据的部分字段复制到table2中,或者将整个table1复制到table2中,这时候我们就要使用SELECT INTO 和 INSERT INTO SELECT 表复制语句了。  阅读全文
posted @ 2008-08-15 08:24 陈晨 阅读(35875) | 评论(7) |  编辑
     摘要: Update是T-sql中再简单不过的语句了,update table set column=expression [where condition],我们都会用到。但update的用法不仅于此,真正在开发的时候,灵活恰当地使用update可以达到事半功倍的效果。  阅读全文
posted @ 2008-08-13 23:37 陈晨 阅读(1415) | 评论(4) |  编辑
     摘要: 在对线程同步机制lock,Monitor,同步事件EventWaitHandler,互斥体Mutex的基本用法有了一定了解的基础上,我们对它们用法进行比较,并给出什么时候需要锁什么时候不需要的几点建议。最后,介绍几个FCL中线程安全的类,集合类的锁定方式等,做为对线程同步系列的补充。   阅读全文
posted @ 2008-08-07 00:10 陈晨 阅读(1686) | 评论(0) |  编辑
     摘要: 抛开.NET环境看线程同步,无非是执行两种操作:一是互斥/加锁,目的是保证临界区代码操作的“原子性”;另一种是信号灯操作,目的是保证多个线程按照一定顺序执行,如生产者线程要先于消费者线程执行。本篇继续介绍WaitHandler类及其子类Mutex,ManualResetEvent,AutoResetEvent的用法。  阅读全文
posted @ 2008-07-30 01:08 陈晨 阅读(1189) | 评论(0) |  编辑
     摘要: 本文从Monitor,Mutex,ManualResetEvent,AutoResetEvent,WaitHandler的类关系图开始,希望通过本篇的介绍能对常见的线程同步方法有一个整体的认识,而对每种方式的使用细节,适用场合不会过多解释。  阅读全文
posted @ 2008-07-29 22:08 陈晨 阅读(1795) | 评论(4) |  编辑
     摘要: 1.委托的含义:(MSDN)A delegate declaration defines a reference type that can be used to encapsulate a method with a specific signature.Adelegate instance encapsulates a static or an instance method.Delegate...  阅读全文
posted @ 2008-07-17 21:40 陈晨 阅读(615) | 评论(5) |  编辑
     摘要: .NET中Cache有两种调用方式:HttpContext.Current.Cache 和 HttpRuntime.Cache,这两种方式有什么区别呢?我们先看MSDN上的解释: HttpContext.Current.Cache:为当前 HTTP 请求获取Cache对象。 HttpRuntime.Cache:获取当前应用程序的Cache。   阅读全文
posted @ 2008-07-15 23:47 陈晨 阅读(1865) | 评论(3) |  编辑