最近在看《企业应用架构模式》,并且思考数据持久层的实现,从而也发现了目前自己项目中持久层的一个漏洞。

一、漏洞

  项目中的数据访问层的实现是这样的,一个数据表对应一个实体(贫血实体,里面只有对应数据库字段的属性),另外加一个数据访问类,这里面封装了类似GetEntity(long id)、Update(Entity entity)、Add(Entity entity)这样的方法。用起来倒是也蛮好用的,但是其实这个里面有个很大的问题:如果在程序中,先用GetEntity方法取得实体,然后修改实体字段,再调用Update(Entity entity)修改数据库,那么这就会有数据同步的问题了。打个比方,一个用户把数据取出来修改了一个属性的值,此时还没有调用Update方法,又有一个用户把这个实体取出来修改了另一个属性,这个时候他们俩都提交了数据,那么会发生什么情况?一定有一个人的操作被另一个人覆盖了。

      说的简单明了一点,就相当于一个多线程的程序对同一份数据的修改完全是在一个没有锁的环境下发生的。当然,在用户量和访问量很小的情况下,发生的概率是很低的,但是这在企业级开发中是绝对不能容忍的,用一个简单的乐观锁也许就能解决这个问题。

二、数据访问机制

     在《企业引用架构模式》中,提到了工作单元的概念,当对数据的进行一系列操作的时候,会把这些修改记录在工作单元中,最后由工作单元负责一次性提交到数据。这种做法的理论根据,当然就是 数据库连接是宝贵的资源,因此在一次与数据库的交互中,完成一系列操作,而不是每次操作都去直接访问数据,这样做还有一个好处就是,比较方便和容易实现事务,一系列操作在一并提交数据库的时候,如果中间有哪一步失败,那么在数据库级别实现回滚。

     但是这样做,在高并发访问的环境下就牺牲了可访问性了,试想当一个用户的一系列操作的工作单元提交数据库时,会锁住数据库相关的表(SQL SERVER应该是锁表的),那么后面的用户线程将会被阻塞,排队的用户多了,那么后面用户的线程将会被牺牲掉。因此对于一个高并发访问的应用,还是应该使用短连接(即对于数据库连接快取快放)来操作,但是短连接又不能保证数据的事务性,这的确一个矛盾的问题,也许这就是开发企业级应用和大型网站的区别吧,各自关注点不同,所以采用不同的数据库访问策略。

 

 

 

posted @ 2009-10-19 23:24 Cheese 阅读(307) 评论(0) 编辑
当我们想把框架底层的异常向上抛时(比如从DAL到BLL),例如下面的代码
try
{
   
//提交数据库
}
catch (System.Data.SqlClient.SqlException ex)
{
   
throw ex;
}
finally
{
   
//释放资源
}
上面代码的的问题在于,会造成CLR重新设置异常抛出的起点,导致我们在查看异常堆栈的时候,无法知道实际抛出异常的最底层的调用。
所以上面的代码应该使用throw关键字来向上抛出异常。




posted @ 2009-09-03 16:41 Cheese 阅读(365) 评论(0) 编辑

按钮点击时出发validate方法:


$("#btnQuery").click(function() {
        $(
"form").validate(validate_settings_query);
});

 

 validate_settings_query这个是validate的option参数,那么实现不同的校验逻辑,实际上就是构造不同的option参数即可:

$(document).ready(function() {
            
var _customer_query = {
                rules: {
                    txtCustEmail: {
                        required: 
true,
                        email: 
true
                    }
                }, 
//end rule
                messages: {
                    txtCustEmail: {
                        required: 
"账号不能为空",
                        email: 
"请录入正确格式的Email地址"
                    }
                }
//end message
            };
                  
            
var _customer_submit = {
                rules: {
                    txtCustAmount: {
                        required: 
true
                    }
                }, 
//end rule
                messages: {
                    txtCustAmount: {
                        required: 
"金额不能为空"
                    }
                }
//end message
            };

            
var validate_settings_query = jQuery.extend({}, _default, _customer_query);
            
var validate_settings_submit = jQuery.extend({}, _default, _customer_submit);
            
            $(
"#btnQuery").click(function() {
                $(
"form").validate(validate_settings_query);
            });

            $(
"#btnSubmit").click(function() {
                $(
"form").validate(validate_settings_submit);
            });
            
        });

 

 

posted @ 2009-04-30 17:33 Cheese 阅读(1130) 评论(4) 编辑

背景:框架结构即普遍的 上-左-右 的结构 leftFrame 是菜单, rightFrame是内容页

跨域问题:本域为x.abc.com菜单里面有挂了另外一个子域y.abc.com的页面,那个子域里面使用了asp.net ajax,生成的脚本里面,要访问top,造成了脚本的跨域访问,于是我在框架页面里面设置了 document.domain = "abc.com" ,在子域的那个页面里面也设置document.domain = "abc.com",跨域的问题就解决了。

新问题:在菜单里面点击了子域的那个页面以后,所有的页面(包括子域的那个页面),都不是在框架的rightFrame里面打开了,而是在新的窗口打开。

