[转载]浅谈大型网站的算法和架构(一) – 川山甲 – 博客园.
上个月老大给我们讲解了”浅谈大型网站的算法和架构”,获益匪浅。由于篇幅太多(光数据结构大概就有20多种),我也没有办法一下全部吸收,故我边理解,边分章节与大家分享。



2.找7到20之间的数,你的思路是什么?
无怪乎以下两点:
1》冒泡排序
2》二分查找快

3.C代码实现

执行结果


数组问题:插入太慢,得挪数据。
请看下面的代码,


执行结果

代码结构


链表的特点是插入快,查找慢。

实现方式




[转载]浅谈大型网站的算法和架构(一) – 川山甲 – 博客园.



2.找7到20之间的数,你的思路是什么?
无怪乎以下两点:
1》冒泡排序
2》二分查找快

3.C代码实现

执行结果


数组问题:插入太慢,得挪数据。
请看下面的代码,


执行结果

代码结构


链表的特点是插入快,查找慢。

实现方式




[转载]Asp.net mvc全球化实例 – Lordbaby – 博客园.
通过MVC的路由机制来实现对当前线程的区域性来设定,然后重定向请求页面来实现对已绑定数据的语言之间的切换,例如中文zh-CN,英文en-US
实例只针对注册页面进行多语言话,在资源文件通过键值来定义语言,2个资源文件公用一个类。通常在开发时,只要一个默认的 Resource.resx,当开发完成之后,拷贝一个相同的Resource.resx,并改名字成上面的样子,然后手动或自动将其中的所有value 都翻译成对应的语言。
然后是核心的类
LocalizationHelpers的主要代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Resources;
using System.Web;
using System.Web.Mvc;
using System.Web.WebPages;
using System.Threading;
using Language;
using System.Collections;
using System.Runtime.Caching;
namespace MvcApp.Extensions
{
public static class LocalizationHelpers
{
public static readonly ResourceManager recourseManager = new ResourceManager(typeof(Resource));
public static IHtmlString MetaAcceptLanguage<T>(this HtmlHelper<T> html)
{
var acceptLanguage = HttpUtility.HtmlAttributeEncode(System.Threading.Thread.CurrentThread.CurrentUICulture.ToString());
return new HtmlString(String.Format("<meta name='accept-language' content='{0}'>", acceptLanguage));
}
/// <summary>
/// 本地化获取资源值方法,用于web页面
/// </summary>
/// <param name="htmlhelper"></param>
/// <param name="key"></param>
/// <returns></returns>
public static string Lang(this HtmlHelper htmlhelper, string key)
{
return Lang(htmlhelper.ViewDataContainer as WebViewPage, key);
}
/// <summary>
/// 本地化获取资源值方法,用于web页面
/// </summary>
/// <param name="page"></param>
/// <param name="key"></param>
/// <returns></returns>
public static string Lang(this WebPageBase page, string key)
{
try
{
string cultureName = null;
if (page.Session["Culture"] != null)
{
cultureName = Thread.CurrentThread.CurrentCulture.Name;
}
else
{
//默认设置为中文
cultureName = "zh-CN";
Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo(cultureName);
Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture;
page.Session["Culture"] = Thread.CurrentThread.CurrentCulture;
}
IEnumerable<DictionaryEntry> resxs = null;
resxs = GetResx(cultureName);
return (string)resxs.FirstOrDefault<DictionaryEntry>(x => x.Key.ToString() == key).Value;
}
catch
{
return "?";
}
}
/// <summary>
/// 当前web环境线程中,获取资源键值
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public static string Toi18nString(string key)
{
IEnumerable<DictionaryEntry> resxs = null;
resxs = GetResx(System.Threading.Thread.CurrentThread.CurrentUICulture.Name);
return (string)resxs.FirstOrDefault<DictionaryEntry>(x => x.Key.ToString() == key).Value;
}
/// <summary>
/// 当前web环境线程中,获取资源视图
/// </summary>
/// <param name="resxKey"></param>
/// <returns></returns>
private static IEnumerable<DictionaryEntry> GetResx(string resxKey)
{
ObjectCache cache = MemoryCache.Default;
IEnumerable<DictionaryEntry> resxs = null;
if (cache.Contains(resxKey))
{
resxs = cache.GetCacheItem(resxKey).Value as IEnumerable<DictionaryEntry>;
}
else
{
ResourceManager resource =new ResourceManager(typeof(Resource));
var resourceSet = resource.GetResourceSet(
Thread.CurrentThread.CurrentUICulture,
true,
true);
if (resourceSet != null)
{
resxs = resourceSet.Cast<DictionaryEntry>();
cache.Add(resxKey, resxs, new CacheItemPolicy() { Priority = CacheItemPriority.NotRemovable });
}
}
return resxs;
}
}
}
然后是重写DisplayName特性
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Web;
namespace MvcApp.Extensions
{
public class LocalizedDisplayNameAttribute : DisplayNameAttribute
{
public LocalizedDisplayNameAttribute(string resourceKey)
{
ResourceKey = resourceKey;
}
public override string DisplayName
{
get
{
string displayName = LocalizationHelpers.Toi18nString(ResourceKey);//MyResource.ResourceManager.GetString(ResourceKey);
return string.IsNullOrEmpty(displayName)
? string.Format("[[{0}]]", ResourceKey)
: displayName;
}
}
private string ResourceKey { get; set; }
}
}
在model层所需要实现多语言的字段带个帽子
public class RegisterModel
{
[Required]
[LocalizedDisplayName("UserName")]
public string UserName { get; set; }
[Required]
[DataType(DataType.EmailAddress)]
[LocalizedDisplayName("EmailAddress")]
public string Email { get; set; }
[Required]
[StringLength(100, ErrorMessageResourceType = typeof(Resource), ErrorMessageResourceName = "passwordlength", MinimumLength = 6)]
[DataType(DataType.Password)]
[LocalizedDisplayName("Password")]
public string Password { get; set; }
[DataType(DataType.Password)]
[LocalizedDisplayName("confirmPwd")]
[System.Web.Mvc.Compare("Password", ErrorMessageResourceType = typeof(Resource), ErrorMessageResourceName = "comparepassword")]
public string ConfirmPassword { get; set; }
}
如果是必须字段可以通过ErrorMessageResourceType和ErrorMessageResourceName来自定义语言,也可以通过微软自带的JQuery的验证也实现了多语言。
语言之间的切换是通过改变区域性的Controller来实现的
public class EnglishController : Controller
{
//
// GET: /English/
public ActionResult Index()
{
System.Globalization.CultureInfo englishCulture = new System.Globalization.CultureInfo("en-US");
Session["Culture"] = englishCulture;
return this.Redirect(this.Request.UrlReferrer.ToString());
}
}
以前只是了解MVC这个东东,项目中用到了现在打算开始学习一下MVC,就从微软现成的学起吧,上面的例子只是实现了功能。
我所要介绍的这几本书都是国内作者出的,没办法!主要是英语太挫,英语阻挡了我阅读国外作品的道路。刚入测 试就有幸接触性能测试,jmeter和loadrunner也属于瞎倒腾着在项目中用过。今年换了工作彻底断绝了我倒腾这些工具的权利。给自己想了想后 路,白盒、自动化、性能,综合考虑了一下,自己对性能测试最感兴趣,也是比较有基础,既然没了工具练手。那只能看书了。也算是打一下基础,对整个性能测试 有更好更深入的认识。
精通软件性能测试与LoadRunner实战

