面试自我介绍:
好的,谢谢,我叫王业鑫,来自于河南,于2010年毕业于河南理工,目前从事.Net开发已经有差不多五年工作经验了。我的第一家就职公司叫Edoc2,主要是为企业做OA文档管理系统和工作流,前两年我在项目部,主要职责是项目开发,我所做的主要项目是上海百视通,新城股,浙江台州联化科技,上海电缆研究所,这些项目都取得了成功,并且目前和公司还保持这合作关系,为公司带来了长久的经济利益,其中这里面有三个项目是我核心参与或带领团队负责去开发的,因为经常和客户,实施顾问,项目经理等一起商讨需求即计划的制定即排期,让我在带领团队方面积累了一些经验。后期基于个人对技术的兴趣,就和公司领导层商讨,最终决定让我进研发部,从事产品研发的相关工作。在研发部这段期间,我做了两个产品,分别是ISO文控管理系统,PDMS项目管理系统…
常见的面试题
高级开发面试题
多线程
页的生命周期
页请求:编译页
开始:设置页的Response Request
页初始化:
加载:
验证:
回发事件处理:
呈现
卸载
理解MVC原理,理解MVC的一些使用技巧
asp.net Web Form MVC 区别
.net 运行原理
Iis怎么运行asp.net
GC内存回收 标记压缩算法 分代算法 cmd.Dispose();
类,抽象类,借口区别
类继承类
可实现多态
抽象类
1> 抽象类中可以定义字段,并赋值
2> 抽象类中可以定义属性
3> 抽象类中可以包含非抽象方法
4> 抽象类中可以包含抽象方法,但继承是必须事项抽象类中的所有抽象方法,否则编译不通过。
5> 抽象类不能实例化,抽象类不能用sealed来修饰
6> 抽象类中可以有需方法(virtual),子类集成抽象类还是用override 重写该方法
7> 子类集成抽象类后,实现抽象方法用override
8> 子类具有和基类相同的方法,可以(建议)加个new,隐藏基类成员,但是不是强制行要加,调用基类成员用base
多态
设计模式
状态模式 允许一个对象在其内部状态改变时改变他的行为,好像是修改子类。
策略模式 实现统一接口,子类不同;
观察者模式 委托事件的实现
简单工厂模式
抽象工厂模式
单例工厂模式 对象仅有一个实例,再就是提供一全局访问点。
适配器模式,装饰着模式 都是对借口的在封装
原型模式 对象的拷贝
单一性原则,开放封闭原则,里氏替换原则,依赖倒置,借口隔离原则,最少知识原则,合成复用原则;
地址:http://www.cnblogs.com/yexinw/p/4115498.html
开发过程中使用好的规范
常用IOC框架汇总及性能总结
拷贝操作(深拷贝和浅拷贝)
委托事件原理及用途
性能优化
前端
- 1. 添加 Expires 或 Cache-Control 信息头
- 压缩内容
- Cookie精简,javascripts压缩合并,css压缩合并
- 静态文件 单独子域名
- 把CSS放到代码上端,JS放到页面下端
- 避免CSS表达式
- 压缩图片,合并多个图片到一张图上,使用css background position定位
- 减少请求
- 9. 减少空图片连接,用更小的并且可缓存的 favicon.ico
- 10. 负载均衡
- 11. CDN
- 杜绝404
服务端
数据库
电商流程
数据库常见SQL
CSS
Javascripts
Ajax
ansych
指数表示法 var test = 2e3; //2*10*10*10
转义字符 var test = 'aa bb';
工作流
流程设计 有点类似于viso流程图,
组织架构
流程日志监控
单元测试
.Net 运行过程
代码编译成DLL==》编译的DLL为中间语言MSIL==》MSIL运行在 .Net Framework 上下文中;
比较IIS5、IIS6、IIS7的ASP.net请求处理过程
www.educity.cn 发布者:cszw12302 来源:网络转载 发布日期:2013年10月28日 文章评论 发表文章
SP.NET是一个非常强大的构建Web应用的平台,它提供了极大的灵活性和能力以致于可以用它来构建所有类型的Web应用。
绝大多数的人只熟悉高层的框架如:
WebForms 和 WebServices --这些都在ASP.NET层次结构在最高层。
这篇文章的资料收集整理自各种微软公开的文档,通过比较 IIS5、IIS6、IIS7 这三代 IIS 对请求的处理过程, 让我们熟悉 ASP.NET的底层机制 并对请求(request)是怎么从Web服务器传送到ASP.NET运行时有所了解。通过对底层机制的了解,可以让我们对 有更深的理解。
IIS 5 的 请求处理过程
|
IIS 5的请求处理过程 |
对图的解释:
IIS 5.x 一个显著的特征就是 Web Server 和真正的 ASP.NET Application 的分离。作为 Web Server 的IIS运行在一个名为 InetInfo.exe 的进程上,InetInfo.exe 是一个Native Executive,并不是一个托管的程序,而我们真正的 ASP.NET Application 则是运行在一个叫做 aspnet_wp 的 Worker Process 上面,在该进程初始化的时候会加载CLR,所以这是一个托管的环境。
ISAPI: 指能够处理各种后缀名的应用程序。 ISAPI 是下面单词的简写 :Internet Server Application Programe Interface,互联网服务器应用程序接口。
IIS 5 模式的特点:
1、首先,同一台主机上在同一时间只能运行一个 aspnet_wp 进程,每个基于虚拟目录的 ASP.NET Application 对应一个 Application Domain
,也就是说每个 Application 都运行在同一个
Worker Process 中,Application之间的隔离是基于 Application Domain 的,而不是基于Process的。
2、其 次,ASP.NET ISAPI 不但负责创建 aspnet_wp Worker Process,而且负责监控该进程,如果检测到
aspnet_wp 的 Performance 降低到某个设定的下限,ASP.NET ISAPI 会负责结束掉该进程。当 aspnet_wp 结束掉之后,后续的 Request 会导致ASP.NET ISAPI 重新创建新的 aspnet_wp Worker Process.
3、最后,由于 IIS 和 Application 运行在他们各自的进程中,他们之间的通信必须采用特定的通信机制。本质上 IIS 所在的 InetInfo 进程和 Worker Process 之间的通信是同一台机器不同进程的通信(local
interprocess communications),处于Performance的考虑,他们之间采用基于Named pipe的通信机制。ASP.NET ISAPI和Worker Process之间的通信通过他们之间的一组Pipe实现。同样处于Performance的原因,ASP.NET ISAPI 通过异步的方式将Request 传到Worker Process 并获得 Response,但是 Worker Process 则是通过同步的方式向 ASP.NET ISAPI 获得一些基于 Server 的变量。
IIS6 的 请求处理过程
|
IIS6 的 请求处理过程 |
对图的解释:
IIS 5.x 是通过 InetInfo.exe 监听 Request 并把Request分发到Work Process.换句话说,在IIS 5.x中对Request的监听和分发是在User Mode中进行,在IIS 6中,这种工作被移植到kernel Mode中进行,所有的这一切都是通过一个新的组件:http.sys 来负责。
注:为了避 免用户应用程序访问或者修改关键的操作系统数据,windows提供了两种处理器访问模式:用户模式(User Mode)和内核模式(Kernel Mode)。一般地,用户程序运行在User mode下,而操作系统代码运行在Kernel Mode下。Kernel Mode的代码允许访问所有系统内存和所有CPU指令。
在User Mode下,http.sys接收到一个基于 aspx 的http request,然后它会根据IIS中的 Metabase 查看该基于该 Request 的 Application 属于哪个Application Pool, 如果该Application Pool不存在,则创建之。否则直接将 request 发到对应Application Pool 的 Queue中。
每个 Application Pool 对应着一个Worker
Process:w3wp.exe,毫无疑问他是运行在User
Mode下的。在IIS Metabase 中维护着
Application Pool 和worker process的Mapping.WAS(Web Administrative service)根据这样一个mapping,将存在于某个Application Pool Queue的request 传递到对应的worker process(如果没有,就创建这样一个进程)。在 worker process 初始化的时候,加载ASP.NET ISAPI,ASP.NET ISAPI 进而加载CLR.最后的流程就和IIS 5.x一样了:通过AppManagerAppDomainFactory 的 Create方法为 Application 创建一个Application Domain;通过 ISAPIRuntime 的 ProcessRequest处理Request,进而将流程进入到ASP.NET Http Runtime Pipeline.
IIS 7 的 请求处理过程
IIS7 站点启动并处理请求的步骤如下图:
步骤 1 到 6 ,是处理应用启动,启动好后,以后就不需要再走这个步骤了。
|
IIS 7 的 请求处理过程 |
上图的8个步骤分别如下:
1、当客户端浏览器开始HTTP 请求一个WEB 服务器的资源时,HTTP.sys 拦截到这个请求。
2、HTTP.sys contacts WAS to obtain information from the
configuration store.
3、WAS 向配置存储中心请求配置信息。nfig。
4、WWW 服务接受到配置信息,配置信息指类似应用程序池配置信息,站点配置信息等等。
5、WWW 服务使用配置信息去配置 HTTP.sys 处理策略。
6、WAS starts a worker process for the application pool
to which the request was made.
7、The worker process processes the request and returns a response to HTTP.sys.
8、客户端接受到处理结果信息。
W3WP.exe 进程中又是如果处理得呢?? IIS 7 的应用程序池的托管管道模式分两种: 经典和集成。 这两种模式下处理策略各不相通。
IIS 6 以及 IIS7 经典模式的托管管道的架构
在IIS7之前,ASP.NET 是以 IIS ISAPI extension 的方式外加到 IIS,其实包括 ASP 以及 PHP,也都以相同的方式配置(PHP 在 IIS 采用了两种配置方式,除了 IIS ISAPI extension 的方式,也包括了 CGI 的方式,系统管理者能选择 PHP 程序的执行方式),因此客户端对 IIS 的 HTTP 请求会先经由 IIS 处理,然后 IIS 根据要求的内容类型,如果是 HTML 静态网页就由 IIS 自行处理,如果不是,就根据要求的内容类型,分派给各自的 IIS ISAPI extension;如果要求的内容类型是 ASP.NET,就分派给负责处理 ASP.NET 的 IIS ISAPI extension,也就是 aspnet_isapi.dll。下图是这个架构的示意图。
|
IIS6 的执行架构图,以及IIS7应用程序池配置成经典模式的执行架构图 |
IIS7 应用程序池的 托管管道模式 经典 模式也是这样的工作原理。 这种模式是兼容IIS 6 的方式, 以减少升级的成本。
IIS 7 应用程序池的 托管管道模式 集成模式
|
IIS 7 的执行架构图(集成托管信道模式下的架构) |
小结
IIS5 到 IIS6 的改进,主要是 HTTP.sys 的改进。
IIS6 到 IIS7 的改进,主要是 ISAPI 的改进。
请求不同
WebForm
页面是继承了IHttpHandler的一个类,最后执行ProcessRequest()方法
WebForm无法把客户端编程和服务端编程混在一起,无法精确控制页面的元素,但是在.net 中得到了改善。
用webform,就需要大量的去维护控件的viewstate,和生命周期
因此 ASP.NET 将不会对 .htm 文件请求执行身份验证或授权检查,但IIS 集成模式是可以的;
Asp.Net MVC
- RouteTable 添加映射规则
- 所有请求 URLRoutingModule 拦截
- Module包装好的HttpContext 传到RouteTable
- 如果在当前请求和路由表中的路由对象之间能找到匹配,就会返回路由对象
- module然后实例化基于routetable的新httphandler,并且把routecontext传给handler的构造函数
- module进行的最后一步就是把mvchandler设置为当前的htpp handler。
- asp.net应用程序自动调用当前http handler的processrequest()
问题1:什么是HttpHandler?
问题2:什么是HttpModule?
问题3:什么时候应该使用HttpHandler什么时候使用HttpModule?
答案1:HttpHandler,Http请求的处理者,例如ScriptHandler、WebServiceHandler,IHttpHandler的实现都是为了处理某一类的请求。如ScriptHandler负责处理对脚本的请求。
答案2:HttpModule,Http模块。实际上就是那19个标准事件的处理者,或者说19个标准事件的订阅者,比如OutputCacheModule,SessionStateModule。详细可以到在这篇文章里面看到http://www.cnblogs.com/kissdodog/p/3527922.html。
一、HttpHandler的职责
1、由于HTTP请求有很多种请求类型,比如请求aspx、html、jpg等等。因此,仅仅由HttpApplication直接处理请求时 很臃肿的,而且不利于扩展。因此Asp.net采用了抽象工厂模式来处理这些请求。Asp.net在web.config的架构中,允许我们制定某些请求 映射到一个HttpHandlerFactory。
<!--适用于IIS6的配置-->
<system.web>
<httpHandlers>
<add path="*.aspx" verb="*" type="MyMVC.MvcPageHandlerFactory, MyMVC" validate="true" />
</httpHandlers>
</system.web>
<!--适用于IIS7的配置(集成模式)-->
<system.webServer>
<handlers>
<add name="MvcPageHandlerFactory" verb="*" path="*.aspx" type="MyMVC.MvcPageHandlerFactory, MyMVC" preCondition="integratedMode" />
</handlers>
</system.webServer>
所以,我们应该这样理解HttpHanlder:一个HttpHanlder用于响应一类的请求,为一类的请求生成响应结果。
我们经常用到的HttpHanlder有哪些?
1. aspx页面。
2. asmx服务文件。
3. ashx文件(一般处理程序)。
4. 实现IHttpHandler接口的自定义类型。
我们通常使用HttpHanlder做什么?
HttpHanlder类型 |
实现目标 |
aspx页面 |
响应aspx的请求,输出HTML结果 |
asmx服务文件 |
响应服务调用 |
ashx文件(一般处理程序) |
实现简单的AJAX响应 |
实现IHttpHandler接口的自定义类 |
响应什么扩展名的请求? |
二、HttpModule的职责
有时候有些页面需要一些相同的检查功能,比如身份验证。明显使用HttpHandler是不方便的,因为不是所有的页面都需要去调用那些相同的功能。
HttpModule 的设计正是提供了一个灵活的方法解决这种功能重用的问题,它采用事件(观察者)的设计模式,将某些HttpHandler都需要的功能抽取出来,形成不同 的观察者类型,这些观察者类型可以编译成类库形式,供多个网站共用。为了让ASP.NET管线更灵活,ASP.NET允许我们再web.config中自 由配置需要的HttpModule。
<!--适用于IIS6的配置-->
<system.web>
<httpModules>
<add name="SetOutputCacheModule" type="MyMVC.SetOutputCacheModule, MyMVC"/>
</httpModules>
</system.web>
<!--适用于IIS7的配置(集成模式)-->
<system.webServer>
<modules>
<add name="SetOutputCacheModule" type="MyMVC.SetOutputCacheModule, MyMVC" preCondition="integratedMode" />
</modules>
</system.webServer>
配置只是告诉ASP.NET,这些HttpModule需要运行起来,可能会用得着。
我们用HttpModule做什么事情?
1. 修改某些请求(例如前面的示例修改了响应头)。
2. 检查检查请求(例如身份认证检查)。
HttpModule能处理哪些请求呢?
1. 默认是全部进入ASP.NET的请求。
2. 如果只需要处理部分请求,那么请自行判断。
三、总结
HttpHandler相当于一条水管,HttpModule相当于一小节水管。HttpHandler有很多条,一条流油,一条流水等等。HttpModule相当于一小截,需要过滤的长水管里面都可以装上。
SQL Server中解决死锁的新方法介绍
数据库操作的死锁是不可避免的,本文并不打算讨论死锁如何产生,重点在于解决死锁,通过SQL Server 2005, 现在似乎有了一种新的解决办法。
将下面的SQL语句放在两个不同的连接里面,并且在5秒内同时执行,将会发生死锁。
use Northwindbegin tran insert into Orders(CustomerId) values(@#ALFKI@#) waitfor delay @#00:00:05@# select * from Orders where CustomerId = @#ALFKI@#commitprint @#end tran@# |
SQL Server对付死锁的办法是牺牲掉其中的一个,抛出异常,并且回滚事务。在SQL Server 2000,语句一旦发生异常,T-SQL将不会继续运行,上面被牺牲的连接中, print @#end tran@#语句将不会被运行,所以我们很难在SQL Server 2000的T-SQL中对死锁进行进一步的处理。
现在不同了,SQL Server 2005可以在T-SQL中对异常进行捕获,这样就给我们提供了一条处理死锁的途径:
下面利用的try ... catch来解决死锁。
SET XACT_ABORT ONdeclare @r intset @r = 1while @r <= 3begin begin tran begin try insert into Orders(CustomerId) values(@#ALFKI@#) waitfor delay @#00:00:05@# select * from Orders where CustomerId = @#ALFKI@# commit break end try begin catch rollback waitfor delay @#00:00:03@# set @r = @r + 1 continue end catchend |
解决方法当然就是重试,但捕获错误是前提。rollback后面的waitfor不可少,发生冲突后需要等待一段时间,@retry数目可以调整以应付不同的要求。
但是现在又面临一个新的问题: 错误被掩盖了,一但问题发生并且超过3次,异常却不会被抛出。SQL Server 2005 有一个RaiseError语句,可以抛出异常,但却不能直接抛出原来的异常,所以需要重新定义发生的错误,现在,解决方案变成了这样:
declare @r intset @r = 1while @r <= 3begin begin tran begin try insert into Orders(CustomerId) values(@#ALFKI@#) waitfor delay @#00:00:05@# select * from Orders where CustomerId = @#ALFKI@# commit break end try begin catch rollback waitfor delay @#00:00:03@# set @r = @r + 1 continue end catchendif ERROR_NUMBER() <> 0begin declare @ErrorMessage nvarchar(4000); declare @ErrorSeverity int; declare @ErrorState int; select @ErrorMessage = ERROR_MESSAGE(), @ErrorSeverity = ERROR_SEVERITY(), @ErrorState = ERROR_STATE(); raiserror (@ErrorMessage, @ErrorSeverity, @ErrorState );end |
我希望将来SQL Server 2005能够直接抛出原有异常,比如提供一个无参数的RaiseError。
因此方案有点臃肿,但将死锁问题封装到T-SQL中有助于明确职责,提高高层系统的清晰度。现在,对于DataAccess的代码,或许再也不需要考虑死锁问题了
========================================================================
SQL Server2000中死锁经验总结
虽然不能完全避免死锁,但可以使死锁的数量减至最少。将死锁减至最少可以增加事务的吞吐量并减少系统开销,因为只有很少的事务:
- 回滚,而回滚会取消事务执行的所有工作。
- 由于死锁时回滚而由应用程序重新提交。
下列方法有助于最大限度地降低死锁:
- 按同一顺序访问对象。
- 避免事务中的用户交互。
- 保持事务简短并在一个批处理中。
- 使用低隔离级别。
- 使用绑定连接。
按同一顺序访问对象
如果所有并发事务按同一顺序访问对象,则发生死锁的可能性会降低。例如,如果两个并发事务获得 Supplier 表上的锁,然后获得 Part 表上的锁,则在其中一个事务完成之前,另一个事务被阻塞在 Supplier 表上。第一个事务提交或回滚后,第二个事务继续进行。不发生死锁。将存储过程用于所有的数据修改可以标准化访问对象的顺序。
避免事务中的用户交互
避 免编写包含用户交互的事务,因为运行没有用户交互的批处理的速度要远远快于用户手动响应查询的速度,例如答复应用程序请求参数的提示。例如,如果事务正在 等待用户输入,而用户去吃午餐了或者甚至回家过周末了,则用户将此事务挂起使之不能完成。这样将降低系统的吞吐量,因为事务持有的任何锁只有在事务提交或 回滚时才会释放。即使不出现死锁的情况,访问同一资源的其它事务也会被阻塞,等待该事务完成。
保持事务简短并在一个批处理中
在同一数据库中并发执行多个需要长时间运行的事务时通常发生死锁。事务运行时间越长,其持有排它锁或更新锁的时间也就越长,从而堵塞了其它活动并可能导致死锁。
保持事务在一个批处理中,可以最小化事务的网络通信往返量,减少完成事务可能的延迟并释放锁。
使用低隔离级别
确定事务是否能在更低的隔离级别上运行。执行提交读允许事务读取另一个事务已读取(未修改)的数据,而不必等待第一个事务完成。使用较低的隔离级别(例如提交读)而不使用较高的隔离级别(例如可串行读)可以缩短持有共享锁的时间,从而降低了锁定争夺。
使用绑定连接
使用绑定连接使同一应用程序所打开的两个或多个连接可以相互合作。次级连接所获得的任何锁可以象由主连接获得的锁那样持有,反之亦然,因此不会相互阻塞
检测死锁
如果发生死锁了,我们怎么去检测具体发生死锁的是哪条SQL语句或存储过程?
这时我们可以使用以下存储过程来检测,就可以查出引起死锁的进程和SQL语句。SQL Server自带的系统存储过程sp_who和sp_lock也可以用来查找阻塞和死锁, 但没有这里介绍的方法好用。
use master
go
create procedure sp_who_lock
as
begin
declare @spid int,@bl int,
@intTransactionCountOnEntry int,
@intRowcount int,
@intCountProperties int,
@intCounter int
create table #tmp_lock_who (
id int identity(1,1),
spid smallint,
bl smallint)
IF @@ERROR<>0 RETURN @@ERROR
insert into #tmp_lock_who(spid,bl) select 0 ,blocked
from (select * from sysprocesses where blocked>0 ) a
where not exists(select * from (select * from sysprocesses where blocked>0 ) b
where a.blocked=spid)
union select spid,blocked from sysprocesses where blocked>0
IF @@ERROR<>0 RETURN @@ERROR
-- 找到临时表的记录数
select @intCountProperties = Count(*),@intCounter = 1
from #tmp_lock_who
IF @@ERROR<>0 RETURN @@ERROR
if @intCountProperties=0
select '现在没有阻塞和死锁信息' as message
-- 循环开始
while @intCounter <= @intCountProperties
begin
-- 取第一条记录
select @spid = spid,@bl = bl
from #tmp_lock_who where Id = @intCounter
begin
if @spid =0
select '引起数据库死锁的是: '+ CAST(@bl AS VARCHAR(10)) + '进程号,其执行的SQL语法如下'
else
select '进程号SPID:'+ CAST(@spid AS VARCHAR(10))+ '被' + '进程号SPID:'+ CAST(@bl AS VARCHAR(10)) +'阻塞,其当前进程执行的SQL语法如下'
DBCC INPUTBUFFER (@bl )
end
-- 循环指针下移
set @intCounter = @intCounter + 1
end
drop table #tmp_lock_who
return 0
end
杀死锁和进程
如何去手动的杀死进程和锁?最简单的办法,重新启动服务。但是这里要介绍一个存储过程,通过显式的调用,可以杀死进程和锁。
use master
go
if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[p_killspid]') and OBJECTPROPERTY(id, N'IsProcedure') = 1)
drop procedure [dbo].[p_killspid]
GO
create proc p_killspid
@dbname varchar(200) --要关闭进程的数据库名
as
declare @sql nvarchar(500)
declare @spid nvarchar(20)
declare #tb cursor for
select spid=cast(spid as varchar(20)) from master..sysprocesses where dbid=db_id(@dbname)
open #tb
fetch next from #tb into @spid
while @@fetch_status=0
begin
exec('kill '+@spid)
fetch next from #tb into @spid
end
close #tb
deallocate #tb
go
--用法
exec p_killspid 'newdbpy'
查看锁信息
如何查看系统中所有锁的详细信息?在企业管理管理器中,我们可以看到一些进程和锁的信息,这里介绍另外一种方法。
--查看锁信息
create table #t(req_spid int,obj_name sysname)
declare @s nvarchar(4000)
,@rid int,@dbname sysname,@id int,@objname sysname
declare tb cursor for
select distinct req_spid,dbname=db_name(rsc_dbid),rsc_objid
from master..syslockinfo where rsc_type in(4,5)
open tb
fetch next from tb into @rid,@dbname,@id
while @@fetch_status=0
begin
set @s='select @objname=name from ['+@dbname+']..sysobjects where id=@id'
exec sp_executesql @s,N'@objname sysname out,@id int',@objname out,@id
insert into #t values(@rid,@objname)
fetch next from tb into @rid,@dbname,@id
end
close tb
deallocate tb
select 进程id=a.req_spid
,数据库=db_name(rsc_dbid)
,类型=case rsc_type when 1 then 'NULL 资源(未使用)'
when 2 then '数据库'
when 3 then '文件'
when 4 then '索引'
when 5 then '表'
when 6 then '页'
when 7 then '键'
when 8 then '扩展盘区'
when 9 then 'RID(行 ID)'
when 10 then '应用程序'
end
,对象id=rsc_objid
,对象名=b.obj_name
,rsc_indid
from master..syslockinfo a left join #t b on a.req_spid=b.req_spid
go
drop table #t
总结
虽然不能完全避免死锁,但我们可以将死锁减至最少,并通过一定的方法来检测死锁。
-------------------------------------------------------------------------------------------------
SQL Server死锁的分析
SQL Server数据库发生死锁时不会像ORACLE那样自动生成一个跟踪文件。有时可以在[管理]->[当前活动] 里看到阻塞信息(有时SQL Server企业管理器会因为锁太多而没有响应).
设定跟踪1204:
USE MASTER
DBCC TRACEON (1204,-1)
显示当前启用的所有跟踪标记的状态:
DBCC TRACESTATUS(-1)
取消跟踪1204:
DBCC TRACEOFF (1204,-1)
在设定跟踪1204后,会在数据库的日志文件里显示SQL Server数据库死锁时一些信息。但那些信息很难看懂,需要对照SQL Server联机丛书仔细来看。根据PAG锁要找到相关数据库表的方法:
DBCC TRACEON (3604)
DBCC PAGE (db_id,file_id,page_no)
DBCC TRACEOFF (3604)
请参考sqlservercentral.com上更详细的讲解.但又从CSDN学到了一个找到死锁原因的方法。我稍加修改, 去掉了游标操作并增加了一些提示信息,写了一个系统存储过程sp_who_lock.sql。代码如下:
if exists (select * from dbo.sysobjects
where id = object_id(N'[dbo].[sp_who_lock]')
and OBJECTPROPERTY(id, N'IsProcedure') = 1)
drop procedure [dbo].[sp_who_lock]
GO
/********************************************************
// 学习到并改写
// 说明 : 查看数据库里阻塞和死锁情况
********************************************************/
use master
go
create procedure sp_who_lock
as
begin
declare @spid int,@bl int,
@intTransactionCountOnEntry int,
@intRowcount
int,
@intCountProperties int,
@intCounter
int
create table #tmp_lock_who (
id int
identity(1,1),
spid smallint,
bl smallint)
IF @@ERROR<>0 RETURN @@ERROR
insert into #tmp_lock_who(spid,bl) select 0 ,blocked
from (select * from sysprocesses where blocked>0 ) a
where not exists(select * from (select * from sysprocesses
where blocked>0 ) b
where a.blocked=spid)
union select spid,blocked from sysprocesses where blocked>0
IF @@ERROR<>0 RETURN @@ERROR
-- 找到临时表的记录数
select @intCountProperties = Count(*),@intCounter = 1
from #tmp_lock_who
IF @@ERROR<>0 RETURN @@ERROR
if @intCountProperties=0
select '现在没有阻塞和死锁信息' as message
-- 循环开始
while @intCounter <= @intCountProperties
begin
-- 取第一条记录
select @spid = spid,@bl = bl
from #tmp_lock_who where Id = @intCounter
begin
if @spid =0
select '引起数据库死锁的是: '+ CAST(@bl AS VARCHAR(10))
+ '进程号,其执行的SQL语法如下'
else
select '进程号SPID:'+ CAST(@spid AS VARCHAR(10))+ '被'
+ '进程号SPID:'+ CAST(@bl AS
VARCHAR(10)) +'阻塞,其当前进程执行的SQL语法如下'
DBCC INPUTBUFFER (@bl )
end
-- 循环指针下移
set @intCounter = @intCounter + 1
end
drop table #tmp_lock_who
return 0
end
需要的时候直接调用:
sp_who_lock
就可以查出引起死锁的进程和SQL语句.
SQL Server自带的系统存储过程sp_who和sp_lock也可以用来查找阻塞和死锁, 但没有这里介绍的方法好用。如果想知道其它tracenum参数的含义,请看http://www.sqlservercentral.com/文章
我们还可以设置锁的超时时间(单位是毫秒), 来缩短死锁可能影响的时间范围:
例如:
use master
seelct @@lock_timeout
set lock_timeout
900000
-- 15分钟
seelct @@lock_timeout
其实所有的死锁最深层的原因就是一个:资源竞争
表现一:
一个用户A 访问表A(锁住了表A),然后又访问表B
另一个用户B 访问表B(锁住了表B),然后企图访问表A
这时用户A由于用户B已经锁住表B,它必须等待用户B释放表B,才能继续,好了他老人家就只好老老实实在这等了
同样用户B要等用户A释放表A才能继续这就死锁了
解决方法:
这种死锁是由于你的程序的BUG产生的,除了调整你的程序的逻辑别无他法
仔细分析你程序的逻辑,
1:尽量避免同时锁定两个资源
2: 必须同时锁定两个资源时,要保证在任何时刻都应该按照相同的顺序来锁定资源.
表现二:
用户A读一条纪录,然后修改该条纪录
这是用户B修改该条纪录
这里用户A的事务里锁的性质由共享锁企图上升到独占锁(for
update),而用户B里的独占锁由于A有共享锁存在所以必须等A释
放掉共享锁,而A由于B的独占锁而无法上升的独占锁也就不可能释放共享锁,于是出现了死锁。
这种死锁比较隐蔽,但其实在稍大点的项目中经常发生。
解决方法:
让用户A的事务(即先读后写类型的操作),在select 时就是用Update lock
语法如下:
select * from table1 with(updlock) where ....
如何将数据库中被锁表解锁
作者:佚名 文章来源:未知
点击数:106 更新时间:2005-12-25
我 们在操作数据库的时候,有时候会由于操作不当引起数据库表被锁定,这么我们经常不知所措,不知怎么给这些表解锁,在pl/sql Developer工具的的菜单“tools”里面的“sessions”可以查询现在存在的会话,但是我们很难找到那个会话被锁定了,想找到所以被锁的 会话就更难了,下面这叫查询语句可以查询出所以被锁的会话。如下:
SELECT
sn.username, m.SID,sn.SERIAL#, m.TYPE,
DECODE (m.lmode,
0, 'None',
1, 'Null',
2, 'Row Share',
3, 'Row Excl.',
4, 'Share',
5, 'S/Row Excl.',
6, 'Exclusive',
lmode, LTRIM (TO_CHAR (lmode, '990'))
) lmode,
DECODE (m.request,
0, 'None',
1, 'Null',
2, 'Row Share',
3, 'Row Excl.',
4, 'Share',
5, 'S/Row Excl.',
6, 'Exclusive',
request, LTRIM (TO_CHAR (m.request, '990'))
) request,
m.id1, m.id2
FROM v$session sn, v$lock m
WHERE
(sn.SID = m.SID AND m.request !=
0) --存在锁请求,即被阻塞
OR ( sn.SID =
m.SID
--不存在锁请求,但是锁定的对象被其他会话请求锁定
AND m.request = 0
AND lmode != 4
AND (id1, id2) IN (
SELECT s.id1, s.id2
FROM v$lock s
WHERE request != 0 AND s.id1 = m.id1
AND s.id2 = m.id2)
)
ORDER BY id1, id2,
m.request;
通过以上查询知道了sid和 SERIAL#就可以开杀了
alter
system kill session 'sid,SERIAL#';