[ASP.NET]ASP.NET底层的初步认识与理解

mikel阅读(419)

最近在国外的网站乱走一通,发现一些比较好的文章,收集整理加于自己的理解,作为笔记形式记录下来,让以后自己有个回忆。

ASP.NET是一个非常强大的构建Web应用的平台,它提供了极大的灵活性和能力以致于可以用它来构建所有类型的Web应用.绝大多数的人只熟悉 高层的框架如WebForms和WebServices-这些都在ASP.NET层次结构在最高层.在这篇文章中我将会讨论ASP.NET的底层机制并解 释请求(request)是怎么从Web服务器传送到ASP.NET运行时然后如何通过ASP.NET管道来处理请求.

ASP.NET是一个请求处理引擎.它接收一个发送过来的请求,把它传给内部的管道直到终点,作为一个开发人员的你可以在这里附加一些代码来处理请 求.这个引擎是和HTTP/Web服务器完全分隔的.事实上,HTTP运行时是一个组件,使你可以摆脱IIS或者任何其他的服务器程序,将你自己的程序寄 宿在内.

运行时提供了一个复杂但同时非常优雅的在管道中路由请求的机制.其中有很多相关的对象,大多数都是可扩展的(通过继承或者事件接口),在几乎所有的 处理流程上都是如此.所以这个框架具有高度可扩展性.通过这个机制,挂接到非常底层的接口(比如缓存,认证和授权)都变得可能了.你甚至可以在预处理或者 处理后过滤内容,也可以简单的将符合特殊标记的请求直接路由你的代码或者另一个URL上.存在着许多不同的方法来完成同一件事,但是所有这些方法都是可以 简单直接地实现的,同时还提供了灵活性,可以得到最好的性能和开发的简单性.

整个ASP.NET引擎是完全建立在托管代码上的,所有的扩展功能也是通过托管代码扩展来提供的.这是对.NET框架具有构建复杂而且高效的框架的 能力的最好的证明.ASP.NET最令人印象深刻的地方是深思熟虑的设计,使得框架非常的容易使用,又能提供挂接到请求处理的几乎所有部分的能力.

ASP.NET在微软的平台上就是通过ISAPI扩展来和IIS进行交互的,这个扩展寄宿着.NET运行时和ASP.NET运行时.ISAPI提供 了核心的接口,ASP.NET使用非托管的ISAPI代码通过这个接口来从Web服务器获取请求,并发送响应回客户端.ISAPI提供的内容可以通过通用 对象(例如HttpRequest和HttpResponse)来获取,这些对象通过一个定义良好并有很好访问性的接口来暴露非托管数据.

当用户发送一个URL请求时,在Web服务器端,IIS5或6,获得这个请求.在最底层,ASP.NET和IIS通过ISAPI扩展进行交互.在 ASP.NET环境中这个请求通常被路由到一个扩展名为.aspx的页面上,但是这个流程是怎么工作的完全依赖于处理特定扩展名的HTTP Handler是怎么实现的.在IIS中.aspx通过’应用程序扩展’(又称为脚本映射)被映射到ASP.NET的ISAPI扩展DLL- aspnet_isapi.dll.每一个请求都需要通过一个被注册到aspnet_isapi.dll的扩展名来触发ASP.NET(来处理这个请 求).

ISAPI是底层的非托管Win32 API.ISAPI定义的接口非常简单并且是为性能做了优化的.它们是非常底层的-处理指针和函数指针表来进行回调-但是它们提供了最底层和面向效率的接 口,使开发者和工具提供商可以用它来挂接到IIS上.因为ISAPI非常底层所以它并不适合来开发应用级的代码,而且ISAPI倾向于主要被用于桥接接 口,向上层工具提供应用服务器类型的功能.

下面来介绍HttpRuntime,HttpContext,HttpApplication

当一个请求到来时,它被路由到ISAPIRuntime.ProcessRequest()方法.这个方法调用HttpRuntime.ProcessRequest方法,它作一些重要的事情

为请求创建一个新的HttpContext实例
获取一个HttpApplication实例
调用HttpApplication.Init()方法来设置管道的事件
Init()方法触发开始ASP.NET管道处理的HttpApplication.ResumeProcessing()方法

首先一个新的HttpContext对象被创建并用来传递ISAPIWorkerRequest,这个上下文在整个请求的生命周期总都是可用的并总可以通过静态属性.
HttpContext.Currect 来访问.正像名字所暗示的那样,HttpContext对象代表了当前活动请求的上下文因为他包含了在请求生命周期中所有典型的你需要访问的重要对 象:Request,Response,Application,Server,Cache.在请求处理的任何时候 HttpContext.Current给你访问所有这些的能力.

HttpContext对象也包含一个非常有用的Items集合,你可以用它来保存针对特定请求的数据.上下文对象在请求周期的开始时被创建,在请 求结束时被释放,所有在Items集合中保存的数据只在这个特定的请求中可用.一个很好的使用的例子是请求日志机制,当你通过想通过在 Global.asax中挂接Application_BeginRequest和Application_EndRequest方法记录请求的开始和结 束时间(象在列表3中显示的那样).HttpContext对你就非常有用了-如果你在请求或页面处理的不同部分需要数据,你自由的使用它.

protected void Application_BeginRequest(Object sender, EventArgs e)
{
 if (App.Configuration.LogWebRequests)
 {
  Context.Items.Add("WebLog_StartTime",DateTime.Now);
 }
}

protected void Application_EndRequest(Object sender, EventArgs e)
{
 if (App.Configuration.LogWebRequests)
 {
  try
  { 
   TimeSpan Span = DateTime.Now.Subtract((DateTime) Context.Items["WebLog_StartTime"] );
   int MiliSecs = Span.TotalMilliseconds;
   WebRequestLog.Log(App.Configuration.ConnectionString, true, MilliSecs);
  } 
 }
}

HttpApplication

每个请求都被路由到一个HttpApplication对象上.HttpApplicationFactory类根据应用程序的负载为你的 ASP.NET应用创建一个HttpApplication对象池并为每个请求分发HttpApplication对象的引用.对象池的大小受 machine.config文件中ProcessModel键中的MaxWorkerThreads设置限制.
HttpApplication 是你的Web程序的外部包装器,而且它被映射到在Global.asax里面定义的类上.它是进入HttpRuntime的第一个入口点.如果你查看 Global.asax(或者对应的代码类)你会发现这个类直接继承自HttpApplication:
HttpApplication的主要职责是作为Http管道的事件控制器,所以它的接口主要包含的是事件.事件挂接是非常广泛的,大概包括以下这些:
BeginRequest
AuthenticateRequest
AuthorizeRequest
ResolveRequestCache
AquireRequestState
PreRequestHandlerExecute
PostRequestHandlerExecute
ReleaseRequestState
UpdateRequestCache
EndRequest

HttpModule和HttpHandler两者都是在HttpApplication.Init()函数调用的一部分中被载入并附加到调用链上

httpApplication它本身对发送给应用程序的数据一无所知-它只是一个通过事件来通讯的消息对象.它触发事件并通过 HttpContext对象来向被调用函数传递消息.实际的当前请求的状态数据由前面提到的HttpContext对象维护.它提供了所有请求专有的数据 并从进入管道开始到结束一直跟随请求

一旦管道被启动,HttpApplication开始象图六那样一个个的触发事件.每个事件处理器被触发,如果事件被挂接,这些处理器将执行它们自 己的任务.这个处理的主要任务是最终调用挂接到此特定请求的HttpHandler.处理器(handler)是ASP.NET请求的核心处理机制,通常 也是所有应用程序级别的代码被执行的地方.记住ASP.NET页面和Web服务框架都是作为HttpHandler实现,这里也是处理请求的的核心之处. 模块(module)趋向于成为一个传递给处理器(handler)的上下文的预处理或后处理器.ASP.NET中典型的默认处理器包括预处理的认证,缓 存以及后处理中各种不同的编码机制.

虽然HttpModule看上去很像ISAPI过滤器,它们都检查每个通过ASP.NET应用的请求,但是它们只检查映射到单个特定的 ASP.NET应用或虚拟目录的请求,也就是只能检查映射到ASP.NET的请求.这样你可以检查所有ASPX页面或者其他任何映射到ASP.NET的扩 展名.

实现一个HTTP模块是非常简单的:你必须实现之包含两个函数(Init()和Dispose())的IHttpModule接口.传进来的事件参 数中包含指向HTTPApplication对象的引用,这给了你访问HttpContext对象的能力.在这些方法上你可以挂接到 HttpApplication事件上.例如,如果你想挂接AuthenticateRequest事件到一个模块上

 

总的来说w3wp.exe调用.NET类库进行具体处理,顺序如下:ISAPIRuntim, HttpRuntime, HttpApplicationFactory, HttpApplication, HttpModule, HttpHandlerFactory, HttpHandler

有时间再对每个对象正进深入理解.