《精通软件性能测试与LoadRunner实战》这是我买的第一本性能测试书,这本书讲解的性能测试的理论知识甚少,甚至性能测试的流程神马的跟本么有。当然,这本书的定位就是技巧工具书。所以,我买回来之后也没细读,大概翻阅了一下,就一直放在公司的办公桌上,直到走的那天,把这本书收起来带回家。
书的第一部分简单介绍的了一下性能测试的基础知识,loadrunner的基本使用,如果录制脚本,如何设置参数化等等,如何负载加压,如何查看分析测试结果等。对我来说最大的亮点就是C语言基础的部分,前段时间又把这部分仔细回顾了一下!最大的不足是讲解的C语言与loadrunner结合的深。其实,也就是把C语言基础书浓缩了一下。
书的第二部分又告诉了我们loadrunner稍微高级一点的技巧,关联动态函数库的调用。如何设置IP欺骗与多机联合测试。根据不同的协议来做不同的测试,数据库性能测试(书上这种方法我到现在也不会用)、foxmail邮件的发送,这个例子我照着做过,挺有意思的。常见问题解决,讲解了许多我们在使用loadrunner时遇到常见问题和技巧。这应该是本书最大的亮点。
操作系统监控,linux与window下的相关监控工具,这太简单了,在网上随便查查就懂了。作者讲得很细。终于讲了一点性能测试过程的东西,不过对现在我来说,太浅了。
第三部分为实战篇,简单介绍了两个项目,也算看到了些性能测试流程的影子。最后作者还告诉了我们其它一些应该必须的知识,http协议,虚拟机,中间件等。最最后的内容挺无聊的。面试技巧跟常见智力题。我了个去。这有点2了。
整体感觉,loadrunner 使用过程中的工具书。对于有点性能测试基础的同学随便翻翻,啥时间遇到问题了,也许可以在这书中找到惊喜。
软件性能测试过程详解与案例抛析

《软件性能测试过程详解与案例抛析》这本书,我看的是电子版,刚拿到之后读了几页,如获至宝,因为他是在讲性能测试,而不是loadrunner 。其它书都拿“loadrunner”当“性能测试”来讲,就算loadrunner是最主流的性能测试工具。
再扯点,反正本篇文章就来胡侃的。第一次知道段念这个是前年在infoq上看过他的一篇演讲,关于《基于互联网产品快速测试》的主题,也知道他是国内比较早接触测试的元老级人物。
作者前面对一些基本概念讲解的比较透彻,虽然在此之前已经知道了那些性能测试的基本概念,但看了他的介绍,还是有豁然开朗,理解加深的感觉。
第三章性能计数器,介绍了硬件方面我们应该监控哪些部件的性能以及如何监控,他们有哪些指标。其实,这部分没什么亮点。第四章介绍性能测试工具的原理,如何选择符合性能测试工具或自己开发工具,这一点明显鄙视了loadrunner在性能测试中的地位。呵呵!你以为你就是性能测试啊。你不过就一性能工具而已,哥可以选择用或不用的。
后面讲性能测试的组织和流程,关于流程流程这块,各抒己见,其实没什么能被许多人认可的流程,都是从自身的经验中提炼出来的。不过,他的这个流程是被大多数人接受和借鉴的。
后面就是项目实战,这里介绍的几个项目都不是很大,但非常完整。对被测试的项目做了详尽的介绍,从前期需求分析,人员安 排,环境部署,脚本开发,到后期结果分析等都包含了。没做过性能测试项目的同学也可以对性能测试的流程有个比较清晰的了解。三个项目在性能测试工具的选择 上,分别用了webload 、loadrunner 与自己开发性能工具。这一部分应该是本书的一大亮点。
因为loadrunner在当今性能测试界的地位太高。最后作者还是附带上了loadrunner的一些使用技巧。没啥亮点,教你咋用这工具呗。
——————————–
《软件性能测试过程详解与案例抛析(第二版)》因为第一版读完感觉这本性能书就是好。于是,订购了第二版,当时刚出来,我花高价订的,china-pub 上面,邮了快二十天,等我收到书到,已经降价了。
第二部多加了两章,前端性能测试,现在前端性能测试也被提到了非常重要的位置,因为各种华丽的前端技术的应用,也使前端也有了非常大的优化空间。本章介绍http协议,前端优化技术以及好多种前端性能测试工具。
增加了jmeter工具的使用,其实,我也非常喜欢jmeter ,但的介绍这个工具书籍与资料不是很多。现在好像出了一本,个人感觉不好。因为在网上看了一点。整体感觉第二本不厚道。时隔六七年了,实战的例子也不说换换。估计这个工作量对作者有点大。建议看过第一版就别买第二版了。
性能测试进阶指南——-loadrunner 9.1实战

《性能测试进阶指南——-loadrunner 9.1实战》,这本书也在看的电子版,老书了都,所以网上很容易找到电子版的,51testing讲 师,专攻性能这块的。不知道为什么,看他的书比较有亲近感,也许是我写文章与他态度类似,虽然自己水平一般(这里没鄙视“云层”大哥的意思),但喜欢学 习、研究、分享给别人。他现在还那喜欢在论坛上帮助别人我很敬佩,好多专都忙,比第一本书的作者于俑,看了的关于数据库性能的内容,看不懂,加他QQ想问问,结果他说忙得很,让发邮件问!算了不问了。
再是说书吧!这是一本比loadrunner中文文档更好的一份中文文档。Loadrunner中文文档只告诉你每个功能在哪儿,简单介绍功能的作用。但这本书告诉你在哪些情况下需要用到这些功能,如何来使用这些功能来为我们的性能测试服务。作者关于检查点,参数化、参考时间、关联、事务等这些loadrunner的技巧讲解的非常透彻。你不但知道这些东西是干嘛的还知道如何把这些东西真实的用到实际的脚本开发中。
其它部分,如负载生成与监控、测试数据分析讲解的也比较透彻。后面也有性能测试实战部分,也是对一个论坛项目比较完整的分析。
作者比较爱举例子,生活中的例子可以让我们接收一些知识变得有趣,空洞的理论非常乏味。其实,我在写博客的时候也喜欢举各种生活中的例子。
——————–
《性能测试进阶指南——-loadrunner 11实战》 这本书是上面那本书的第二版,在网上看过两节,内容应该比第一版加了很多东西,应该比段念的第二版厚道,不过一直没买,价格高,国内的性能书都快餐,虽然也能解决饥饿问题,但听过一次就没味了。所以,还是不买了,免得后悔。
评价书的好坏,其实更多的与读者的水平有关,如果一本书的内容你都没接触了,而且对你来说都非常有用,那你自然从书中收获很多,会感觉是好书。反之,则会认为是骗小孩钱的作品。就像段念的第二本,如果我没看过第一本,那买到的第二本一定会觉得是非常好的书。