新问题的解决:摸索着在leftFrame的页面里面 也加上 document.domain = "abc.com" ,于是问题解决了,所有的页面都在rightFrame里面打开

疑惑:虽然问题解决了,但是觉得还是没理解好修改document的domain

----先记下来,有空研究一下,补上心得。

 

posted @ 2009-04-30 12:39 Cheese 阅读(164) 评论(1) 编辑

     

     eval()这个东东,以前也接触过和用过,但是一直没放在心上去理解。今天偶然发现了一篇文章,才让我恍然大悟,其实eval()就是把一个字符串当做代码来执行的。这也就引出了引文中提到的问题:eval() 如果不善用的话,会给自己的程序带来很大的问题,  

 

-------引文原文如下:---------------------------

 

       Simon Willison 认为:虽然Javascript提供了把动态字符串作为脚本代码来执行的 eval() 函数,为代码的编写提供了很多的便利,但同时也导致了代码执行效率的低下以及难以维护。通常来说,只有设计存在缺陷才会不得不用 eval() 来弥补这些缺陷。

 

     对于 eval() 的使用最常见的错误是用来动态获取某个对象/子对象及其属性。假设你的代码中有一个对象foo,其属性将在运行时被决定。你可能会想用eval来解决这个问题:

 

1.       var property = 'bar';   

2.         

3.       var value = eval('foo.' + property);   

4.         

     

     这样做固然可以达到预期的效果,但这会导致JavaScript每次运行这段代码的时候都切换到解释器模式来重新解释这段动态构建的代码,其运行效率大大降低。实际上以上情况你可以完全回避使用eval()

 

1.       var property = 'bar';   

2.         

3.       var value = foo[property];   

4.         

 

     另一方面,使用 eval() 也可能会导致一些潜在的安全隐患。这一点对于任何语言来说都是如此。当你通过页面的GET/POST参数来获取数据并 eval() 之的时候,就有可能被恶意用户利用来注入非法代码进行非预期的操作。所以,无论是从执行效率、代码维护成本还是应用安全性角度考虑,对于 eval() 的使用都必须谨慎。回想自己曾经写过的那些代码,有段时间里面 eval() 简直被我给用滥了 -- 最直接的后果就是给接手的其他程序员造成了不小的麻烦。要弄懂一段动态组合出来的字符串到底被 eval() 之后是用来干什么的的确不像结构清晰的OO代码那么容易。

难怪有人认为 eval() 应该被完全从编程语言中被清理出去,因为 eval() 意味着 B.A.D. -- Broken As Designed 。这个情形有点像 goto 关键字。不知道有多少人对 goto 深恶痛绝,也不知道 goto 导致了多少代码的崩溃。但不可否认,仍然有很多精彩的 goto 使用范例。只要用在合适的地方, eval() 同样可以是不二的解决方案。比如Ajax中用来执行XMLHttpRequest得到的服务器端响应:

 

1.       function evalRequest(url) {   

2.         

3.           var xmlhttp = new XMLHttpRequest();   

4.         

5.           xmlhttp.onreadystatechange = function() {   

6.         

7.               if (xmlhttp.readyState==4 && xmlhttp.status==200) {   

8.         

9.                   eval(xmlhttp.responseText);   

10.     

11.           }   

12.    

13.       }   

14.     

15.       xmlhttp.open("GET", url, true);   

16.     

17.       xmlhttp.send(null);   

18.     

19.   }  

 

      原文链接:http://www.zeali.net/entry/266

 

posted @ 2009-02-18 12:15 Cheese 阅读(199) 评论(0) 编辑

看到标题,相信很多有经验的开发人员,已经猜到是什么问题了。

写在这里是希望给后来人一个提醒,并且也提醒自己应该如何正确的去认识任何一个数据类型。

言归正传,用 " somedate <= 2009-1-1 23:59.59.999 " 作为查询条件,最终的结果是

会把 somedate = 2009-1-2 00:00.00.000 的记录一起查出来。

为什么呢?答案在联机丛书中一句不起眼的话:

“日期和时间数据,从 1753 年 1 月 1 日到 9999 年 12 月 31 日,准确度为三百分之一秒或 3.33 毫秒。值被圆整到 .000、.003 或 .007 毫秒增量。”

也就是说,我们使用datetime时,可以用到1毫秒级别,但是Sql Server看到的只精确到3.33毫秒。

深层的原因有待研究,也许哪位大虾可帮忙解释一下。

本人推荐的用法是 : somedate < 2009-1-2 00:00.00.000  这样能够正确的表达这句过滤条件的真正目的吧。

 

posted @ 2009-01-06 14:50 Cheese 阅读(112) 评论(0) 编辑
摘要: 使用.NET做开发三年多了,还以为自己的.NET基本功很扎实,谁知一个简单的读程序我却做错了…… 教训是:常常你自己觉得你了解的很清楚了,但其实那是一种思维定势,也许你根本就没真正了解。这种不求甚解的学习,是计算机技术最最要不得的。言归正传,代码清单如下:[代码]我就不卖关子了,这段代码的输出是: true true false true 。下面解释一下结果,其实就是操作符...阅读全文
posted @ 2008-09-12 23:18 Cheese 阅读(209) 评论(1) 编辑