[C#]C# 4.0 新对象ExpandoObject

mikel阅读(425)

      今天无意中看了4.0的一些新特性,其中看到SystemDynamic 命名空间下的ExpandoObject 类很感兴趣,看了篇英文文章给大伙分享下。

先来看下该类的成员:

  http://msdn.microsoft.com/en-us/library/system.dynamic.expandoobject_members(VS.100).aspx

ExpandoObject instances can add and remove members at run time.什么意思呢?这意味着此类的实例能够在运行时动态的增加和删除成员。

其中有个新概念:dynamic language runtime (DLR)(动态语言运行时),我才疏学浅,还希望各位专家们多去研究下。

说说ExpandoObject这个动态特性的意义吧。

我们用XML来做下对比:

首先我们创建一个XML对象,

 


XElement contactXML =
    
new XElement("Contact",
        
new XElement("Name""Patrick Hines"),
        
new XElement("Phone""206-555-0144"),
        
new XElement("Address",
            
new XElement("Street1""123 Main St"),
            
new XElement("City""Mercer Island"),
            
new XElement("State""WA"),
            
new XElement("Postal""68042")
        )
    );

再来看看Dynamic对象,

 


dynamic contact = new ExpandoObject();
contact.Name 
= "Patrick Hines";
contact.Phone 
= "206-555-0144";
contact.Address 
= new ExpandoObject();
contact.Address.Street 
= "123 Main St";
contact.Address.City 
= "Mercer Island";
contact.Address.State 
= "WA";
contact.Address.Postal 
= "68402";

 

首先,我们看下dynamic对象的声明:dynamic contact = new ExpandoObject();

 

我没有写成 ExpandoObject contact = new ExpandoObject(), 因为我用静态的ExpandoObject 类型来声明则此对象没有在运行时增加成员的特性,所以我使用新的关键字dynamic.

其次,大家能注意到,我创建一个子节点只需要创建一个ExpandoObject实例作为contact对象的成员。

这样你可以很简单的看清父子节点之间的关系,更重要的是你可以很简单的访问每一个元素。

用linq to XML:

Console.WriteLine((string)contactXML.Element("Address").Element("State"));

用 ExpandoObject对象:

Console.WriteLine(contact.Address.State);
可是,当你有很多个contact对象时该怎么办呢?
呵呵,看代码:
//用XML 方式: XElement contactsXML =     new XElement("Contacts",         new XElement("Contact",             new XElement("Name""Patrick Hines"),             new XElement("Phone""206-555-0144")         ),         new XElement("Contact",             new XElement("Name""Ellen Adams"),             new XElement("Phone""206-555-0155")         )     ); //用dynamic对象: dynamic contacts = new List<dynamic>(); contacts.Add(new ExpandoObject()); contacts[0].Name = "Patrick Hines"; contacts[0].Phone = "206-555-0144"; contacts.Add(new ExpandoObject()); contacts[1].Name = "Ellen Adams"; contacts[1].Phone = "206-555-0155";

再来看看用Linq to Object怎么来操作dynamic吧,

 

var phones = from c in (contacts as List<dynamic>)
             
where c.Name == "Patrick Hines"
             select c.Phone;

 

大家看了这个新特性有什么感受呢?想不想立刻感受下C# 4.0?不管怎么样我是很期待啦。。希望.net越来越强大~~你可是我的饭碗啊(PS:坚决不会转向java)

[C#]C# 委托的同步调用和异步调用

mikel阅读(511)

转载:http://www.cnblogs.com/yinhu435/archive/2009/10/19/1585958.html

委托的Invoke方法用来进行同步调用。同步调用也可以叫阻塞调用,它将阻塞当前线程,然后执行调用,调用完毕后再继续向下进行。

同步调用的例子:

using System;
using System.Threading;
public delegate int AddHandler(int a, int b);
public class Foo {
static void Main() {
Console.WriteLine("**********SyncInvokeTest**************");
AddHandler handler = new AddHandler(Add);
int result = handler.Invoke(1,2);
Console.WriteLine("Do other work... ... ...");
Console.WriteLine(result);
Console.ReadLine();
}
static int Add(int a, int b) {
Console.WriteLine("Computing "+a+" + "+b+" ...");
Thread.Sleep(3000);
Console.WriteLine("Computing Complete.");
return a+b;
}
}

运行结果:

**********SyncInvokeTest**************

Computing 1 + 2 …

Computing Complete.

Do other work… … …

3

同步调用会阻塞线程,如果是要调用一项繁重的工作(如大量IO操作),可能会让程序停顿很长时间,造成糟糕
的用户体验,这时候异步调用就很有必要了。
异步调用不阻塞线程,而是把调用塞到线程池中,程序主线程或UI线程可以继续执行。
委托的异步调用通过BeginInvoke和EndInvoke来实现。
异步调用:

using System;
using System.Threading;
public delegate int AddHandler(int a, int b);
public class Foo {
static void Main() {
Console.WriteLine("**********AsyncInvokeTest**************");
AddHandler handler = new AddHandler(Add);
IAsyncResult result = handler.BeginInvoke(1,2,null,null);
Console.WriteLine("Do other work... ... ...");
Console.WriteLine(handler.EndInvoke(result));
Console.ReadLine();
}
static int Add(int a, int b) {
Console.WriteLine("Computing "+a+" + "+b+" ...");
Thread.Sleep(3000);
Console.WriteLine("Computing Complete.");
return a+b;
}
}

运行结果: **********AsyncInvokeTest**************
Do other work… … …
Computing 1 + 2 …
Computing Complete.
3  

可以看到,主线程并没有等待,而是直接向下运行了。
但是问题依然存在,当主线程运行到EndInvoke时,如果这时调用没有结束(这种情况很可能出现),这时为了等待调用结果,线程依旧会被阻塞。
解决的办法是用回调函数,当调用结束时会自动调用回调函数
回调异步:

public class Foo {
static void Main() {
Console.WriteLine("**********AsyncInvokeTest**************");
AddHandler handler = new AddHandler(Add);
IAsyncResult result = handler.BeginInvoke(1,2,new AsyncCallback(AddComplete),"AsycState:OK");
Console.WriteLine("Do other work... ... ...");
Console.ReadLine();
}
static int Add(int a, int b) {
Console.WriteLine("Computing "+a+" + "+b+" ...");
Thread.Sleep(3000);
Console.WriteLine("Computing Complete.");
return a+b;
}
static void AddComplete(IAsyncResult result) {
AddHandler handler = (AddHandler)((AsyncResult)result).AsyncDelegate;
Console.WriteLine(handler.EndInvoke(result));
Console.WriteLine(result.AsyncState);
}
}

[MVC]ASP.Net MVC 源码解析系列

mikel阅读(587)

转载自Q.yuChen的blog
他写的这系列的文章比较清晰明了,值得收藏,对学习ASP.NET MVC Framework原理很有帮助,特收藏之
ASP.NET MVC

ASP.NET MVC Preview 2 – 流程分析 (1)
ASP.NET MVC Preview 2 – 流程分析 (2)
ASP.NET MVC Preview 2 – 流程分析 (3)
ASP.NET MVC Preview 2 – RedirectToAction
ASP.NET MVC Preview 2 – ClientNoCacheFilterAttribute
ASP.NET MVC Preview 2 – AuthenticateFilterAttribute
ASP.NET MVC Preview 2 – ActionCacheFilterAttribute
ASP.NET MVC Preview 2 – NVelocityViewEngine
ASP.NET MVC Preview 2 – Context
ASP.NET MVC Preview 2 – ControllerActionFilter
ASP.NET MVC Preview 3 – 1. MvcHandler
ASP.NET MVC Preview 3 – 2. Controller
ASP.NET MVC Preview 3 – 3. View
ASP.NET MVC Preview 3 – 4. Route
ASP.NET MVC Preview 4 – 1. ActionInvoker
ASP.NET MVC Preview 4 – 2. Filter
ASP.NET MVC 1.0 – 1. 准备工作
ASP.NET MVC 1.0 – 2. 流程分析 (System.Web.Routing)
ASP.NET MVC 1.0 – 3. 流程分析 (MvcHandler & Controller)
ASP.NET MVC 1.0 – 4. 流程分析 (ControllerActionInvoker)
ASP.NET MVC 1.0 – 5. 流程分析 (ControllerActionInvoker 续)
ASP.NET MVC 1.0 – 6. 流程分析 (ViewResult)
ASP.NET MVC 1.0 – 7. Route Namespace
ASP.NET MVC 1.0 – 8. TempData
ASP.NET MVC 1.0 – 9. ModelBinder
ASP.NET MVC 1.0 – 10. Controller
ASP.NET MVC 1.0 – 11. ViewData
ASP.NET MVC 1.0 – 12. NVelocityViewEngine
ASP.NET MVC 1.0 – 13. OutputCacheAttribute
ASP.NET MVC 1.0 – 14. CompressAttribute
ASP.NET MVC 1.0 – 15. StaticCacheAttribute
ASP.NET MVC 1.0 – 16. NoClientCacheAttribute
ASP.NET MVC 1.0 – 17. Anti Attack
ASP.NET MVC 1.0 – 18. ControllerContext

[MYSQL]理解MySQL——架构与概念

mikel阅读(526)

转载:http://www.cnblogs.com/hustcat/archive/2009/10/18/1585626.html

写在前面:最早接触的MySQL是在三年前,那时候MySQL还是4.x版本,很多功能都不支持,比如,存储过程,视图,触发器,更别说分布式事务 等复杂特性了。但从5.0(2005年10月)开始,MySQL渐渐步入企业级数据库的行列了;复制、集群、分区、分布式事务,这些企业级的特性,使得现 在的MySQL,完全可以应用于企业级应用环境(很多互联网公司都用其作为数据库服务器,尽管节约成本是一个因素,但是没有强大功能作后盾,则是不可想象 的)。虽然,MySQL还有很多不足,比如,复制、分区的支持都十分有限、查询优化仍需要改进,但是MySQL已经是一个足够好的DBMS了,更何况它是 opensource的。这段时间没有事,出于好奇,略微的研究了一下MySQL,积累了一些资料,欲总结出来。这些资料打算分为两部分,上部主要讨论 MySQL的优化,其中主要参考了《MySQL Manual》和《High Performance MySQL》,如果有时间,以后在下部分析一下MySQL的源码。如果你是MySQL高手,希望你不吝赐教;如果你是新手,希望对你有用。

 

第一章、MySQL架构与概念
1、MySQL的逻辑架构

 最上面不是MySQL特有的,所有基于网络的C/S的网络应用程序都应该包括连接处理、认证、安全管理等。
中间层是MySQL的核心,包括查询解析、分析、优化和缓存等。同时它还提供跨存储引擎的功能,包括存储过程、触发器和视图等。
最下面是存储引擎,它负责存取数据。服务器通过storage engine API可以和各种存储引擎进行交互。
1.1、查询优化和执行(Optimization and Execution)

MySQL 将用户的查询语句进行解析,并创建一个内部的数据结构——分析树,然后进行各种优化,例如重写查询、选择读取表的顺序,以及使用哪个索引等。查询优化器不 关心一个表所使用的存储引擎,但是存储引擎会影响服务器如何优化查询。优化器通过存储引擎获取一些参数、某个操作的执行代价、以及统计信息等。在解析查询 之前,服务器会先访问查询缓存(query cache)——它存储Select语句以及相应的查询结果集。如果某个查询结果已经位于缓存中,服务器就不会再对查询进行解析、优化、以及执行。它仅仅 将缓存中的结果返回给用户即可,这将大大提高系统的性能。

 1.2、并发控制
MySQL提供两个级别的并发控制:服务器级(the server level)和存储引擎级(the storage engine level)。加锁是实现并发控制的基本方法,MySQL中锁的粒度:
(1)    表级锁:MySQL独立于存储引擎提供表锁,例如,对于Alter TABLE语句,服务器提供表锁(table-level lock)。
(2)    行级锁:InnoDB和Falcon存储引擎提供行级锁,此外,BDB支持页级锁。InnoDB的并发控制机制,下节详细讨论。
另外,值得一提的是,MySQL的一些存储引擎(如InnoDB、BDB)除了使用封锁机制外,还同时结合MVCC机制,即多版本两阶段封锁协议(Multiversion two-phrase locking protocal),来实现事务的并发控制,从而使得只读事务不用等待锁,提高了事务的并发性。
注:并发控制是DBMS的核心技术之一(实际上,对于OS也一样),它对系统性能有着至关重要的影响,以后再详细讨论。

1.3、事务处理
MySQL中,InnoDB和BDB都支持事务处理。这里主要讨论InnoDB的事务处理(关于BDB的事务处理,也十分复杂,以前曾较为详细看过其源码,以后有机会再讨论)。
1.3.1、事务的ACID特性
事务是由一组SQL语句组成的逻辑处理单元,事务具有以下4个属性,通常简称为事务的ACID属性(Jim Gray在《事务处理:概念与技术》中对事务进行了详尽的讨论)。
(1)原子性(Atomicity):事务是一个原子操作单元,其对数据的修改,要么全都执行,要么全都不执行。
(2)一致性(Consistent):在事务开始和完成时,数据都必须保持一致状态。这意味着所有相关的数据规则都必须应用于事务的修改,以保持数据的完整性;事务结束时,所有的内部数据结构(如B树索引或双向链表)也都必须是正确的。
(3)隔离性(Isolation):数据库系统提供一定的隔离机制,保证事务在不受外部并发操作影响的“独立”环境执行。这意味着事务处理过程中的中间状态对外部是不可见的,反之亦然。
(4)持久性(Durable):事务完成之后,它对于数据的修改是永久性的,即使出现系统故障也能够保持。
1.3.2、事务处理带来的相关问题
由于事务的并发执行,带来以下一些著名的问题:
(1)更新丢失(Lost Update):当两个或多个事务选择同一行,然后基于最初选定的值更新该行时,由于每个事务都不知道其他事务的存在,就会发生丢失更新问题--最后的更新覆盖了由其他事务所做的更新。
(2) 脏读(Dirty Reads):一个事务正在对一条记录做修改,在这个事务完成并提交前,这条记录的数据就处于不一致状态;这时,另一个事务也来读取同一条记录,如果不加 控制,第二个事务读取了这些“脏”数据,并据此做进一步的处理,就会产生未提交的数据依赖关系。这种现象被形象地叫做"脏读"。
(3)不可重复读(Non-Repeatable Reads):一个事务在读取某些数据后的某个时间,再次读取以前读过的数据,却发现其读出的数据已经发生了改变、或某些记录已经被删除了!这种现象就叫做“不可重复读”。
(4)幻读(Phantom Reads):一个事务按相同的查询条件重新读取以前检索过的数据,却发现其他事务插入了满足其查询条件的新数据,这种现象就称为“幻读”。
1.3.3、事务的隔离性
SQL2标准定义了四个隔离级别。定义语句如下:
SET TRANSACTION ISOLATION LEVEL
[READ UNCOMMITTED |
READ COMMITTED  |
REPEATABLE READ  |
SERIALIZABLE ]
这 与Jim Gray所提出的隔离级别有点差异。其中READ UNCOMMITTED即Jim的10(浏览);READ COMMITTED即20,游标稳定性;REPEATABLE READ为2.99990隔离(没有幻像保护);SERIALIZABLE隔离级别为30,完全隔离。SQL2标准默认为完全隔离(30)。各个级别存在 问题如下:

隔离级

脏读

不可重复读

幻象读

读未提交

(Read uncommitted)

可能

可能

可能

读提交

(Read committed)

不可能

可能

可能

可重复读

(Repeatable read)

不可能

不可能

可能

可串行化

(Serializable)

不可能

不可能

不可能

各 个具体数据库并不一定完全实现了上述4个隔离级别,例如,Oracle只提供READ COMMITTED和Serializable两个标准隔离级别,另外还提供自己定义的Read only隔离级别;SQL Server除支持上述ISO/ANSI SQL92定义的4个隔离级别外,还支持一个叫做“快照”的隔离级别,但严格来说它是一个用MVCC实现的Serializable隔离级别。MySQL 支持全部4个隔离级别,其默认级别为Repeatable read,但在具体实现时,有一些特点,比如在一些隔离级别下是采用MVCC一致性读。国产数据库DM也支持所有级别,其默认级别为READ COMMITTED。
 

1.3.4、InnoDB的锁模型
InnoDB的行级锁有两种类型:
(1)共享锁(shared lock,S):允许一个事务去读一行,阻止其他事务获得相同数据集的排他锁。
(2)排它锁(exclusive lock,X):允许获得排它锁的事务更新数据,阻止其他事务取得相同数据集的共享读锁和排他写锁。
此外,InnoDB支持多粒度加锁(multiple granularity locking),从而允许对记录和表同时加锁。为此,InnoDB引入意向锁(intention locks),意向锁是针对表的:
(1)意向共享锁(IS):事务打算给数据行加行共享锁,事务在给一个数据行加共享锁前必须先取得该表的IS锁。
(2)意向排他锁(IX):事务打算给数据行加行排他锁,事务在给一个数据行加排他锁前必须先取得该表的IX锁。
例如,Select … LOCK IN SHARE MODE加IS锁,Select … FOR Update加IX锁,意向锁的规则如下:
(1)事务在对表T中的记录获取S锁前,先要获取表T的IS锁或者更强的锁;
(2)事务在获取表T中记录的X锁前,先要获取表T的IX锁。
InnoDB的锁相容性矩阵:

 如 果一个事务请求的锁模式与当前的锁兼容,InnoDB就将请求的锁授予该事务;反之,如果两者不兼容,该事务就要等待锁释放。意向锁只会阻塞其它事务对表 的请求,例如,LOCK TABLES …WRITE,意向锁的主要目的是表明该事务将要或者正在对表中的记录加锁。使用封锁机制来进行并发控制,一个比较重要的问题就是死锁。
来看一个死锁的例子:

1-1

Session 1

Session 2

mysql> Create TABLE t (i INT) ENGINE = InnoDB;

Query OK, 0 rows affected (0.22 sec)

 

mysql> Insert INTO t (i) VALUES(1);

Query OK, 1 row affected (0.08 sec)

 

mysql> START TRANSACTION;

Query OK, 0 rows affected (0.00 sec)

 

mysql> Select * FROM t Where i = 1 LOCK IN SHARE MODE;

+——+

| i    |

+——+

|    1 |

+——+

1 row in set (0.01 sec)

 

mysql>

 

 

mysql> START TRANSACTION;

Query OK, 0 rows affected (0.00 sec)

 

mysql> Delete FROM t Where i = 1;

等待

mysql> Delete FROM t Where i = 1;

等待

 

 

ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction

Query OK, 1 row affected (0.00 sec)

 

 

 1.3.5、一致性非阻塞读
一致性读是MySQL的重要特点之一,InnoDB通过MVCC机制表示数据库某一时刻的查询快照,查询可以看该时刻之前提交的事务所做的改变,但是不能看到该时刻之后或者未提交事务所做的改变。但是,查询可以看到同一事务中之前语句所做的改变,例如:

1-2

Session 1

Session 2

mysql> select * from t;

Empty set (0.00 sec)

 

mysql> Insert INTO t (i) VALUES(1);

Query OK, 1 row affected (0.00 sec)

 

mysql> select * from t;

+——+

| i    |

+——+

|    1 |

+——+

1 row in set (0.00 sec)

 

mysql> set autocommit = 0;

Query OK, 0 rows affected (0.01 sec)

 

mysql> update t set i=3;

Query OK, 1 row affected (0.00 sec)

Rows matched: 1 Changed: 1 Warnings: 0

mysql> select * from t;

+——+

| i    |

+——+

|    3 |

+——+

1 row in set (0.00 sec)

 

 

mysql> set autocommit = 0;

Query OK, 0 rows affected (0.00 sec)

 

mysql> select * from t;

+——+

| i    |

+——+

|    1 |

+——+

1 row in set (0.00 sec)

mysql> commit;

Query OK, 0 rows affected (0.06 sec)

 

 

mysql> select * from t;

+——+

| i    |

+——+

|    1 |

+——+

1 row in set (0.00 sec)

 

mysql> commit;

Query OK, 0 rows affected (0.00 sec)

 

mysql> select * from t;

+——+

| i    |

+——+

|    3 |

+——+

1 row in set (0.00 sec)

 

 如果事务的隔离级别为REPEATABLE READ(默认),同一个事务中的所有一致性读都是读的事务的第一次读操作创建的快照。你可以提交当前事务,然后在新的查询中即可看到最新的快照,如上所示。
如果事务的隔离级别为READ COMMITTED,一致性读只是对事务内部的读操作和它自己的快照而言的,结果如下:

1-3

Session 1

Session 2

mysql> SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;

Query OK, 0 rows affected (0.01 sec)

 

mysql> set autocommit = 0;

Query OK, 0 rows affected (0.00 sec)

 

mysql> select * from t;

+——+

| i    |

+——+

|    3 |

+——+

1 row in set (0.00 sec)

 

 

mysql> SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;

Query OK, 0 rows affected (0.01 sec)

 

mysql> set autocommit = 0;

Query OK, 0 rows affected (0.00 sec)

 

mysql> select * from t;

+——+

| i    |

+——+

|    3 |

+——+

1 row in set (0.00 sec)

mysql> update t set i=5;

Query OK, 1 row affected (0.00 sec)

Rows matched: 1 Changed: 1 Warnings: 0

 

 

mysql> select * from t;

+——+

| i    |

+——+

|    3 |

+——+

1 row in set (0.00 sec)

mysql> commit;

Query OK, 0 rows affected (0.06 sec)

 

 

mysql> select * from t;

+——+

| i    |

+——+

|    5 |

+——+

1 row in set (0.00 sec)

 

 注意,session 2发生了不可重复读。
当InnoDB在READ COMMITTED 和REPEATABLE READ隔离级别下处理Select语句时,一致性读是默认的模式。一致性读不会对表加任何锁,所以,其它连接可以同时改变表。
假设事务处于REPEATABLE READ级别,当你正在进行一致性读时,InnoDB根据查询看到的数据给你一个时间点。如果其它的事务在该时间点之后删除一行,且提交事务,你不会看到行已经被删除,插入和更新操作一样。但是,InnoDB与其它DBMS的不同是,在REPEATABLE READ隔离级别下并不会造成幻像。
一致性读不与Drop TABLE 或者 Alter TABLE一起工作。
在 nodb_locks_unsafe_for_binlog变量被设置或者事务的隔离级别不是SERIALIZABLE的情况下,InnoDB对于没有指 定FOR Update 或 LOCK IN SHARE MODE的Insert INTO … Select, Update … (Select), 和Create TABLE … Select语句使用一致性读,在这种情况下,查询语句不会对表中的元组加锁。否则,InnoDB将使用锁。

1.3.6、Select … FOR Update和Select … LOCK IN SHARE MODE的加锁读(locking read)
在一些场合,一致性读并不是很方便,此时,可以用加锁读。InnoDB支持两种加锁读:
(1)    Select … LOCK IN SHARE MODE:对读取的元组加S锁。
(2)    Select … FOR Update:在扫描索引记录的过程中,会阻塞其它连接的Select …LOCK IN SHARE MODE和一定事务隔离级别下的读操作。
InnoDB 使用两阶段封锁协议,事务直到提交或回滚时才会释放所有的锁,这都是系统自动执行的。此外,MySQL支持LOCK TABLES和UNLOCK TABLES,但这些都是在服务器层实现的,而不是在存储引擎。它们有用处,但是不能取代存储引擎完成事务处理,如果你需要事务功能,请使用事务型存储引 擎。
来考虑locking read的应用,假设你要在表child插入一个新的元组,并保证child中的记录在表parent有一条父记录。如果你用一致性读来读parent 表,确实可以将要插入的child row的parent row,但是可以安全的插入吗?不,因为在你读parent表时,其它连接可能已经删除该记录。(一致性读是针对事务内而言的,对于数据库的状态,它应该 叫做“不一致性读”)
此时,就可以使用Select LOCK IN SHARE MODE,它会对读取的元组加S锁,从而防止其它连接删除或更新元组。另外,如果你想在查询的同时,进行更新操作,可以使用Select … FOR Update,它读取最新的数据,然后对读到的元组加X锁。此时,使用Select … LOCK IN SHARE MODE不是一个好主意,因为此时如果有两个事务进行这样的操作,就会造成死锁。
注:Select … FOR Update仅在自动提交关闭(即手动提交)时才会对元组加锁,而在自动提交时,符合条件的元组不会被加锁。

1.3.7、记录锁(record lok)、间隙锁(gap lock)和后码锁(next-key lock)
InnoDB有以下几种行级锁:
(1) 记录锁:对索引记录(index records)加锁,InnoDB行级锁是通过给索引的索引项加锁来实现的,而不是对记录实例本身加锁。如果表没有定义索引,InnoDB创建一个隐藏 的聚簇索引,然后用它来实现记录加锁(关于索引与加锁之间的关系的详细介绍请看下一章)。
(2)间隙锁:对索引记录之间的区间,或者第一个索引记录之前的区间和最后一个索引之后的区间加锁。
(3)后码锁:对索引记录加记录锁,且对索引记录之前的区间加锁。
默认情况下,InnoDB的事务工作在REPEATABLE READ的隔离级别,而且系统变量innodb_locks_unsafe_for_binlog为关闭状态。此时,InnoDB使用next-key锁进行查找和索引扫描,从而达到防止“幻像”的目的。
Next- key锁是记录锁和间隙的结合体。当InnoDB查找或扫描表的索引时,对它遇到的索引记录加S锁或者X锁,所以,行级锁(row-level lock)实际上就是索引记录锁(index-record lock);此外,它还对索引记录之前的区间加锁。也就是说,next-key锁是索引记录锁,外加索引记录之前的区间的间隙锁。如果一个连接对索引中的 记录R持有S或X锁,其它的连接不能按照索引的顺序在R之前的区间插入一个索引记录。
假设索引包含以下值:10, 11,13和20,则索引的next-key锁会覆盖以下区间(“(”表示不包含,“[”表示包含):
(negative infinity, 10]
(10, 11]
(11, 13]
(13, 20]
(20, positive infinity)
对于最后一个区间,next-key锁将锁住索引最大值以上的区间,上界虚记录(“supremum” pseudo-record)的值比索引中的任何值都大,其实,上界不是一个真实的索引记录,所以,next-lock将对索引的最大值之后的区间加锁。
间隙锁对查询唯一索引中的唯一值是没有必要的,例如,id列有唯一索引,则下面的查询仅对id=100的元组加索引记录锁(index-record lock),而不管其它连接是否在之前的区间插入元组。
Select * FROM child Where id = 100;
如果id没有索引,或者非唯一索引,则语句会锁住之前的空间。

例1-4
Session 1
Session 2
mysql> create unique index i_index on t(i);
Query OK, 0 rows affected (0.19 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> select * from t;
+------+
| i    |
+------+
|    4 |
|   10 |
+------+
2 rows in set (0.00 sec)
 
 
 
mysql> set autocommit=0;
Query OK, 0 rows affected (0.00 sec)
mysql> select i from t where i =10 lock in share mode;
+------+
| i    |
+------+
|   10 |
+------+
1 row in set (0.00 sec)
mysql> insert into t(i) values(9);
Query OK, 1 row affected (0.03 sec)
 
 
mysql> select * from t;
+------+
| i    |
+------+
|    4 |
|    9 |
|   10 |
+------+
3 rows in set (0.00 sec)

 上例中,产生了幻像问题。如果将唯一查询变成范围查询,结果如下(接上例的索引):

1-5

Session 1

Session 2

mysql> select * from t;

+——+

| i    |

+——+

|    4 |

|    9 |

|   10 |

+——+

3 rows in set (0.00 sec)

 

 

mysql> set autocommit=0;

Query OK, 0 rows affected (0.00 sec)

mysql> select i from t where i>4 lock in share mode;

+——+

| i    |

+——+

|    9 |

|   10 |

+——+

2 rows in set (0.00 sec)

mysql> insert into t(i) values(1);

ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

mysql> insert into t(i) values(8);

ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

 

 可以看到,session 2 的next-key使得在i=4之前的区间和之后的插入都被阻塞。
另外,如果删除索引i_index,则结果如下:

1-6

Session 1

Session 2

mysql> drop index i_index on t;

Query OK, 3 rows affected (0.25 sec)

Records: 3 Duplicates: 0 Warnings: 0

mysql> select * from t;

+——+

| i    |

+——+

|    4 |

|   10 |

|    9 |

+——+

3 rows in set (0.00 sec)

 

 

mysql> set autocommit=0;

Query OK, 0 rows affected (0.00 sec)

 

mysql> select i from t lock in share mode;

+——+

| i    |

+——+

|    4 |

|   10 |

|    9 |

+——+

3 rows in set (0.00 sec)

mysql> insert into t(i) values(8);

等待。。。

 

 

 另 外,针对插入(Insert)操作,只要多个事务不会在同一索引区间的同一个位置插入记录,它们就不用互相等待,这种情况可以称为插入意向间隙锁 (insertion intention gap lock)。例如,索引记录的值为4和7,两个独立的事务分别插入5和6,仅管它们都持有4—7之间的间隙锁,但是它们不会相互阻塞。这可以提高事务的并 发性。

1-7

Session 1

Session 2

mysql> select * from t;

+——+

| i    |

+——+

|    4 |

|   10 |

|    9 |

|    8 |

+——+

4 rows in set (0.00 sec)

 

mysql> create unique index i_index on t(i);

Query OK, 4 rows affected (0.34 sec)

Records: 4 Duplicates: 0 Warnings: 0

 

mysql> set autocommit=0;

Query OK, 0 rows affected (0.00 sec)

 

 

mysql> set autocommit=0;

Query OK, 0 rows affected (0.00 sec)

mysql> insert into t(i) values(5);

Query OK, 1 row affected (0.00 sec)

 

 

mysql> insert into t(i) values(5);

ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

mysql> insert into t(i) values(6);

Query OK, 1 row affected (0.00 sec)

 间隙锁是可以显示关闭的,如果你将事务的隔离级别设为READ COMMITTED,或者打开innodb_locks_unsafe_for_binlog系统变量,间隙锁就会关闭。在这种情况下,查找或扫描索引仅会进行外键约束检查和重复键值检查。
此 外,READ COMMITTED隔离级别和关闭nodb_locks_unsafe_for_binlog还有另外一个负作用:MySQL会释放掉不匹配Where条 件的记录锁。例如,对于Update语句,InnoDB只能进行“半一致性(semi_consistent)读”,所以,它会返回最新提交事务所做改 变,从而产生不可重复读和幻像问题。
1.3.8、使用next-key lock防止幻像问题
例1-4展示了一个幻像问题。使用next-key锁的select语句可以解决幻像问题,但例1-4的之所以会产生总是在于唯一索引,使得select语句没有使用gap lock,而只使用了index-record lock。

1.4、存储引擎
插 件式存储引擎是MySQL最重要特性之一,也是最不同于其它DBMS的地方。MySQL支持很多存储引擎,以适用于不同的应用需求,常用的包括 MyISAM、InnoDB、BDB、MEMORY、MERGE、NDB Cluster等。其中,BDB和NDB Cluster提供事务支持。
MySQL 默认的存储引擎为MyISAM,当然,创建表的时候可以指定其它的存储引擎,你可以在同一个数据库中对不同的表使用不同的存储引擎(这是非常强大而独特的 特性)。可以通过SHOW TABLE STATUS命令查询表所使用的存储引擎,例如,查看mysql数据库的user表:

mysql> SHOW TABLE STATUS LIKE 'user' \G

*************************** 1. row ***************************

           Name: user

         Engine: MyISAM

        Version: 10

     Row_format: Dynamic

           Rows: 4

 Avg_row_length: 61

    Data_length: 244

Max_data_length: 281474976710655

   Index_length: 2048

      Data_free: 0

 Auto_increment: NULL

    Create_time: 2009-06-16 21:50:34

    Update_time: 2009-09-30 14:59:08

     Check_time: NULL

      Collation: utf8_bin

       Checksum: NULL

 Create_options:

        Comment: Users and global privileges

1 row in set (0.00 sec)

 Name:表的名称;
Engine:表使用的存储引擎;
Row_format:记录的格式。MyISAM支持三种不同的存储格式:静态(固定长度)表(默认格式)、动态表及压缩表。静态表的字段都是固定长度的,例如CHAR和INTEGER;动态表的字段可以是变长的,例如,VARCHAR或者BLOB。
Rows:表中记录的数量。
Avg_row_length:记录的平均长度(字节数);
Data_length:表中数据的全部字节数;
Max_data_length:表中数据最大的字节数;
Index_length:索引消耗的磁盘空间;
Data_free:对于MyISAM表,表示已经分配但还没有使用的空间;该空间包含以前删除的记录留下的空间,可以被Insert操作重用。
Auto_increment:下一个自增的值。
Check_time:上次使用CHECK TABLE或myisamchk检查表的时间。

1.4.1、MyISAM
1.4.1.1、存储
MySQL的默认存储引擎,性能与功能的折中,包括全文索引(full-text index)、数据压缩,支持空间(GIS)数据,但是,不支持事务和行级锁。一般来说,MyISAM更适用于大量查询操作。如果你有大量的插入、删除操作,你应该选择InnoDB。
每个表包含3个文件:
(1).frm:表定义文件,对于其它存储引擎也一样。
(2).MYD文件:数据文件。
(3).MYI文件:索引文件。
可以在创建表时通过DATA DIRECTORY和INDEX DIRECTORY为数据文件和索引文件指定路径,它们可以位于不同目录。另外,MyISAM的存储格式是跨平台的,你可以将数据文件和索引文件从Intel平台拷贝到PPC或者SPARC平台。
5.0 中,MyISAM的变长记录表默认处理256TB数据,使用6字节的指针来指向数据记录;而之前的版本使用默认的4字节指针,所以只能处理4GB数据。所 有的版本都可以将指针增加到8字节指针,如果你想改变MyISAM表的指针的大小,可以通过设置MAX_ROWS和AVG_ROW_LENGTH来实现:
Create TABLE mytable (
   a    INTEGER  NOT NULL PRIMARY KEY,
   b    CHAR(18) NOT NULL
) MAX_ROWS = 1000000000 AVG_ROW_LENGTH = 32;
上面的例子中,MySQL将至少可以存储32GB的数据。可以查看一下表的信息:

mysql> SHOW TABLE STATUS LIKE 'mytable' \G

*************************** 1. row ***************************

           Name: mytable

         Engine: MyISAM

     Row_format: Fixed

           Rows: 0

 Avg_row_length: 0

    Data_length: 0

Max_data_length: 98784247807

   Index_length: 1024

      Data_free: 0

 Auto_increment: NULL

    Create_time: 2002-02-24 17:36:57

    Update_time: 2002-02-24 17:36:57

     Check_time: NULL

 Create_options: max_rows=1000000000 avg_row_length=32

        Comment:

1 row in set (0.05 sec)

可以看到,Create_options列出了创建时的选项,而且该表的最大的数据量为91GB。你可以用Alter TABLE来改变指针的大小,但是那会导致表和索引的重建,这会花费很长的时间。
1.4.1.2、MyISAM的特性
(1)锁与并发性:MyISAM只有表级锁,不支持行级锁。所以不适合于大量的写操作,但是它支持并发插入(concurrent inserts),这是一个非常重要且有用的特性。
(2)自动修复:MySQL支持自动检查和修复MyISAM表。
(3)手动修复:你可以使用CHECK TABLE检查表的状态,并用REPAIR TABLE修复表。
(4)索引:你可以为BLOB和TEXT的前500个字符创建索引。而且,MyISAM还支持全文索引,但仅限于CHAR、VARCHAR、和TEXT列。
(5) 延迟键写(Delayed key writes):如果创建MyISAM表时指定DELAY_KEY_WRITE,MySQL在查询结束时,不会将改变的索引数据写入磁盘,而将修改保存在 key buffer中。只有要改变缓存或者关闭表时,才会把索引数据刷入磁盘。
1.4.2、InnoDB
InnoDB是一个高性能的事务存储引擎,此外,BDB也支持事务处理(关于BDB,以前曾较为详细的阅读过其源码,以后有时间再讨论),它有以下一些特点:
1.4.2.1、表空间
InnoDB存储表和索引有两种方式:
(1)共享表空间存储:这种方式下,表的定义位于.frm文件中,数据和索引保存在innodb_data_home_dir和innodb_data_file_path指定的表空间中。
(2)多表空间存储:表的定义仍位于.frm文件,但是,每个InnoDB表和它的索引在它自己的文件(.idb)中,每个表有它自己的表空间。
对那些想把特定表格移到分离物理磁盘的用户,或者那些希望快速恢复单个表的备份而无须打断其余InnoDB表的使用的用户,使用多表空间会是有益的。你可以往my.cnf的[mysqld]节添加下面行来允许多表空间:
[mysqld]
innodb_file_per_table
重 启服务器之后,InnoDB存储每个新创建的表到表格所属于的数据库目录下它自己的文件tbl_name.ibd里。这类似于MyISAM存储引擎所做 的,但MyISAM 把表分成数据文件tbl_name.MYD和索引文件tbl_name.MYI。对于InnoDB,数据和所以被一起存到.ibd文件。 tbl_name.frm文件照旧依然被创建。
如果你从my.cnf文件删除innodb_file_per_table行,并重启服务器,InnoDB在共享的表空间文件里再次创建表。
innodb_file_per_table只影响表的创建。如果你用这个选项启动服务器,新表被用.ibd文件来创建,但是你仍旧能访问在共享表空间里的表。如果你删掉这个选项,新表在共享表空间内创建,但你仍旧可以访问任何用多表空间创建的表。
InnoDB总是需要共享表空间,.ibd文件对InnoDB不足以去运行,共享表空间包含熟悉的ibdata文件,InnoDB把内部数据词典和undo日志放在这个文件中。
1.4.2.2、外键约束
MySQL中,支持外键的存储引擎只有InnoDB,在创建外键时,要求被参照表必须有对应的索引,参照表在创建外键时也会自动创建对应的索引。
1.4.2.3、MVCC与后码锁(next-key locking)
InnoDB 将MVCC机制与next-key lock结合起来,实现事务的各个隔离级别,这是非常用意思的。在nodb_locks_unsafe_for_binlog变量被设置或者事务的隔离级 别不是SERIALIZABLE的情况下,InnoDB对于没有指定FOR Update 或 LOCK IN SHARE MODE的Insert INTO … Select, Update … (Select), 和Create TABLE … Select语句使用一致性读(参照前面),在这种情况下,查询语句不会对表中的元组加锁。否则,InnoDB将使用锁。

 

主要参考:

 《MySQL Manual》

 《High Performance MySQL》

[工具]Visual Studio Team System 2008正式版下载

mikel阅读(497)

Microsoft Visual Studio Team System 2008 Team Suite正式版已于2007/11/19在MSDN Subscriptions开放下载。
微 软官方网站仅提供Visual Studio Team System 2008 Beta 2 Team Suite(90-day Trial) 和Visual Studio 2008 Beta 2 Team Foundation Server (Virtual PC) 下载。
Visual Studio Team System 2008正式版下载地址 – Visual Studio Team System 2008 Team Suite download
Microsoft Visual Studio Team System 2008 Team Suite.iso

引用
ed2k://|file|Microsoft.Visual.Studio.Team.System.2008.Team.Suite-ZWTiSO.iso|4112060416|7730FC9FFA4E1A1AB2A070C61BFD634B|h=YDLIF7QGESBVMJNATFOZA47X4YLBLY6H|/

Visual Studio Team System 2008 Team Suite正式版下载(eMule下载)
Microsoft Visual Studio Team System 2008 Team Suite正式版下载(BT下载)
微软Visual Studio Team System 2008正式版激活方法
如果下载过MSDN上的Visual Studio Team System 2008 Beta 2 Team Suite 90天trial版,
只要把Setupsetup.sdb文件中的[Product Key],
由T2CRQGDKBVW7KJR8C6CKXMW3D修改为PYHYPWXB3BB2CCMV9DX9VDY8T,
再次安装就成Visual Studio Team System 2008 Team Suite正式版了。
Visual Studio Team System 2008正式版下载地址-Visual Studio Team System 2008 Team Suite download
Visual Studio 2008 Professional正式版下载地址
VS2008正式版下载-vs2008各版本下载地址
MSN9.0下载-Windows Live Messenger 9.0 Beta下载(免邀请)
Visual Studio 2008 Team Foundation Server的90天免费试用版本下载(官方试用版本)
Visual Studio 2008 Beta 1 Download
Visual Studio 2008 和 .NET 3.5 的新功能和改进
Visual Studio 2008下载(Visual Studio 2008 Download)
SQL Server 2008 CTP Download
ASP.NET 3.5 Extensions, Silverlight 2.0, IIS7
Windows Server 2008 Download-Windows Server 2008下载
迁移到Windows Server 2008和IIS 7.0

Visual Studio Team System 2008正式版下载

原文来自:http://www.ad0.cn/netfetch/read.php/1152.htm
转载请保留本文链接:http://www.ad0.cn/netfetch/read.php/1152.htm

[管理]我是如何带领团队开发工作流项目的(转载)

mikel阅读(471)

转载:http://www.cnblogs.com/foundation/archive/2009/10/17/1584875.html#_Toc243502607

最近有不少朋友写信问我一些关于团队开发的问题,由于这段时间有些忙,没有回复.今天写一篇这方面的文章向大家介绍一下我是如何带领团队开发工作流项目的

关于团队建设,项目管理的文章网上已经有很多了,在这里我就不谈这些理论了,直接给大家展示一个我在 项目开发方,后台服务开发方式,前台UI开发方式,后台服务与前台UI对接方式,代码文档,页面的开发文档,源码管理,单元测试,以及单元测试文档,实现 思路设计文档,数据库文档,数据库设计规范,编码规范,操做数据的方法命名规则 方面的一些片断,这是一个为期6个月的工作流平台开发项目,是今年3月份启动的,现在已完成,比计划时间多出25天.核心开发人员(不包括美工,需求,黑 盒测试)共有12人(编号从114到125)

补充一点:在UI草图设计上,这次想用绘图板,但最后还是使用铅笔绘制+扫描的方式制做的.

 

目录

项目开发方式说明图    1

后台服务开发方式说明图    1

前台UI开发方式说明图    2

后台服务与前台UI对接方式说明图    3

代码文档(片断节选)    4

页面的开发文档(片断节选)    5

源码管理    6

单元测试,以及单元测试文档(片断节选)    7

实现思路设计文档(片断节选)    9

数据库文档    11

数据库设计规范(片断节选)    13

编码规范(片断节选)    13

操做数据的方法命名规则    13

 

 

项目开发方式说明图

 

后台服务开发方式说明图

 

 

前台UI开发方式说明图

 

 

后台服务与前台UI对接方式说明图

 

 

代码文档(片断节选)

 

方法签名

public int? addBaseEnumeration(string powerID, List<baseEnumeration> list)

返回值

  • [0]:方法未完成
  • [null]:操作成功
  • [401]:参数[powerID]没通过[security.checkPowerID方法]验证
  • [-1]:参数[list][null]
  • [-2]:参数[list]中的[baseEnumeration.rowID][Guid.Empty]
  • [-3]:参数[list]中的[baseEnumeration.entity][null][string.Empty]
  • [-4]:参数[list]中的[baseEnumeration.field][null][string.Empty]
  • [-5]:参数[list]中的[baseEnumeration.entityType][null][string.Empty]
  • [-6]:参数[list]中的[baseEnumeration.title][null][string.Empty]
  • [-7]:参数[list]中的[baseEnumeration.value][null][string.Empty]
  • [-8]:参数[list]中存在[rowID]重复的记录
  • [-9]:参数[list]中存在[Entity][field][value]重复的记录
  • [3] :参数[list]中的[baseEnumeration.rowID]在数据库中已存在
  • [4] :联合唯一索引[Entity][field][value]在数据库中已存在
  • [5] :参数[entityType]的传入值不是枚举表[entitytype]的基础枚举数据
  • [6] :插入时数据库异常
  • [7] :不能插入[entity]["insertBaseEnumeration"],[field]["entitytype"]的数据

参数

  • [powerID]: 权限参数
  • [list]: 多条baseEnumeration表记录,的泛型集合

约束

<1> 调用[security.checkPowerID方法]判断[powerID],如果[security.checkPowerID方法]返回[false],返回[401]

<2> 如果参数[list][null],返回[-1]

<3> 如果参数[list]中的[baseEnumeration.rowID][Guid.Empty],返回[-2]

<4> 如果参数[list]中的[baseEnumeration.entity][null][string.Empty], 返回[-3]

<5> 如果参数[list]中的[baseEnumeration.field][null][string.Empty], 返回[-4]

<6> 如果参数[list]中的[baseEnumeration.entityType][null][string.Empty], 返回[-5]

<7> 如果参数[list]中的[baseEnumeration.title][null][string.Empty], 返回[-6]

<8> 如果参数[list]中的[baseEnumeration.value][null][string.Empty], 返回[-7]

<9> 如果参数[list]中存在[rowID]重复的记录,返回[-8]

<10>如果参数[list]中存在[entity][field][value]重复的记录,返回[-9]

<11>如果参数[list]中的[baseEnumeration.rowID]在数据库中已存在, 返回[3]

<12>如果联合唯一索引[entity][field][value]在数据库中已存在, 返回[4]

<13>如果参数[entity]["baseEnumeration"],[field][entitytype]的数据,返回[7]

<14>如果参数[entityType]的传入值不是枚举表[entitytype]的基础枚举数据, 返回[5]

<15>如果插入时数据库异常, 返回[6]

说明

[Entity][field][value] 联合唯一索引

<14>获取[Entitytype]基础枚举数据时,使用[23 selectBaseEnumerationTypeName]得到枚举类型名称

单元测试

(组合测试),(自动判断返回状态),(自动判断返回结果)

WFServiceTestProject. manageServiceTest. addBaseEnumerationTest()

 

//[26] 批量添加枚举

public int? addBaseEnumeration(string powerID, List<baseEnumeration> list)

{

//<1>

if (!security.checkPowerID(powerID))

{

return 401;

}

//<2>

if (list == null)

{

return -1;

}

using (wxwinterDBDataContext db = new wxwinterDBDataContext())

{

//<3>

if (list.Count(p => p.rowID == Guid.Empty) > 0)

{

return -2;

}

//<4>

if (list.Count(p => string.IsNullOrEmpty(p.entity)) > 0)

{

return -3;

}

//<5>

if (list.Count(p => string.IsNullOrEmpty(p.field)) > 0)

{

return -4;

}

//<6>

if (list.Count(p => string.IsNullOrEmpty(p.entityType)) > 0)

{

return -5;

}

 

………………………….

 

 

页面的开发文档(片断节选)

模块编号

Wxwinter.Index.Power.manageDutyControl

模块需要调用的其它UI模块列表

Wxwinter.Index.Power.insertDutyControl

Wxwinter.Index.Power.changeDutyControl

模块的调用入口UI

Wxwinter.Index.Power.navigationOrganizationControl

UI类型

[ V ] 中控件 700 * 500

工具栏按钮的调用路径

[ V ] 无工具栏

模块调用方式

[ V ] 模式化弹出框

action说明

不需要action

 

 

源码管理

 

 

 

 

单元测试,以及单元测试文档(片断节选)

文档

×

方法签名

public int? transactComplete(string powerID , Guid instanceID , Guid stateID , string transactResult , status status)

×

返回值

  • [0]:方法未完成
  • [null]:操作成功
  • [401]:参数[powerID]没通过[security.checkPowerID方法]验证
  • [-1]:[instanceID]为[Guid.empty]
  • [-2]:[stateID]为[Guid.empty]
  • [1]:[wfStateTransactTask]表中没有指定完成的办理任务
  • [2]:所指定的办理任务处在非等待状态
  • [3]:数据库提交失败

×

参数

  • [powerID]: 权限参数
  • [instanceID]:实例编号
  • [stateID]:状态编号
  • [transactResult]:办理结果
  • [status]:身份

×

约束

<1>调用[security.checkPowerID方法]判断[powerID],如果[security.checkPowerID方法]返回[false],返回[401]

<2>调用[checkInstanceState()]方法对[instanceID][stateID]指定的实例状态进行验证,返回值不为[null],返回[checkInstanceState()]的返回值

<3>调用[checkStatus()]方法对[status]进行验证,返回值不为[null],返回[checkStatus()]的返回值

<4>得到[wfStateTransactTask]表中

[

wfStateTransactTask.instanceID = instanceID

&& wfStateTransactTask.stateID = stateID

&& wfStateTransactTask.departmentNo = status.departmentNo

&& wfStateTransactTask.dutyNo = status.dutyNo

&& wfStateTransactTask.personNo = status.personNo

]

的记录并赋给变量[taskInfo],如果不存在,返回[1]

<5>如果[taskInfo.runState != runState.wait],返回[2]

<6>修改

[

taskInfo.runState=runState.end

taskInfo.completeTime=System.DateTime.Now

taskInfo.transactResult=transactResult

]

用[taskInfo]修改[wfStateTransactTask]表中记录

<7>向[wfStepList]中插入数据

[

flowID = taskInfo.flowID

flowName = taskInfo.flowName

nodeID = taskInfo.nodeID

nodeName = taskInfo.nodeName

departmentNo = status.departmentNo

departmentName = status.departmentName

dutyNo = status.dutyNo

dutyName = status.dutyName

personNo = status.personNo

personName = status.personName

instanceID = taskInfo.instanceID

stateID = taskInfo.stateID

processID = taskInfo.processID

processName = taskInfo.processName

stepAction = stepAction.办理

stepTime = System.DateTime.Now

taskID = stepAction.办理

]

<8>如果数据库提交失败,返回[3],成功,返回[null]

×

说明

调用[checkInstanceState()]方法对实例状态进行验证

×

单元测试

 

 

单元测试选项

范围

判断

影响

(无)

 

(不需要)

 

(全路径)

 

(正常路径)

 

(简单调用)

 

(组合测试)

 

(已在外部调试通过)

(自动判断返回状态)

 

(自动判断返回结果)

 

(人工判断返回结果,结果控制台输出)

 

(人工判断返回结果,结果存入磁盘)

 

(自动判断操作结果)

 

(人工判断操作结果,结果存入数据库)

 

(人工判断操作结果,结果存入数据库)

 

(不出异常即可)

 

(说明…)

(操作数据库,完成测试后已复原)

 

(操作数据库,已做state标记)

 

(操作数据库,需要手工复原)

 

(操作临时数据库)

 

 

实现思路设计文档(片断节选)

例1:工作流结构的解析

 

 

 

例2:删除部门职能人员的约束

 

 

例3:查询用户的模块权限

public List<viewRelationModel> searchModelPowerOfPerson(string powerID,string personNo)

 

searchModelPowerOfPerson("","user1")

step1

使用 searchStatusList("", "user1") 得到[得到身份列表]

 

departmentNo 

dutyNo 

personNo 

user1 

user1 

user1 

step2

用得到的身份与[powerRelationModel]对比,并返回如下算法的集合

 

departmentNo 

dutyNo 

modelNo 

action 

scope 

all 

m1 

see 

 

B 

all 

m2 

see 

 

all 

all 

m3 

see 

 

m4 

see 

 

 

 

 

数据库文档

wfFlow 流程表

表说明:存储流程模板的属性信息,该表内容是将xoml存入时,解析xoml后一次性生成的,不能修改

flowID

流程编号

f1

来自iFlow

flowName

流程名称

f2

flowType

流程类型

f3

flowDescription

流程说明

f4

businessType

业务类型

f5

startWindow

启动窗体

f6

dataFormList

表单列表

f7

startDataForm

启动时填写的表单

f8

inputFormItems

传入表单

f9

inputFormItemsExpandData

传入表单扩展数据

f10

commandOption

命令选项

f11

commandOptionExpandData

命令选项扩展数据

f12

ownedType

流程归属类型

f13

timelimitUnit

时限单位

l1

来自iTimelimit

timelimit

时限

l2

overtimeOperate

超时操作

l3

calendar 

日历

l4

residualTimelimit

剩余时限

l5

createDepartmentNo

创建部门编号

创建该流程模板的人员所在部门的编号

createDepartmentName

创建部门名称

 

createDutyNo

创建职能编号

创建该流程模板的人员所担任的职能的编号

createDutyName

创建职能名称

 

createPersonNo

创建人员编号

创建该流程模板的人员的编号

createPersonName

创建人员名称

 

createTime

创建时间

 

isCheckout

是否签出

如果为真,签出人可以对流程模板进行修改,非签出人不能再将该模板签出进行修改,如果为假,就可以将该流程签出进行修改

checkoutPersonNo

签出人员编号

 

checkoutPersonName

签出人员名称

 

checkoutTime

签出时间

 

checkinTime

签入时间

 

isFreeze

是否冻结

如果为真,流程模板处于冻结状态,不能被启动

如果为假,流程模板可以正常启动

 

wfFlow 流程表 表结构

编号

字段

中文对照

外创

模创

外改

数据类型

主键

非空

唯一

外键约束/字段值选项

 

rowID

行编号

     

uniqueidentifier 

 
 

state

状态

     

int

       

f1

flowID

流程编号

 

 

nvarchar(50) 

 

 

f2

flowName

流程名称

 

 

nvarchar(50) 

 

   

f3

flowType

流程类型

 

 

nvarchar(50) 

 

 

option.flowType

f4

flowDescription

流程说明

 

 

nvarchar(MAX)

 

   

f5

businessType

业务类型

 

 

nvarchar(50) 

 

 

wfBusinessType.businessType

f6

startWindow

启动窗体

 

 

nvarchar(255)

 

   

f7

dataFormList

表单列表

 

 

nvarchar(MAX)

 

   

f8

startDataForm

启动时填写的表单

 

 

nvarchar(MAX)

 

   

f9

inputFormItems

传入表单

 

 

nvarchar(MAX)

 

   

f10

inputFormItemsExpandData

传入表单扩展数据

 

 

nvarchar(MAX)

 

   

f11

commandOption

命令选项

 

 

nvarchar(255)

 

   

f12

commandOptionExpandData

命令选项扩展数据

 

 

nvarchar(MAX)

 

   

f13

ownedType

流程归属类型

 

 

nvarchar(50) 

 

 

option.ownedType

l1

timelimitUnit

时限单位

 

 

nvarchar(50) 

 

 

option.timelimitUnit

l2

timelimit

时限

 

 

int

 

   

l3

overtimeOperate

超时操作

 

 

nvarchar(50)

 

   

l4

calendar 

日历

 

 

nvarchar(50) 

 

   

I5

residualTimelimit

剩余时限

 

 

int

 

   
 

createDepartmentNo

创建部门编号

   

nvarchar(50) 

 

   
 

createDepartmentName

创建部门名称

   

nvarchar(50) 

 

   
 

createDutyNo

创建职能编号

   

nvarchar(50) 

 

   
 

createDutyName

创建职能名称

   

nvarchar(50) 

 

   
 

createPersonNo

创建人员编号

   

nvarchar(50) 

 

   
 

createPersonName

创建人员名称

   

nvarchar(50) 

 

   
 

createTime

创建时间

   

datetime 

 

   
 

isCheckout

是否签出

 

int

 

   
 

checkoutPersonNo

签出人员编号

 

nvarchar(50) 

       
 

checkoutPersonName

签出人员名称

 

nvarchar(50) 

       
 

checkoutTime

签出时间

 

datetime 

       
 

checkinTime

签入时间

 

datetime 

       
 

isFreeze 

是否冻结

 

int

 

   

 

数据库设计规范(片断节选)

SQL Server 类型

C# 类型

说明

nvarchar(50)

string

  • 字符类的[唯一索引]
  • 标识类信息,如用户名,口令,性别
  • 标签类信息
  • 标记类信息
  • 状态标识 :如:[成功],[失败],[运行中]

对应的UI为单行行文本框,标签,提示文字

nvarchar(255)

string

  • 小量的描述信息,两行以上
  • 磁盘文件的路径信息

对应的UI为垂直滚动条的多行文本框,或多段的标签

nvarchar(MAX)

string

  • 文章
  • 二进制串行化信息
  • XML数据
  • 大字符数据

对应的UI为双滚动条的多行文本框

 

编码规范(片断节选)

操做数据的方法命名规则

前缀

含义

传入

返回

get

得到单条记录

rowID

单条记录对象

唯一键

search

查询多条记录

唯一键

List<记录对象>

非唯一键

多个参数, [and/or]关系组合

select

查询多条记录

唯一键,[字段名]

List<string>

字段名所对应的[表.字段.ToString()]

非唯一键,[字段名]

多个参数, [and/or]关系组合,[字段名]

change

修改单条

记录对像

执行状态

stringResult.state 执行状态

stringResult.value 出问题的字段

set

修改单条

唯一键,[字段名],[值]

执行状态

rowID,[字段名],[值]

update

修改多条

(事物)

List<记录对象>

执行状态

modify

修改多条

(无事物)

List<记录对象>

无法完成修改的List<记录对象>

insert

添加单条

记录对象

执行状态

add

批量添加

(事物)

List<记录对象>

执行状态

stringResult.state 执行状态

stringResult.value 出问题的字段

append

批量添加

(无事物)

List<记录对象>

无法完成添加的List<记录对象>

remove

删除单条

rowID

执行状态

唯一键

delete

删除多条

(事物)

List<记录对象>

执行状态

clear

删除多条

(事物)

多个参数, [and/or]关系组合

执行状态

wipe

删除多条

(无事物)

List<记录对象>

无法完成删除的List<记录对象>

execute

执行SQL

SQL 字串

 

存储过程

执行状态

stringResult.state 执行状态

stringResult.value 问题

stringResult.state 执行状态

stringResult.value 返回对象的XML

binding

添加单条(关系表)

记录对象

执行状态

unbinding

删除单条(关系表)

rowID

执行状态

[ASP.NET] SWFUpload+Javascript仿163邮件上传文件

mikel阅读(446)

转载:http://www.cnblogs.com/land/archive/2009/10/16/swfupload.html
  时下上传文件一般有三种方式:
    1、使用隐藏的FRAME来模拟AJAX的方式上传文件
    2、使用ACTIVEX上传文件
    3、使用Flash控件+JavaScript上传文件(严格的来说FLASH也算是ACTIVEX)
    一般使用B/S结构上传大文件的应用一般在局域网中使用,在INTERNET中应用的效果还不是很理想。使用INTERNET上传文件一般也就是10-20M左右。
    SWFUpload是老外开发的一个FLASH上传控件,其主页地址是http://www.swfupload.org/,目前最新版本是V2.2.0.1,下载地址是http://code.google.com/p/swfupload/downloads/list,中文文档在这:http://www.v-sky.com/doc/swfupload/v2.1.0/Documentation.html
     其具体使用请大家到官方网站下载吧,DEMO地址:http://demo.swfupload.org/
     页面效果如下图:


    目前上传单个文件的进度条的位置有点偏上,CSS我没调整好,希望各位在调整好进度条显示后把CSS给我发一份!
源码下载

修正

针对网友“Aleax”提出的问题[上传第一个文件后再上传一个文件,上传总进度统计错了],修正如下:
(1)、在demoupload.aspx页面的声明加"queue_complete_handler:queueComplete"
(2)、在handler.js中的queueComplete如下:
function queueComplete(numFilesUploaded)
{
    fg_fileSizes = 0;
    fg_uploads = 0;  
}

  

[TOP]Taobao Open Platform“兵器谱”- TOP架构组件体系介绍

mikel阅读(555)

转载:http://blog.open.taobao.com/archives/32#more-32

放翁(淘宝花名:文初)

Email:fangweng@taobao.com

Blog:http://blog.csdn.net/cenwenchu79

TOP是淘宝开放平台的英文缩写,同时也有顶级优质的英文含义。TOP的整个架构体系是组件化体系架构,可以是很少的几个基础组件构成的 Skeleton,也可以是融入了商业想象的Amazing Architecture。这里就通过对于这些组件的罗列,描述出在TOP这个大体系中,各个组件所处的地位及作用。TOP的“兵器谱”是在现阶段商业需 求及平台非业务性需求指导下形成的,未来TOP将继续发展,“兵器谱”也会不断演进。

下图是整个TOP当前的一个组件结构图:

1

图中,红色虚线就是TOP的Skeleton。TOP当前从业务模块功能角度来划分,可以分成三个层次:基础平台组件层,基础业务组件层,普通业务 组件层。基础平台组件层,倾向于平台级别功能满足及对平台稳定性,可用性的支持。基础业务组件层,是介于平台服务于普通业务服务之间的组件,部分利用了平 台基础组件层的组件,来抽象出一层公用业务服务组件,为业务组件提供通用的基础支持。

安全组件:

安全组件主要从四个角色去考虑整体的安全策略及具体的实施方案,这四个角色是:用户,应用,平台,服务。

2

平台本身的安全主要是基于在大并发和大流量的情况下,保证平台自身稳定性和可用性,同时也要兼顾在平台开放的服务不相互干扰和影响。因此采取服务分 流隔离机制,通过虚拟配置及软负载方式将服务请求动态分流和隔离,保证了服务之间相互的独立性,同时也充分利用TOP的能力。频率控制及流量控制除了保护 TOP自身不受到攻击,也为后端服务提供者作了天然的一个保护屏障,保证服务请求压力可以在TOP上可控,防止流量直接压倒服务提供者。用户隐私安全在淘 宝尤为重要,用户信息的安全性也在淘宝开放的过程中被放到了首位。在开放平台设计中,除了采用普通开放平台的认证模式以外(OAuth类似流程),还在服 务调用过程中通过区分应用角色来限制对于用户信息的获取和使用。同时针对不同的应用类型(插件,Web应用,客户端应用,手机应用)都有各自不同的用户授 权方式,保证用户的知情权。App的安全其实也是为了保证对服务的请求及对用户信息的获取不被不法的应用信息盗取者所利用,根据应用角色及自己对于安全的 需求,采取多种方式或者组合的方式来实现App信息的保密性,保护App自身安全,也保证了平台服务的数据安全。服务安全指的是对于服务来说分成了几个层 级,不同层级的服务对于安全级别的要求不同(不需要交验应用身份,需要交验应用身份,需要用户授权,用户可选择授权等),在应用访问服务的时候,就会需要 根据服务级别的不同采用不同的访问控制流程。根据上述的四个角色对于安全的考虑,通过应用角色的定义,服务虚拟组的编排,黑名单(频率控制及流量控制), 多模式用户令牌等手段,形成了多种模式的安全控制流程。

服务路由组件:

服务路由是开放平台最基本的功能,如果排除商业因素,那么对于TOP最基本上来看可以看作一个服务路由器,服务路由主要的功能如下图展示:3

服务路由组件需要支持多服务类型的服务接入,不同服务类型主要表现在两个维度:1.服务对外的展现方式(REST or RPC),这两种形态的服务没有任何好坏之分,只是根据各自的系统形态来选择采用哪一种模式来对外暴露,RPC比较符合过去应用开放的风格,REST比较 适合面向资源的架构。同时对于同步,异步,通知,大数据量的服务,都会有不同的接入方式和调用方式支持,满足各种业务场景的需求。多通信协议支持,表示服 务请求到了TOP以后,TOP负责将请求继续发送给服务提供者,不论服务提供者采用什么方式和TOP交互,最终将得到的结果返回给客户,服务调用者将会对 后端的服务请求过程透明,同时可以使TOP很容易接入一些传统遗留系统的服务,或者是对通信有特殊需求的服务。特性支持主要是会有对内容的一些特殊处理, 例如压缩,在CS或者手机应用交互过程中,就会需要对数据量有所压缩,满足业务需求。

监控告警组件:

下图是监控告警组件的基本功能图:

4

监控和告警模块在TOP中起到越来越重要的作用,访问量逐日膨胀,运行期TOP是一个黑盒,无法知晓当前系统实际的健康状况,当出现问题以后比较难 以定位。服务监控主要是服务质量(响应时间),短时间段内的服务请求峰值,和阶段性的趋势。系统和平台主要是对底层基础组件的监控,同时及时地通知TOP 负责人处理线上即将要发生的事情。对于应用的监控通常就是从客户端和服务端两面对于应用当前的情况作汇总分析。当监控发现异常以后,就交由告警部分按照一 定的发送策略给相关的负责人,在第一时间将问题解决。

日志组件:

日志组件和其他系统的日志组件基本没有太大的区别,只是在对于海量数据写出和获取的方法做了优化(例如异步分页批量输出等)。日志组件主要负责,打点,收集,分析,数据库记录,归档。

5

协议转换组件:

这里谈到的协议转换指的是对于请求和返回的协议,TOP可以做适配,来满足服务调用者和服务发布者之间在服务协议失配的情况下还是能够正常通信。当 前支持JSON,XML,Atom,二进制协议之间的转换,当然转换描述文档将会配置在TOP。同时返回的数据内容,也可以通过协议转换,返回给客户端常 规的xml或者json类型的数据。

6

服务流程化组件:

服务流程化指的是将离散的服务通过流程描述文档能够虚拟的串联成为一个新的服务,这样更加适合调用者使用,同时将服务的一些内部逻辑隐藏起来。这很 类似于SOA中的服务编排,同时也可以参看Yahoo的Pipe,那就是一种典型的服务串联,同时还提供了方便的界面直接交由用户通过手动拖拉的方式来使 用服务串联。

服务流程化最大的特点就是将不同类型的服务能够根据业务场景的需求组合成简单的流程性服务,极大降低了服务开发者由于对服务流程不熟悉而犯错的几率,同时也为服务开发者提高了开发效率。

7

计费组件:

当前计费模型主要是按流量收费和插件分成两种模式,因此计费组件还比较简单,当前就是基于日志做分析,未来会考虑在流量上的各种特殊模式(打包,优惠等等)。

容器组件(TBML):

产生原因

数据隐私性

开发便利性

业务升级透明化

监控全局化

开发标准化

作用

数据操作可控,保护终端用户隐私(结合cookie和标签,控制ISV业务数据操作尺度,提高数据安全性)

提供标准业务流程标签,简化开发者对于业务流程理解过程。

标签化接口方式,完成数据获取和页面渲染,后台业务升级对ISV透明化。

标签获取客户端信息,将监控扩展到整个业务请求过程。制定行业化标签库,形成统一开发标准

8

TBML首先需要根据业务需求及场景定义出对应的标签库,也就是制定Taobao的标签标准,最简单的获取用户信息标签,到最复杂的业务操作流程标 签都会成为标签库中的一部分。同时在服务端需要有解释引擎来翻译标签,解释引擎一方面需要去了解标签内容和含义,同时需要请求后台多个API,串联成为流 程化的服务,从应用的输入,得到最后的输出,当然期间也需要处理异常的情况。最后还需要关注的就是安全控制,在交验标签传递来的数据时,需要对数据作完整 性及合法性的交验,防止通过标签数据的特殊性攻击后台服务接口。

TBQL组件:

TBQL其实是一种服务调用的方式,也是通过一种程序员和开发者习惯的方式,将对资源的REST请求转换成一种类似QL的请求,对于面向资源性的架构体系来说是十分有利的。同时对于API来说,使用者会更加自然的去采用连接和过滤得方式得到需要的数据。

9

QL解释引擎负责对于TBQL的翻译工作,数据存储的MetaData保存在数据库中,可以指导QL解释引擎翻译。需要支持不同数据来源的连接和过 滤,在获得结果以后需要做格式转换返回给服务调用者(通常就是xml)。与容器一样,需要着重考虑安全性问题,对于传统的SQL注入就是典型攻击QL系统 的案例,需要谨慎处理解析中对于字符的翻译工作。在流程中出现异常,需要制定策略来判断是否直接返回错误还是支持部分容错。

TOPID组件:

TOPID组件有点类似于Facebook的Connect,需要在淘宝和淘宝的合作开发者之间建立起双向的用户互通的标准和流程,同时也为服务互通打好基础,毕竟业务的互动需要基于可以互通的用户体系。

以上仅仅只是简单的罗列了一下TOP技术体系架构中的一些组件化的内容,同时在这些组件的背后有着更多的基础性项目的支持,例如统一配置中心对于系 统动态扩容的支持,分布式缓存对于监控告警的支持,分布式文件系统对于海量小文件保存和获取的支持等等。同时以上每一个模块都有各自特殊的定制和优化,例 如路由模块就需要有Lazy的服务参数解析模式来提高处理性能,安全体系中需要有动态密钥机制来保证高安全性等等。

TOP从萌芽走向成熟,不论从技术架构还是商业规划都处于不断摸索和改进的过程,当前的技术体系仅仅是现阶段的一个需求缩影,未来在市场不断成熟,开发者不断介入和反馈的情况下,TOP会走得更快更远,TOP的“兵器谱”会更加丰富,更加出彩。

[Oracle]Oracle Access SQL Server类型对照表

mikel阅读(505)

   Access, SQL Server, and oracle数据类型的对应关系

The table below shows the ADO Data Type mapping between Access, SQL Server, and oracle:

DataType Enum Value Access SQLServer Oracle
adBigInt 20   BigInt (SQL Server 2000 +)  
adBinary 128   Binary
TimeStamp
Raw *
adBoolean 11 YesNo Bit  
adChar 129   Char Char
adCurrency 6 Currency Money
SmallMoney
 
adDate 7 Date DateTime  
adDBTimeStamp 135 DateTime (Access 97 (ODBC)) DateTime
SmallDateTime
Date
adDecimal 14     Decimal *
adDouble 5 Double Float Float
adGUID 72 ReplicationID (Access 97 (OLEDB)), (Access 2000 (OLEDB)) UniqueIdentifier (SQL Server 7.0 +)  
adIDispatch 9      
adInteger 3 AutoNumber
Integer
Long
Identity (SQL Server 6.5)
Int
 
Int *
adLongVarBinary 205 OLEObject Image Long Raw *
Blob (Oracle 8.1.x)
adLongVarChar 201 Memo (Access 97)
Hyperlink (Access 97)
Text Long *
Clob (Oracle 8.1.x)
adLongVarWChar 203 Memo (Access 2000 (OLEDB))
Hyperlink (Access 2000 (OLEDB))
NText (SQL Server 7.0 +) NClob (Oracle 8.1.x)
adNumeric 131 Decimal (Access 2000 (OLEDB)) Decimal
Numeric
Decimal
Integer
Number
SmallInt
adSingle 4 Single Real  
adSmallInt 2 Integer SmallInt  
adUnsignedTinyInt 17 Byte TinyInt  
adVarBinary 204 ReplicationID (Access 97) VarBinary  
adVarChar 200 Text (Access 97) VarChar VarChar
adVariant 12   Sql_Variant (SQL Server 2000 +) VarChar2
adVarWChar 202 Text (Access 2000 (OLEDB)) NVarChar (SQL Server 7.0 +) NVarChar2
adWChar 130   NChar (SQL Server 7.0 +)  

* In oracle 8.0.x – decimal and int are equal to number and number(10).