第一本是性能测试技巧查询工具书,第二本是性能测试理论书,第三本是loadunner的应用级中文文档。 《性能测试诊断分析与优化》就是告诉我们如何提高软件的性能,这也是我们做性能测试的最终目的,我们做性能测试的目的不就是验证软件能力,想办法提高与优化它么?可惜了这么好的书名。呵呵
其实,性能测试难点不是性能测试上,而是你除了性能测试的知识与工具的使用外,更应该对整个被测系统有深入的了解。当然 必须对软件所依附的操作系统、中间件、数据库、开发语言、网络、协议都有一定的认识。这样我们才能诊断分析与优化。掌握上面的东西也不是一朝一夕之功。
作者的第一篇,讲性能测试基础与性能测试流程。虽然前面的几本书都讲过这些东西,但每个人的的认知都有局限性能。再读一下这本书的内容也能略有收获。本书的第二篇是介绍loadrunner ,这部分就毫无亮点了,除非你从没看过前面三本书,对loadrunner也一点不了解。
其实,我只是想买这本书的第三部分,对apache 、tomcat、weblogic等最常用的中间件做了简单分析以及如何监控分析;对数据库如何监控分析,应用代码的性能分析以及操作系统。讲得很粗浅,不过让也让我们对性能分析与调优有了初步的认识。
其实,我觉得更应该比第三部分放大为全书内容,前面两章不要,这样才对得起这个名字吧,可能作者也想让新手看这本书。
要想学好性能测试的分析与调优,你还是买一些apache、数据库这类书好好研读吧。投机取不了巧。
————————
但然还读了《web性能测试实战》一书,也是电子版,介于这本书出的较早,作者接触的性能测试也不专业,讲得也啰嗦,实用性很差。不过,你没事也可以翻阅一下。在这里也只是我一家之言,不可全信。
[转载]探讨IOS应用在中国的盈利模式 – 青青子熙 – 博客园.
写在正文前:这个命题是面试的时候,面试官Roger给我的题目。昨天将结果发过去后,就没有消息了,估计这事黄了。好久没有写东西,回想这一年,淡淡的忧伤,当初预想的事情很多都没有做。这是开头的一篇,督促自己以后要写有质量的文章。
正文:
IOS吸引越来越多的用户使用,但中国用户偏向使用免费应用,IOS应用的盈利有哪些。本文通过分析IOS用户和IOS应用的使用情况,寻找应用使用者多,开发者盈利少的原因,探讨IOS应用在中国的盈利模式。
一 IOS用户的使用概况
1.1 IOS用户终端APP使用情况
智能应用最多,占70%;手机最初的通话功能被淡化,占19%。

1.2 中国APP应用类型分布情况
实用工具吸引最多的用户,信息、社交网络也具有相当大的参与度。APP广泛使用让IOS成为便捷商务、交流和娱乐的平台。

1.3 不同类型的用户,APP应用类型分布存在差异性。

女性比男性更多使用社交网络,多媒体的应用。女性更多倾向于娱乐沟通交流的应用,男性更喜好商务应用或游戏应用。
二 APP使用者多,为何盈利难
移动互联网的用户在不断攀升,更多开发者进入手机开发平台。IOS盈利模式有移动广告、应用收费、道具购买等方式,开发者更愿意选择IOS平台开发。
而中国用户偏向使用免费应用,更多选择越狱的IOS。IOS版本越早,越狱的比例越高,一半以上的用户选择越狱版本。

加上中国本土的因素,传统的IOS盈利模式受到各方面的挑战:
1、越狱版本使原本收费的应用可以免费使用,损害开发者在应用收费的所得;
2、IOS平台支付的可操作性差,采用美元支付,用户难以理解,选择不支付;
3、终端屏幕小,上网费用高,联网游戏用户体验差,道具购买量少;
4、移动广告平台的投放效果差;
三 探讨IOS应用在中国的盈利模式
结合传统的盈利模式,根据移动互联网的便捷性等特点。总结出如下盈利模式有如下的方式:
1.1 移动互联网广告:精准化的广告投放,吸引更多商家投放广告。
移动互联网广告可能掀起移动互联网商业模式的全新变革,带领移动互联网业务走向繁荣。IOS平台用户的分布集中在发达城市,广东地区分布最多,达12.8%,北京,上海,浙江,江苏在8%-10%之间。可根据各地区用户的消费习惯不同,有针对性地投放广告。

用户在是使用的时间也非常有规律, 图书、新闻、商业类应用在白天使用较多,游戏、娱乐类应用在晚上使用较多;图书、新闻在8-10点达到使用高峰,游戏类应用在17-21点达到使用高峰。因此可精确对不同群体,对不同的时间段,不同地区的用户投放不同的广告。例如,早上8:00-9:00是都市白领挤公交地铁的时刻,在这个时刻可投入消费群体为都市白领的广告。同时,移动终端屏幕较小,投放广告更应该注意广告的针对性和趣味性,尽量让广告投对人,让人对广告有兴趣,而不是产生一种排斥心理。
1.2 移动互联网游戏:通过品牌效益,道具购买,嵌入广告的方式盈利。
单机游戏用户的忠实度高,越狱IOS损害单机游戏的应用收费盈利模式,可利用游戏的知名度,推出一系列品牌的商品,如定制的服装,摆设物等,通过游戏的品牌效益带动相关商品的消费。
联网游戏的趣味性和互动性更高,对终端屏幕和配置较高。可专注平板IOS的联网游戏的开发,通过道具购买,嵌入广告的模式盈利。
1.3 移动商务。建立商业中心吸引消费者,对入驻商家的营销活动进行收费。
建立移动商街,在IOS建 立虚拟商业中心,在移动商街上,入驻移动商街的企业和商家可通过移动商街进行市场营销、产品推广和形象展示,为消费者提供商业服务,促进销售;消费者可以 通过手机在移动商街上获得及时有用的消费资讯和生活服务信息进行比较、选择和购物消费,了解商家并参与营销互动,享受折扣、奖品和积分回报等实惠。
1.4 社交网络平台。对个性化设置和差异化服务收费。
社交网络对于收费群体提供更多个性化设置,在免费的基础上提供更有价值的服务吸引用户付款使用。增加用户购物分享和应用分享的频道。实现用户传播品牌,带动好友消费的商业价值。
[转载]Java报表比较之中国式报表(复杂报表)篇 – 报表,报表软件,报表工具,java报表,JAVA报表工具 – Java – ITeye论坛.
Java报表工具,首先可以分成两大类:纯Java报表工具,和支持Java的报表工具。
支持Java的报表工具
我们所说的”支持”Java的报表工具.其实就是非Java的报表工具,但是可以在Java程序中调用.这样的产品很多,总的讲一大类是采用独立报表服务器的,如Crystal Report,Brio,Cognos,和勤等;另一大类是在前端有控件的,如数巨报表等。
纯Java报表工具
纯Java的报表工具,就是用java语言编写的报表工具,包括报表引擎、内核、设计器界面、操作等。主要的有:Style Report,润乾报表、Jasper Report,Birt,Fine Report,ireport,杰表等。
笔者只针对其中三款纯Java报表的中国式报表的处理做简单比较: 所谓中国式报表或者说复杂报表,其最根本的特征就是其格间关系的复杂度和布局扩展的灵活性,比起传统的以数据分组和聚合为基础的报表来说,中国式报表的布 局和格间计算都复杂得多,所以很多传统的报表工具比如最著名的水晶报表在处理起这类复杂报表时就显得比较吃力。
Java报表工具–润乾:类似于Excel的可以支持任意行列扩展的报表处理模式。
Java报表工具–杰表:通过拖拽加拼接的操作结合结构化设计的报表处理模式。
Java报表工具—Style Report将结构化设计和行列任意扩展相结合的混合型报表处理模式。
当然,对复杂表格的支持只是选择报表软件很多要求中的一点。如果是一次性的使用,我们可以只关注软件和当前需求的匹配,如果是准备长期使用的软件,就需要关注软件总体设计思维和它长期的发展方向。
转载asp.net 网站纯静态化设计及其实现 – 饥饿定义我 – 博客园.
引言:为减轻服务器压力,较少伪静态对CPU的消耗,下面使用了纯静态的方式提供站点访问!
一、流程图如下

二、逐步分析
A.捕获404,获取请求地址
用户访问站点地址如下(例如:www.yahoo.com/news/1.html)
这时如果站点中存在如下文件即可快速的完成访问,为什么呢?因为是真实的,纯html文件呗!
不存在,那就是这套流程发挥效用的时候了!找不到文件,你肯定能得到404的错误
这时在Global.asax文件中,写下如下代码:
protected void Application_Error(object sender, EventArgs e)
{
Exception error = Server.GetLastError();
HttpException httpException = error as HttpException;
if (httpException != null)
{
int httpCode = httpException.GetHttpCode();
if (httpCode == 404)
{
Server.ClearError();
string ruleType, htmlcache, cacheName;
string errorUrl = Request.RawUrl;//请求页面地址
}
}
}
B.静态地址和动态地址的转化
到目前为止你得到了页面的真是请求地址,(例如:www.yahoo.com/news/1.html),这时你需要做一个转换,将真是的请求地址转换为动态(aspx)地址,那么转换的关系的配置文件,我配置在一个xml中使用url rewriter格式编写
如下:
1 <RewriterRule> 2 <LookFor>/news/(\d+).html</LookFor> 3 <SendTo>News.aspx?pageIndex=$0</SendTo> 4 </RewriterRule>
转化方法略
C.发送HTTP请求,向动态地址请求html内容,在Global.asax直接Response.Write(“返回的html”);
WebRequest wrt = null;
WebResponse wrse = null;
try
{
wrt = WebRequest.Create("真实地址");
wrse = wrt.GetResponse();
Stream strM = null;
StreamReader SR = null;
try
{
strM = wrse.GetResponseStream();
SR = new StreamReader(strM, code);
string strallstrm = SR.ReadToEnd();
return strallstrm;
}
catch (Exception ex)
{ }
}
D.异步生成静态文件,供下次访问(异步请求的好处,用户不必等待,完成获取内容用户即可看到网页,生成静态页面由另一条线程完成)
public delegate bool MakeHtmlDelegate(string htmlContent, string path);//htmlContent html内容,path 文件存放目录及其文件名称
AsyncCallback callBack = new AsyncCallback(Procdss);
MakeHtmlDelegate deleg = new MakeHtmlDelegate(生成方法);
IAsyncResult async = deleg.BeginInvoke(htmlContent,path), callBack, deleg);
void Procdss(IAsyncResult async)
{
MakeHtmlDelegate deleg = async.AsyncState as MakeHtmlDelegate;
if (deleg != null)
{
bool isSuc = deleg.EndInvoke(async);
}
}
[转载]高质量开发JS准则及范例 – Miracle He – 博客园.
1.用匿名函数(function(){})();将脚本包裹起来,有效控制全局变量,避免冲突隐患。
2.在解决JS冲突的前提下,如果需要进行多个模块(匿名函数)之间的通信,则需要采用唯一全局变量(系约定名:GLOBAL)+命名空间+属性的方式来解决,同时应该为你维护的模块添加必要的注释,以提高团队合作的效率。
3.CSS放在页头,JS放在页尾。
4.发布正式前压缩JS文件:Packer(http://dean.edwards.name/packer)和YUI Compressor
(http://developer.yahoo.com/yui/compressor)。后者需安装JDK和配置java环境,下载jar文件 并通过命名进行调用。常见命令:java -jar yuicompressor-x.y.z.jar myfile.js -o myfile.min.js。
不过也可在线使用YUI Compressor: http://refresh-sf.com/yui。同时,可以使用反压缩工具http://jsbeautifier.org对已压缩后的文件进行恢复。
5.利用JS分层对应用程序代码组织进行更好的控制:base、common、page。其中base层完成封装不同浏览器下JS的差异,提供统一 的接口,位于三层中的最底层。common层依赖于base层,提供可复用的组件,和具体的页面功能没有直接关系,为page层提供组件。page层依赖 于base和common层,提供具体的页面功能。
6.利用getElementsByClassName()和getElementsByTagName()都可获取一组具有”相似功能”的DOM节点,但后者适合稳定的HTML结构,而前者使得JS和HTML实现最大程序解耦。
7.要满足一组具有”相似功能”的DOM节点能够复用,则不能使用父容器的ID作为挂钩,而是对这组节点使用相同的类。
8.在同一页面使用多个内容结构相似的组件时,应分别为每个组件指定一个根节点,以保持每个组件之间的独立性。
9.如果一个函数内部某个因素非常不稳定,可将它从函数内部分离出来,以参数形式传入,实现将不稳定因素和函数解耦。
10.可通过匿名函数,call以及apply来调整this指向,也可在this指向变化之前保存为另一变量。
11.为函数预留回调接口增加可扩展性。
12.通常利用function来定义类,一般函数名为大写(同时代表构造函数)。每定义一个类时,同时将产生一个该类对应的原型(hash对 象),也可在原型中定义属性和行为,但构造函数中的属性和行为比原型优先级高,对于同名属性和行为,构造函数中的对应的属性和行为将覆盖原型中定义的同名 属性和行为。通过this关键字实现构造函数和原型进行通信。
13.推荐将行为封装到类的函数原型里,属性封装到构造函数中。通过this定义公有属性和行为,通过var定义私有属性和行为(通过作用域实 现)。私有属性和行为是不能在原型中被访问。通常情况下定义多实例情况下,构造函数中的属性和行为都会复制一份到每个实例中,而原型中的属性和行为都会在 多实例中共享(不会复制)。
14.如要实现公有行为访问到私有成员,最简单的解决办法就是将所有的公有成员定义到构造函数中(与私有成员在同一作用域),但这样做会消耗内存,仅适合于对私有性要求非常高的项目(通常具有强制性要求),但一般情况下不推荐这样做。
15.定义在原型中的行为一定是公有的,如果项目对私有成员并没有强制性要求,推荐以下做法:约定私有成员的定义形式(通常在成员前加_以示区分公 有成员),将私有属性定义到构造函数中,私有行为定义到原型中。但注意:既然只是约定,就不能真正实现私有化,只是团队成员调用私有成员属于不合乎规范而 已(不能强制避免,只是约定而已)。
16. 极端的OO采用get和set访问实现对私有属性的完全私有化,同样会带来很大的内存消耗,但可以定制私有属性(如只读等)。对于比较简单的应用,直接采用this.**对属性进行读写,而对于较复杂的应用,则采用get和set访问器实现。
17.在接触到18之前,有必要说下JS传值和传址的问题。所谓传值,即复制一份副本传递,而不改变其本身,适合于基本数据类型 (如:int,bool,string等);所谓传址,即将当前变量的地址传递给新变量,此时两个变量都引用同一个地址,对新变量的更改也会影响原变量本 身,适合于数组、对象等复杂数据类型。那如何实现给复杂数据类型(其中包含基本数据类型)传值呢?首先定义一个新变量,可通过for in循环其中的基本数据类型,来分别将每个基本类型赋值给新变量即可完成。对于数组来说,还可通过自身方法slice或concat来实现。
18.简单的说,要实现类继承,无外乎就是将父类构造函数和原型中的属性和行为复制到子类的过程。但不能通过直接复制或调用父类构造函数就能完成, 必须通过call或apply调整当前对象指向(window->this)来完成调用。对于原型继承,也不可直接将父类的原型直接拷贝到子类,我 们都知道原型实际上可看成一个hash对象,在JS中传值方式分为传值和传址两种方式,对于hash对象来说当然是传址(即子类原型和父类原型指向同一个 对象),这时要是在子类中添加了新的行为(实际上正是因为有了继承,子类肯定会添加新的行为),同时也将改变父类的原型,当然就违背继承的初衷了。我们可 以让父类原型以传值的方式给子类(即只给一个副本给子类,子类原型改变而不影响父类自身),通常有两种方式可以实现:定义子类新原型,通过for in循环父类原型,将其中的值(其实都已经是基本类型)逐个拷贝到子类新原型中。其次利用构造函数特性,new一个父类对象给子类原型,同时调整子类原型 构造函数为子类本身,就可简单实现父类原型中的成员复制到子类。
我这里用实例来说明以上的准则(完整版):
利用面向过程设计Tab
<html>
<head>
<style type="text/css">
ul {padding:0;margin:0;}
.tab {width:400px;}
.tab .tab-currentMenu {background-color:#333;color:#fff;}
.tab .tab-currentMenu2 {background-color:blue;color:#fff;}
.underline {text-decoration:underline;}
.tab-menu {padding-left:20px;}
.tab-menu li {float:left;display:inline;padding:5px;border:1px solid #333;border-bottom:none;margin-right:5px;}
.tab-content {border:1px solid #333;clear:left;padding:5px;}
</style>
</head>
<body>
<div class="tab J_tab">
<ul class="tab-menu">
<li class="J_tab-menu">menu1-1</li>
<li class="J_tab-menu">menu1-2</li>
<li class="J_tab-menu underline">menu1-3</li>
</ul>
<div class="tab-content">
<div class="J_tab-content"><div>content1-1</div><ul><li>abc</li></ul></div>
<div class="J_tab-content" style="display:none;"><p>content1-2</p><div>abc</div></div>
<div class="J_tab-content" style="display:none;">content1-3</div>
</div>
</div>
<div class="tab J_tab">
<ul class="tab-menu">
<li class="J_tab-menu tab-currentMenu">menu2-1</li>
<li class="J_tab-menu">menu2-2</li>
</ul>
<div class="tab-content">
<div class="J_tab-content"><div>content2-1</div><ul><li>abc</li></ul></div>
<div class="J_tab-content" style="display:none;"><p>content2-2</p><div>abc</div></div>
</div>
</div>
<div class="tab J_tab">
<ul class="tab-menu">
<li class="J_tab-menu tab-currentMenu2">menu3-1</li>
<li class="J_tab-menu">menu3-2</li>
<li class="J_tab-menu">menu3-3</li>
<li class="J_tab-menu">menu3-4</li>
<li class="J_tab-menu">menu3-5</li>
</ul>
<div class="tab-content">
<div class="J_tab-content"><div>content3-1</div><ul><li>abc</li></ul></div>
<div class="J_tab-content" style="display:none;"><p>content3-2</p><div>abc</div></div>
<div class="J_tab-content" style="display:none;">content3-3</div>
<div class="J_tab-content" style="display:none;"><p>content3-4</p><div>abc</div></div>
<div class="J_tab-content" style="display:none;">content3-5</div>
</div>
</div>
<script type="text/javascript">
var GLOBAL = {};
GLOBAL.namespace = function (str) {
var arr = str.split("."), o = GLOBAL;
for (i = (arr[0] == "oa") ? 1 : 0; i < arr.length; i++) {
o[arr[i]] = o[arr[i]] || {};
}
o = o[arr[i]];
};
GLOBAL.namespace("dom");
GLOBAL.dom.getElementsByClassName = function(str, parent, tag) {
if(parent) {
parent = typeof parent == "string" ? document.getElementById(parent) : parent;
} else {
parent = document.body;
}
tag = tag || "*";
var elems = parent.getElementsByTagName(tag);
var array = [];
for(var i = 0, len = elems.length; i < len; i++) {
for (var j = 0, k = elems[i].className.split(" "), l = k.length; j < l; j++) {
if(k[j]==str) {
array.push(elems[i]);
break;
}
}
}
return array;
}
GLOBAL.dom.addClass = function(node, str) {
if (!new RegExp("(^|\\s+)" + str).test(node.className)) {
node.className = node.className + " " + str;
}
}
GLOBAL.dom.removeClass = function(node, str) {
node.className = node.className.replace(new RegExp("(^|\\s+)" + str), "");
}
GLOBAL.namespace("event");
GLOBAL.event.on = function(node, eventType, handler, scope) {
node = typeof node == "string" ? document.getElementById(node) : node;
scope = scope || node;
//可通过匿名函数,call以及apply来调整this指向,也可在this指向变化之前保存为另一变量
if(document.all) {
//node.attachEvent("on" + eventType, handler);
node.attachEvent("on" + eventType, function() {
handler.apply(scope, arguments);
});
} else {
//node.addEventListener(eventType, handler, false);
node.addEventListener(eventType, function() {
handler.apply(scope, arguments);
}, false);
}
}
function setTab(config) {
var parent = config.parent;
var currentClass = config.currentClass;
var trigger = config.trigger || "click";
var handler = config.handler;
var autoPlay = config.autoPlay;
var playTime = config.playTime || 3000;
var menus = GLOBAL.dom.getElementsByClassName("J_tab-menu", parent);
var contents = GLOBAL.dom.getElementsByClassName("J_tab-content", parent);
var currentIndex = 0;
function showItem(n) {
for(var i = 0, len = contents.length; i < len; i++) {
contents[i].style.display = "none";
}
contents[n].style.display = "block";
if(currentClass) {
var currentMenu = GLOBAL.dom.getElementsByClassName(currentClass, parent)[0];
if (currentMenu) {
GLOBAL.dom.removeClass(currentMenu, currentClass);
}
GLOBAL.dom.addClass(menus[n], currentClass);
}
//预留回调接口
if(handler) {
handler(n);
}
}
function autoHandler() {
currentIndex++;
if(currentIndex >= menus.length) {
currentIndex = 0;
}
showItem(currentIndex);
}
if(autoPlay) {
setInterval(autoHandler, playTime);
}
for (var i = 0, mLen = menus.length; i < mLen; i++) {
menus[i]._index = i;
GLOBAL.event.on(menus[i], trigger, function() {
showItem(this._index);
currentIndex = this._index;
});
}
}
var tabs = GLOBAL.dom.getElementsByClassName("J_tab");
setTab({ parent: tabs[0], trigger: "mouseover" });
setTab({ parent: tabs[1], currentClass: "tab-currentMenu", autoPlay: true, playTime: 4000 });
setTab({ parent: tabs[2], currentClass: "tab-currentMenu2", trigger: "mouseover", handler: function (index) {
alert("你激活的是第" + (index + 1) + "个标签");
}
});
</script>
</body>
</html>
利用面向对象设计Tab
<html>
<head>
<style type="text/css">
ul {padding:0;margin:0;}
.tab {width:400px;}
.tab .tab-currentMenu {background-color:#333;color:#fff;}
.tab .tab-currentMenu2 {background-color:blue;color:#fff;}
.underline {text-decoration:underline;}
.tab-menu {padding-left:20px;}
.tab-menu li {float:left;display:inline;padding:5px;border:1px solid #333;border-bottom:none;margin-right:5px;}
.tab-content {border:1px solid #333;clear:left;padding:5px;}
</style>
</head>
<body>
<div class="tab J_tab">
<ul class="tab-menu">
<li class="J_tab-menu">menu1-1</li>
<li class="J_tab-menu">menu1-2</li>
<li class="J_tab-menu underline">menu1-3</li>
</ul>
<div class="tab-content">
<div class="J_tab-content"><div>content1-1</div><ul><li>abc</li></ul></div>
<div class="J_tab-content" style="display:none;"><p>content1-2</p><div>abc</div></div>
<div class="J_tab-content" style="display:none;">content1-3</div>
</div>
</div>
<div class="tab J_tab">
<ul class="tab-menu">
<li class="J_tab-menu tab-currentMenu">menu2-1</li>
<li class="J_tab-menu">menu2-2</li>
</ul>
<div class="tab-content">
<div class="J_tab-content"><div>content2-1</div><ul><li>abc</li></ul></div>
<div class="J_tab-content" style="display:none;"><p>content2-2</p><div>abc</div></div>
</div>
</div>
<div class="tab J_tab">
<ul class="tab-menu">
<li class="J_tab-menu tab-currentMenu2">menu3-1</li>
<li class="J_tab-menu">menu3-2</li>
<li class="J_tab-menu">menu3-3</li>
<li class="J_tab-menu">menu3-4</li>
<li class="J_tab-menu">menu3-5</li>
</ul>
<div class="tab-content">
<div class="J_tab-content"><div>content3-1</div><ul><li>abc</li></ul></div>
<div class="J_tab-content" style="display:none;"><p>content3-2</p><div>abc</div></div>
<div class="J_tab-content" style="display:none;">content3-3</div>
<div class="J_tab-content" style="display:none;"><p>content3-4</p><div>abc</div></div>
<div class="J_tab-content" style="display:none;">content3-5</div>
</div>
</div>
<script type="text/javascript">
var GLOBAL = {};
GLOBAL.namespace = function (str) {
var arr = str.split("."), o = GLOBAL;
for (i = (arr[0] == "oa") ? 1 : 0; i < arr.length; i++) {
o[arr[i]] = o[arr[i]] || {};
}
o = o[arr[i]];
};
GLOBAL.namespace("dom");
GLOBAL.dom.getElementsByClassName = function(str, parent, tag) {
if(parent) {
parent = typeof parent == "string" ? document.getElementById(parent) : parent;
} else {
parent = document.body;
}
tag = tag || "*";
var elems = parent.getElementsByTagName(tag);
var array = [];
for(var i = 0, len = elems.length; i < len; i++) {
for (var j = 0, k = elems[i].className.split(" "), l = k.length; j < l; j++) {
if(k[j]==str) {
array.push(elems[i]);
break;
}
}
}
return array;
}
GLOBAL.dom.addClass = function(node, str) {
if (!new RegExp("(^|\\s+)" + str).test(node.className)) {
node.className = node.className + " " + str;
}
}
GLOBAL.dom.removeClass = function(node, str) {
node.className = node.className.replace(new RegExp("(^|\\s+)" + str), "");
}
GLOBAL.namespace("event");
GLOBAL.event.on = function(node, eventType, handler, scope) {
node = typeof node == "string" ? document.getElementById(node) : node;
scope = scope || node;
//可通过匿名函数,call以及apply来调整this指向,也可在this指向变化之前保存为另一变量
if(document.all) {
//node.attachEvent("on" + eventType, handler);
node.attachEvent("on" + eventType, function() {
handler.apply(scope, arguments);
});
} else {
//node.addEventListener(eventType, handler, false);
node.addEventListener(eventType, function() {
handler.apply(scope, arguments);
}, false);
}
}
//面向对象
function Tab(config) {
this._parent = config.parent;
this._currentClass = config.currentClass;
var trigger = config.trigger || "click";
this._handler = config.handler;
var autoPlay = config.autoPlay;
var playTime = config.playTime || 3000;
this._menus = GLOBAL.dom.getElementsByClassName("J_tab-menu", this._parent);
this._contents = GLOBAL.dom.getElementsByClassName("J_tab-content", this._parent);
this.currentIndex = 0;
var $this = this;
if(autoPlay) {
setInterval(function() { $this._autoHandler(); }, playTime);
}
for (var i = 0, mLen = this._menus.length; i < mLen; i++) {
this._menus[i]._index = i;
GLOBAL.event.on(this._menus[i], trigger, function() {
$this.showItem(this._index);
this.currentIndex = this._index;
});
}
}
Tab.prototype = {
showItem: function(n) {
for(var i = 0, len = this._contents.length; i < len; i++) {
this._contents[i].style.display = "none";
}
this._contents[n].style.display = "block";
if(this._currentClass) {
var currentMenu = GLOBAL.dom.getElementsByClassName(this._currentClass, this._parent)[0];
if (currentMenu) {
GLOBAL.dom.removeClass(currentMenu, this._currentClass);
}
GLOBAL.dom.addClass(this._menus[n], this._currentClass);
}
//预留回调接口
if(this._handler) {
this._handler(n);
}
},
_autoHandler: function() {
this.currentIndex++;
if(this.currentIndex >= this._menus.length) {
this.currentIndex = 0;
}
this.showItem(this.currentIndex);
}
};
var tabs = GLOBAL.dom.getElementsByClassName("J_tab");
new Tab({ parent: tabs[0], trigger: "mouseover" });
new Tab({ parent: tabs[1], currentClass: "tab-currentMenu", autoPlay: true, playTime: 4000 });
new Tab({ parent: tabs[2], currentClass: "tab-currentMenu2", trigger: "mouseover", handler: function (index) {
alert("你激活的是第" + (index + 1) + "个标签");
}
});
</script>
</body>
</html>
[转载]sql server 锁表 select for update – 风信绮缘.唧唧的博客.
SELECT 语句中“加锁选项”的功能说明
SQL Server提供了强大而完备的锁机制来帮助实现数据库系统的并发性和高性能。用户既能使用SQL Server的缺省设置也可以在select 语句中使用“加锁选项”来实现预期的效果。 本文介绍了SELECT语句中的各项“加锁选项”以及相应的功能说明。
功能说明:
NOLOCK(不加锁)
此选项被选中时,SQL Server 在读取或修改数据时不加任何锁。 在这种情况下,用户有可能读取到未完成事务(Uncommited Transaction)或回滚(Roll Back)中的数据, 即所谓的“脏数据”。
HOLDLOCK(保持锁)
此选项被选中时,SQL Server 会将此共享锁保持至整个事务结束,而不会在途中释放。
UPDLOCK(修改锁)
此选项被选中时,SQL Server 在读取数据时使用修改锁来代替共享锁,并将此锁保持至整个事务或命令结束。使用此选项能够保证多个进程能同时读取数据但只有该进程能修改数据。
TABLOCK(表锁)
此选项被选中时,SQL Server 将在整个表上置共享锁直至该命令结束。 这个选项保证其他进程只能读取而不能修改数据。
PAGLOCK(页锁)
此选项为默认选项, 当被选中时,SQL Server 使用共享页锁。
TABLOCKX(排它表锁)
此选项被选中时,SQL Server 将在整个表上置排它锁直至该命令或事务结束。这将防止其他进程读取或修改表中的数据。
HOLDLOCK 持有共享锁,直到整个事务完成,应该在被锁对象不需要时立即释放,等于SERIALIZABLE事务隔离级别
NOLOCK 语句执行时不发出共享锁,允许脏读 ,等于 READ UNCOMMITTED事务隔离级别
PAGLOCK 在使用一个表锁的地方用多个页锁
READPAST 让sql server跳过任何锁定行,执行事务,适用于READ UNCOMMITTED事务隔离级别只跳过RID锁,不跳过页,区域和表锁
ROWLOCK 强制使用行锁
TABLOCKX 强制使用独占表级锁,这个锁在事务期间阻止任何其他事务使用这个表
UPLOCK 强制在读表时使用更新而不用共享锁
注意: 锁定数据库的一个表的区别
SELECT * FROM table WITH (HOLDLOCK) 其他事务/语句可以读取表,但不能更新删除
SELECT * FROM table WITH (TABLOCKX) 其他事务/语句不能读取表,更新和删除
例子:
begin tran
select * from test_table with (TABLOCKX) //表锁
commit tran
这时,其它语句,比如select * from test_table将只能等待
[转载]浅谈SQL SERVER中事务的ACID – CareySon – 博客园.
ACID,是指在可靠数据库管理系统(DBMS)中,事务(transaction)所应该具有的四个特性:原子性(Atomicity)、一致性 (Consistency)、隔离性(Isolation)、持久性(Durability).这是可靠数据库所应具备的几个特性.下面针对这几个特性进 行逐个讲解.
原子性意味着数据库中的事务执行是作为原子。即不可再分,整个语句要么执行,要么不执行。
在SQL SERVER中,每一个单独的语句都可以看作是默认包含在一个事务之中:
所以,每一个语句本身具有原子性,要么全部执行,这么全部不执行,不会有中间状态:
上面说了,每一条T-SQL语句都可以看作是默认被包裹在一个事务之中的,SQL Server对于每一条单独的语句都实现了原子性,但这种原子粒度是非常小的,如果用户想要自己定义原子的大小,则需要包含在事务中来构成用户自定义的原子粒度:
对于用户来说,要用事务实现的自定义原子性往往是和业务相关的,比如银行转账,从A账户减去100,在B账户增加100,如果这两个语句不能保证原子性的 话,比如从A账户减去100后,服务器断电,而在B账户中却没有增加100.虽然这种情况会让银行很开心,但作为开发人员的你可不希望这种结果.而默认事 务中,即使出错了也不会整个事务进行回滚。而是失败的语句抛出异常,而正确的语句成功执行。这样会破坏原子性。所以SQL SERVER给予了一些选项来保证事务的原子性.
SQL SERVER提供了两大类方式来保证自定义事务的原子性:
1.通过SET XACT_ABORT ON来设置事务必须符合原子性
利用设置XACT_ABORT选项设置为ON,来设置所有事务都作为一个原子处理.下面例子利用两个语句插入到数据库,可以看到开启SET XACT_ABORT ON选项后,事务具有了原子性:
2.按照用户设置进行回滚(ROLLBACK)
这种方式具有更高的灵活性,开发人员可以自定义在什么情况进行ROLLBACK,利用TRY CATCH语句和@@ERROR进行判断都属于这种方式.
一致性,即在事务开始之前和事务结束以后,数据库的完整性约束没有被破坏。
一致性分为两个层面
1.数据库机制层面
数据库层面的一致性是,在一个事务执行之前和之后,数据会符合你设置的约束(唯一约束,外键约束,Check约束等)和触发器设置.这一点是由SQL SERVER进行保证的.
2.业务层面
对于业务层面来说,一致性是保持业务的一致性.这个业务一致性需要由开发人员进行保证.很多业务方面的一致性可以通过转移到数据库机制层面进行保证.比如,产品只有两个型号,则可以转移到使用CHECK约束使某一列必须只能存这两个型号.
隔离性。事务的执行是互不干扰的,一个事务不可能看到其他事务运行时,中间某一时刻的数据。
在Windows中,如果多个进程对同一个文件进行修改是不允许的,Windows通过这种方式来保证不同进程的隔离性:
而SQL Server中,通过SQL SERVER对数据库文件进行管理,从而可以让多个进程可以同时访问数据库:
SQL Server利用加锁和阻塞来保证事务之间不同等级的隔离性.
一般情况下,完全的隔离性是不现实的,完全的隔离性要求数据库同一时间只执行一条事务,这样的性能可想而知.想要理解SQL Server中对于隔离性的保障,首先要了解事务之间是如何干扰的.
事务之间的互相影响的情况分为几种,分别为:脏读(Dirty Read),不可重复读,幻读
脏读
脏读意味着一个事务读取了另一个事务未提交的数据,而这个数据是有可能回滚的:
下面来看一个例子:
两个事务,事务A插入一条数据,但未提交,事务B在此期间进行了读取,读取到了事务A未提交的数据,造成脏读
不可重复读(Unrepeatable Read)
不可重复读意味着,在数据库访问中,一个事务范围内两个相同的查询却返回了不同数据。这是由于查询时系统中其他事务修改的提交而引起的。
下面来看一个不可重复读的例子:
事务B中对某个查询执行两次,当第一次执行完时,事务A对其数据进行了修改。事务B中再次查询时,数据发生了改变:
幻读(phantom read)
幻读,是指当事务不是独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。同时,第二个事务也修改这 个表中的数据,这种修改是向表中插入一行新数据。那么,以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行,就好象发生了幻觉一样.
下面来看一个例子:
事务B更新表中所有的数据,在此期间事务A插入了一条数据,事务B再次查询后,发现居然还有没有修改的数据,产生幻读:
理解SQL SERVER中的隔离级别
为 了避免上述几种事务之间的影响,SQL Server通过设置不同的隔离等级来进行不同程度的避免。因为高的隔离等级意味着更多的锁,从而牺牲性能.所以这个选项开放给了用户根据具体的需求进行 设置。不过默认的隔离等级Read Commited符合了99%的实际需求.
SQL Server隔离事务之间的影响是通过锁来实现的,这个概念比较繁杂,所以本文不会详细对这个概念进行讲解.通过阻塞来阻止上述效果
SQL Server提供了5种选项来避免不同级别的事务之间的影响
隔离等级由低到高分别为
Read Uncommited(最高的性能,但可能出现脏读,不可重复读,幻读)
Read commited(可能出现不可重复读,幻读)
Repeatable Read(可能出现幻读)
Serializable(最低的性能,一次只能执行一个事务,但避免了上述所有情况)
SNOPSHOT(这个是通过在tempDB中创建一个额外的副本来避免脏读,不可重复读,会给tempDB造成额外负担,因为不是标准ANSI SQL标准,不详细讨论)
总之,不同的隔离级别是通过加不同的锁,造成阻塞来实现的,来看一个例子:
SQL SERVER通过阻塞来阻止脏读,所以保持独立性会以付出性能作为代价:
理解持久性(Durability)
持久性,意味着在事务完成以后,该事务所对数据库所作的更改便持久的保存在数据库之中,并不会被回滚。
即使出现了任何事故比如断电等,事务一旦提交,则持久化保存在数据库中.
SQL SERVER通过write-ahead transaction log来保证持久性。write-ahead transaction log的意思是,事务中对数据库的改变在写入到数据库之前,首先写入到事务日志中。而事务日志是按照顺序排号的(LSN)。当数据库崩溃或者服务器断点 时,重启动SQL SERVER,SQL SERVER首先会检查日志顺序号,将本应对数据库做更改而未做的部分持久化到数据库,从而保证了持久性.
本文简单讲述了ACID的概念和ACID在SQL SERVER中的实现.ACID只是一个理念,并不是某项具体的技术.对于健壮数据库来说,保证ACID是可靠数据库的前提.
[转载]SQL SERVER2008存储过程调试 – 冷酒少 – 博客园.
昨天被问到SQL server中存储过程怎么调试,我以前写存储过程,调试方法很笨拙,就是逐条执行语句,然后查看结果是不是预期的,这种调试方法,实在是无奈之举,极大 程度地限制了开发速度和准确性。今天在他的提点下,研究了下SQL SERVER 2008的存储过程调试。
1.在SQL SERVER2008中调试存储过程
以下内容引自MSDN
SQL SERVER 2008的SSMS是支持单步Debug的,但是在调试之前必须配置权限。
如果 SQL Server Management Studio 与 SQL Server 数据库引擎实例在同一台计算机上运行,则对于运行 Transact-SQL 调试器没有配置要求。但是,当 SQL Server Management Studio 与数据库引擎实例在不同计算机上运行时,若要运行 Transact-SQL 调试器,则必须在两台计算机上使用“Windows 防火墙”控制面板应用程序来启用程序和端口例外。
在运行数据库引擎实例的计算机上,在“Windows 防火墙”中指定以下信息:
在运行 SQL Server Management Studio 的计算机上,在“Windows 防火墙”中指定以下信息:
我们建议在测试服务器上调试 Transact-SQL 代码,而不要在生产服务器上调试,原因如下:
启动 Transact-SQL 调试器可将查询编辑器窗口置于调试模式。在查询编辑器窗口进入调试模式时,调试器会在第一个代码行处暂停。然后,您可以单步执行代码,在特定 Transact-SQL 语句上暂停执行,并使用调试器窗口来查看当前执行状态。可以通过在“查询”工具栏上单击“调试”按钮,或在“调试”菜单上单击“启动调试”来启动调试器。
查询编辑器窗口会保持在调试模式下,直到查询编辑器窗口中的最后一个语句完成或您停止调试模式。可以使用以下任何一种方法来停止调试模式和语句执行:
也可在“调试”菜单上单击“全部分离”,以停止调试模式,但允许剩余的 Transact-SQL 语句完成执行。
原文http://msdn.microsoft.com/zh-cn/library/cc646024(v=SQL.100).aspx
2.在Visual Studio中调试存储过程(以VS2010为例)
打开服务器资源管理器,添加一个SQL SERVER 2008数据库连接,然后在存储过程节点上点右键,选择“单步执行存储过程”,即可进入单步调试状态,同上边过程,也要设置权限。