[WCF编程]12.事务:服务事务编程(上)
一、设置环境事务
默认情况下,服务类和操作没有环境事务,即使客户端事务传播到服务端也是如此。
尽管强制事务流从客户端传播过来,但服务端的环境事务依旧为null。为了启用环境事务,每个操作必须告诉WCF启用事务。为了解决这个问题,WCF提供了OperationBehaviorAttribute的TransactionScopeRequired属性:
// 指定服务方法的本地执行行为。
[AttributeUsage(AttributeTargets.Method)]
public sealed class OperationBehaviorAttribute : Attribute, IOperationBehavior
{
//......
// 获取或设置一个值,该值指示方法在执行时是否需要事务环境。
public bool TransactionScopeRequired { get; set; }
}TransactionScopeRequired的默认值为false。这就是为何默认情况下服务没有环境事务的原因了。将TransactionScopeRequired设置为true,将会为操作启用环境事务。
public class MyService : IMyService
{
[OperationBehavior(TransactionScopeRequired=true)]
public void MyMethod()
{
Transaction transaction = Transaction.Current;
Debug.Assert(transaction != null);
}
}如果客户端事务传播给服务,WCF会把客户端事务作为操作的环境事务。如果没有传播,WCF会为操作创建一个新的事务,并把此事务视为操作的环境事务。
服务类构造函数没有事务,他不能参与到客户端事务里,所以不能让WCF将它加入到事务域中来。除非你手动创建环境事务,否则不要在服务构造函数里执行事务代码,构造函数中的代码不会加入到客户端事务。
下图所展示的是服务使用的事务,这个事务是有绑定,操作契约属性来分配的:
在上图中,非事务客户端调用服务1,服务1的操作契约配置为TranscationFlowOption.Allowed(允许参与事务,如果调用方启用了事务,则参与),尽管绑定允许事务流传播,但是由于客户端没有包含事务,所以无法传播事务。服务1的操作配置需要事务域。因此,WCF为服务1创建了一个新的事务A。服务1随后调用其它三个服务。服务2使用的绑定也是允许事务流操作,而且操作契约强制需要客户端事务流。因为操作行为配置需要配置事务流,WCF把事务A设置为服务2的环境事务。服务3的绑定和操作契约不允许事务流传播。但是,因为服务3的操作需要事务域,WCF为此创建了一个新的事务B,并作为服务3的环境事务。与服务3类似,服务4的绑定与操作也不允许事务流 传播,但是服务4不需要事务域,所以WCF不会给它创建环境事务。
二、事务传播模式
服务使用哪个事务取决于绑定的事务流属性(两个值)、操作契约事务(三个值),以及操作行为的事务域(两个值)的设置。下表列出了可行的八种组合:
八种组合实际产生四种有效的事务传播模式,即客户端/服务、客户端、服务和None。上表也列出了每种模式推荐的配置。每种模式在应用程序中都有用武之地。
1.客户端/服务事务模式
如果客户端启用了事务,则服务端就参与事务;如果客户端没有启用事务,则服务端独立启用事务。即不管客户端是否启用事务,服务端总是运行在事务中。
实现步骤:
a.选择一个支持事务的绑定,设置TransactionFlow = true。
b.在方法契约上添加TransactionFlowAttribute声明,设置TransactionFlow(TransactionFlowOption.Allowed)。
c.在方法行为上声明OperationBehavior(TransactionScopeRequired=true)。客户端/服务事务模式是最解耦的配置,因为服务端尽量不去考虑客户端的工作。服务会在客户端事务流传播的时候允许加入客户端事务。
服务代码:
[ServiceContract]
public interface IClientServiceTransaction
{
[OperationContract]
//如果客户端启用了事务,则服务端参与事务
[TransactionFlow(TransactionFlowOption.Allowed)]
void CSMethod();
}</span><span style="color: #0000ff">public</span> <span style="color: #0000ff">class</span><span style="color: #000000"> ClientServiceTransaction : IClientServiceTransaction
{
</span><span style="color: #008000">//</span><span style="color: #008000">服务端代码必须置于服务中执行</span>
[OperationBehavior(TransactionScopeRequired = <span style="color: #0000ff">true</span><span style="color: #000000">)]
</span><span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span><span style="color: #000000"> CSMethod()
{
</span><span style="color: #008000">//</span><span style="color: #008000">获取当前事务对象</span>
Transaction transaction =<span style="color: #000000"> Transaction.Current;
</span><span style="color: #008000">//</span><span style="color: #008000">注册事务流执行结束的事件方法</span>
transaction.TransactionCompleted += <span style="color: #0000ff">new</span><span style="color: #000000"> TransactionCompletedEventHandler(transaction_TransactionCompleted);
</span><span style="color: #008000">//</span><span style="color: #008000">显示事务的本地ID</span>
Debug.WriteLineIf(transaction != <span style="color: #0000ff">null</span>, <span style="color: #800000">"</span><span style="color: #800000"><服务端>事务本地ID:</span><span style="color: #800000">"</span> +<span style="color: #000000"> transaction.TransactionInformation.LocalIdentifier);
}
</span><span style="color: #008000">//</span><span style="color: #008000">事务流执行结束时会触发此方法</span>
<span style="color: #0000ff">void</span> transaction_TransactionCompleted(<span style="color: #0000ff">object</span><span style="color: #000000"> sender, TransactionEventArgs e)
{
</span><span style="color: #008000">//</span><span style="color: #008000">显示事务全局的ID</span>
Debug.WriteLine(<span style="color: #800000">"</span><span style="color: #800000"><服务端>事务全局ID:</span><span style="color: #800000">"</span> +<span style="color: #000000"> e.Transaction.TransactionInformation.DistributedIdentifier);
</span><span style="color: #008000">//</span><span style="color: #008000">显示事务的执行结果</span>
Debug.WriteLine(<span style="color: #800000">"</span><span style="color: #800000"><服务端>事务执行结果</span><span style="color: #800000">"</span> +<span style="color: #000000"> e.Transaction.TransactionInformation.Status);
} }</span></pre></div>
服务配置代码:
<system.serviceModel>
<services>
<service name="WCF.Service.ClientServiceTransaction">
<endpoint address="ClientServiceTransaction" contract="WCF.Service.IClientServiceTransaction" binding="netTcpBinding"/>
<endpoint address="ClientServiceTransaction/mex" binding="mexTcpBinding" contract="IMetadataExchange"/>
<host>
<baseAddresses>
<add baseAddress="net.tcp://127.0.0.1:9000/"/>
</baseAddresses>
</host>
</service>
</services>
<bindings>
<netTcpBinding>
<binding transactionFlow="true" transactionProtocol="WSAtomicTransactionOctober2004">
<reliableSession enabled="true"/>
</binding>
</netTcpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="false" httpsGetEnabled="false"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<diagnostics performanceCounters="All"/>
</system.serviceModel>客户端代码:
class Program
{
static void Main(string[] args)
{
ClientServiceTransactionClient prox = new ClientServiceTransactionClient("NetTcpBinding_IClientServiceTransaction");
//第一次调用,客户端没有启用事务
prox.CSMethod();
using (TransactionScope ts = new TransactionScope())
{
Transaction.Current.TransactionCompleted += new TransactionCompletedEventHandler(Current_TransactionCompleted);
Console.WriteLine("<客户端>事务本地ID:" + Transaction.Current.TransactionInformation.LocalIdentifier);
//第二次调用事务,客户端启用了分布式事务
prox.CSMethod();</span><span style="color: #008000">//</span><span style="color: #008000">事务提交。如果提交,事务流会执行成功;如果不提交的话,事务流会回滚。
</span><span style="color: #008000">//</span><span style="color: #008000">ts.Complete();</span>
}
Console.ReadLine();
}</span><span style="color: #008000">//</span><span style="color: #008000">事务流执行结束时会触发此方法</span>
<span style="color: #0000ff">static</span> <span style="color: #0000ff">void</span> Current_TransactionCompleted(<span style="color: #0000ff">object</span><span style="color: #000000"> sender, TransactionEventArgs e)
{
Console.WriteLine(</span><span style="color: #800000">"</span><span style="color: #800000"><客户端>事务全局ID:</span><span style="color: #800000">"</span> +<span style="color: #000000"> e.Transaction.TransactionInformation.DistributedIdentifier);
Console.WriteLine(</span><span style="color: #800000">"</span><span style="color: #800000"><客户端>事务执行结果:</span><span style="color: #800000">"</span> +<span style="color: #000000"> e.Transaction.TransactionInformation.Status);
}
}</span></pre></div>
运行结果:
结论:
从图中我们看到:
1.服务端第一次执行成功,事务有本地ID,但没有全局ID。这说明虽然客户端调用没有启用事务,但服务端代码仍在事务中运行,该事务是服务端本地事务。
2.客户的全局事务ID与服务端的全局事务ID相同,这说明客户端与服务端处于同一个事务流中。但二者本地的事务ID不同,这说明它们各自是处于全局“大事务”中的本地“小事务”。由此得出,服务端代码仍在事务中运行,并参与到客户端事务流中
3.由于客户端代码中ts.Complete()被注释了,所以客户端事务执行不会提交,从而导致服务端事务提交失败,全局事务流提交失败。总结:
Client/Service事务模型是最常见的,它对客户端准备了“两手应对策略”:
当客户端启动了事务流的话,服务就参与事务流中,以维持整个系统的一致性,这样客户端的操作和服务端的操作会做为一个整体进行操作,任何一处的操作产生异常都会导致整个事务流的回滚。
如果客户端没有启动事务流,服务端的操作仍需要在事务的保护下运行,它会自动启动事务保护。2.客户端模式
Client事务模型必须由客户端启动分布式事务,并强制服务端必须参与客户端事务流。
当服务端必须使用客户端事务且设计上不能单独工作时,应该选用客户端事务模式。使用这个模式的主要目的就是为了最大化地保持一致性,因为客户端与服务端的操作需作为一个原子操作。还有一个重要原因,即服务共享客户端的事务可以降低死锁的风险,因为所有被访问的资源都会加载到相同的事务里。这意味着事务不可能再访问相同的资源和事务锁。
实现步骤:
a.选择一个支持事务的Binding,设置 TransactionFlow = true。
b.在方法契约上添加TransactionFlowAttribute声明,设置TransactionFlow(TransactionFlowOption.Mandatory)。
c.在方法行为上声明OperationBehavior(TransactionScopeRequired=true)。服务代码:
/// <summary>
/// 客户端模式
/// </summary>
[ServiceContract]
public interface IClientTransaction
{
[OperationContract]
//强制把当前事务加入客户端事务流中
[TransactionFlow(TransactionFlowOption.Mandatory)]
void TestMethod();
}
public class ClientTransaction : IClientTransaction
{
//服务端代码必须置于服务中执行
[OperationBehavior(TransactionScopeRequired = true)]
public void TestMethod()
{
Transaction transaction = Transaction.Current;
transaction.TransactionCompleted += new TransactionCompletedEventHandler(transaction_TransactionCompleted);
Debug.WriteLineIf(transaction != null, "<服务端>事务本地ID:" + transaction.TransactionInformation.LocalIdentifier);
}
void transaction_TransactionCompleted(object sender, TransactionEventArgs e)
{
Debug.WriteLine("<服务端>事务全局ID:" + e.Transaction.TransactionInformation.DistributedIdentifier);
Debug.WriteLine("<服务端>事务执行结果:" + e.Transaction.TransactionInformation.Status);
}}</span></pre></div>
服务配置代码:
<system.serviceModel>
<services>
<service name="WCF.ServiceForClient.ClientTransaction">
<endpoint address="ClientTransaction" contract="WCF.ServiceForClient.IClientTransaction" binding="netTcpBinding"/>
<endpoint address="ClientTransaction/mex" binding="mexTcpBinding" contract="IMetadataExchange"/>
<host>
<baseAddresses>
<add baseAddress="net.tcp://127.0.0.1:9000/"/>
</baseAddresses>
</host>
</service>
</services>
<bindings>
<netTcpBinding>
<binding transactionFlow="true" transactionProtocol="WSAtomicTransactionOctober2004">
<reliableSession enabled="true"/>
</binding>
</netTcpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="false" httpsGetEnabled="false"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<diagnostics performanceCounters="All"/>
</system.serviceModel>
</configuration>客户端代码:
/// <summary>
/// 客户端事务
/// </summary>
class Program
{
static void Main(string[] args)
{
//客户端不启用事务,会产生异常
//ClientTransactionClient prox = new ClientTransactionClient();
//prox.Open();
//prox.TestMethod();
//prox.Close();</span><span style="color: #008000">//</span><span style="color: #008000">------------------------------------------ </span><span style="color: #008000">//</span><span style="color: #008000">客户端启用事务</span>
ClientTransactionClient prox = <span style="color: #0000ff">new</span><span style="color: #000000"> ClientTransactionClient();
prox.Open();
</span><span style="color: #0000ff">using</span> (TransactionScope ts = <span style="color: #0000ff">new</span><span style="color: #000000"> TransactionScope())
{
prox.TestMethod();
</span><span style="color: #008000">//</span><span style="color: #008000">获取当前事务对象</span>
Transaction trans =<span style="color: #000000"> Transaction.Current;
</span><span style="color: #008000">//</span><span style="color: #008000">注册服务结束事件方法</span>
trans.TransactionCompleted += <span style="color: #0000ff">new</span><span style="color: #000000"> TransactionCompletedEventHandler(trans_TransactionCompleted);
</span><span style="color: #008000">//</span><span style="color: #008000">显示事务本地ID;</span>
Console.WriteLine(<span style="color: #800000">"</span><span style="color: #800000"><客户端>事务本地ID:</span><span style="color: #800000">"</span> +<span style="color: #000000"> trans.TransactionInformation.LocalIdentifier);
</span><span style="color: #008000">//</span><span style="color: #008000">提交事务</span>
ts.Complete();
}
prox.Close();Console.ReadLine();
}
</span><span style="color: #008000">//</span><span style="color: #008000">事务结束触发的事件</span>
<span style="color: #0000ff">static</span> <span style="color: #0000ff">void</span> trans_TransactionCompleted(<span style="color: #0000ff">object</span><span style="color: #000000"> sender, TransactionEventArgs e)
{
Console.WriteLine(</span><span style="color: #800000">"</span><span style="color: #800000"><客户端>事务全局ID:</span><span style="color: #800000">"</span> +<span style="color: #000000"> e.Transaction.TransactionInformation.DistributedIdentifier);
Console.WriteLine(</span><span style="color: #800000">"</span><span style="color: #800000"><客户端>事务执行结果:</span><span style="color: #800000">"</span> +<span style="color: #000000"> e.Transaction.TransactionInformation.Status);
}
}</span></pre></div>
运行结果:
如果客户端没有启用事务会产生异常信息
如果客户端启用事务,则客户端会和服务端会使用同一事务流
这种事务模式,服务端不能独立启动事务,服务端事务必须参与客户端事务流中,确保客户端和服务端处于同一事务流中,这样客户端和服务端的代码会做为一个原子执行,当事务流中任何一个环节产生异常都会把整个事务流进行回滚,实现非常好的一致性。
3.服务事务模型
这种事务模型是把服务端事务与客户端事务分离开,服务端代码执行总是会创建自己的事务,并不会参与到客户端事务中去。所以客户端的事务启用与否并不影响服务端事务的执行。
实现步骤:
a.可以使用任何绑定信道。如果选择的是支持事务的绑定,需要设置TransactionFlow = false,因为服务端事务独立启动,并不需要事务流。
b.不需要在方法契约上添加TransactionFlowAttribute声明。如果你非得设置此Attribute的话,请设置TransactionFlow(TransactionFlowOption.NotAllowed),指明服务端拒绝参与事务流。
c.在方法行为上声明OperationBehavior(TransactionScopeRequired=true)。指明服务端需要自己启用事务。当服务端工作不需要在客户端事务范围内完成时,可以选择服务端事务模式(连例如,日志或审计操作,或者不论客户端事务提交成功或终止,都像将事件给服务端)。
例如,我们编写一个记录操作日志的服务,客户端所做的每一步操作都需要调用服务端的方法进行记录。这个日志记录服务端就适用于Service服务模型,不管客户端事务是否正常提交,服务端记录日志的事务不受影响。如果采取的是Client/Service事务模型或Client事务模型的话,当客户端事务没有提交成功,会导致服务端日志无法正常记录。
服务代码:
/// <summary>
/// 服务端事务模式
/// </summary>
[ServiceContract]
public interface IServiceTransaction
{
[OperationContract]
//禁用事务流功能
[TransactionFlow(TransactionFlowOption.NotAllowed)]
void TestMethod();
}
public class ServiceTransaction : IServiceTransaction
{
//服务端代码必须置于服务中执行
[OperationBehavior(TransactionScopeRequired = true)]
public void TestMethod()
{
Transaction transaction = Transaction.Current;
transaction.TransactionCompleted += new TransactionCompletedEventHandler(transaction_TransactionCompleted);
Debug.WriteLineIf(transaction != null, "<服务端>事务本地ID" + transaction.TransactionInformation.LocalIdentifier);
}
void transaction_TransactionCompleted(object sender, TransactionEventArgs e)
{
Debug.WriteLine("<服务端>事务全局ID:" + e.Transaction.TransactionInformation.DistributedIdentifier);
Debug.WriteLine("<服务端>事务执行结果:" + e.Transaction.TransactionInformation.Status);
}
}服务配置代码:
<system.serviceModel>
<services>
<service name="WCF.ServiceForService.ServiceTransaction">
<endpoint address="ServiceTransaction" contract="WCF.ServiceForService.IServiceTransaction" binding="netTcpBinding"/>
<endpoint address="ServiceTransaction/mex" binding="mexTcpBinding" contract="IMetadataExchange"/>
<host>
<baseAddresses>
<add baseAddress="net.tcp://127.0.0.1:9000/"/>
</baseAddresses>
</host>
</service>
</services>
<bindings>
<netTcpBinding>
<binding transactionFlow="true" transactionProtocol="WSAtomicTransactionOctober2004">
<reliableSession enabled="true"/>
</binding>
</netTcpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="false" httpsGetEnabled="false"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<diagnostics performanceCounters="All"/>
</system.serviceModel>客户端代码:
public static void Main(string[] args)
{
ServiceTransactionClient prox = new ServiceTransactionClient();
prox.Open();
using (TransactionScope ts = new TransactionScope())
{
prox.TestMethod();
Transaction trans = Transaction.Current;
trans.TransactionCompleted += new TransactionCompletedEventHandler(trans_TransactionCompleted);
Console.WriteLine("<客户端>事务本地ID:" + trans.TransactionInformation.LocalIdentifier);
//ts.Complete();
}
prox.Close();
Console.ReadLine();
}
static void trans_TransactionCompleted(object sender, TransactionEventArgs e)
{
Console.WriteLine("<客户端>事务全局ID:" + e.Transaction.TransactionInformation.DistributedIdentifier);
Console.WriteLine("<客户端>事务执行结果:" + e.Transaction.TransactionInformation.Status);
}运行结果:
结论:
从图中我们可以看到:
服务端本地事务ID不为空,说明服务端代码仍处于事务中执行。但全局事务ID都是空的,说明这种事务模型不存在全局型事务流。
还管客户端事务执行是否成功,服务端事务总是成功执行。总结:
这种事务模型一般应用于:当服务端需要在客户端事务流之外独立运行事务的情况。4.None事务模式
这种种事务模型中服务端代码不启用任何事务也不参与任何事务流。
实现步骤:
a.可以使用任何绑定信道。如果选择的是支持事务的绑定,需要设置TransactionFlow = false,因为服务端事务独立启动,并不需要事务流。
b.不需要在方法契约上添加TransactionFlowAttribute声明。如果你非得设置此Attribute的话,请设置TransactionFlow(TransactionFlowOption.NotAllowed),指明服务端拒绝参与事务流。
c.不需要在方法行为上添加TransactionScopeRequired属性声明,如果你非要设置此属性的话,请设置OperationBehavior(TransactionScopeRequired=false)。指明此方法执行过程中不使用事务。即默认情况下,服务是不使用事务的。
None事务模式允许开发非事务型服务,它可以被事务型客户端调用。
显然这种事务模型很危险,它破坏了系统的一致性:如果客户端在执行过程中产生异常时,将不会回滚服务端的数据。一般这在一些不会出现不一致性的系统中采用这种模型。
事务模型的选择
上面所述的四种事务模型中,Service模型和None模型用得比较少,这两种模式带系统不一致的潜在危险。一般在需要事务流控制的地方,我们应选择Client/Service模型或Client模型来确保客户端和服务端之间系统一致。
三、实例代码下载
点击下载
[WCF编程]12.事务:服务事务编程(上)的更多相关文章
- [WCF编程]12.事务:服务事务编程(下)
一.投票与提交 虽然WCF负责事务传播及两阶段提交协议的管理工作,但是 她不知道事务是否应该提交或终止.这需要根服务告诉WCF应该何时启动两阶段提交协议.是提交还是终止.WCF提供了两种编程模式来对事 ...
- [WCF编程]12.事务:事务协议与管理器
一.事务协议 总体来说,WCF开发人员不需要涉及事务协议与管理器.我们应该依赖WCF来选择相应的事务协议和管理器,重点关注业务逻辑的实现. WCF是根据事务范围里的参与个体来选择事务管理协议的.事务管 ...
- [WCF编程]12.事务:事务概述
一.事务概述 维护系统一致性和正确地处理错误恢复挑战的最佳方式是使用事务. 一个事务就是一个复杂操作的集合,这个集合中任何一个操作的失败都会引起整个集合的失败. 尽管在事务进行时系统被允许暂时出于不一 ...
- 使用WCF实现SOA面向服务编程—— 架构设计
原文地址:http://www.cnblogs.com/leslies2/archive/2011/03/29/1997889.html SOA本身就是一种面向企业级服务的系统架构,简单来说,SOA就 ...
- Spring事务服务
Spring事务服务 (2013-07-22 11:13:36) 转载▼ 标签: 事务管理 ssh 分类: Sping Spring为事务管理提供了一流的支持.同时支持编程式事务和声明式事务.无论是编 ...
- 《Linux多线程服务端编程:使用muduo C++网络库》上市半年重印两次,总印数达到了9000册
<Linux多线程服务端编程:使用muduo C++网络库>这本书自今年一月上市以来,半年之内已经重印两次(加上首印,一共是三次印刷),总印数达到了9000册,这在技术书里已经算是相当不错 ...
- http服务&ajax编程
http服务&ajax编程 1.服务器 前言:通俗的讲,能够提供某种服务的机器(计算机)称为服务器 1.1.服务器类型 按照不同的划分标准,服务可划分为以下类型: 按服务类型可分为:文件服务器 ...
- C# 6 与 .NET Core 1.0 高级编程 - 41 ASP.NET MVC(上)
译文,个人原创,转载请注明出处(C# 6 与 .NET Core 1.0 高级编程 - 41 ASP.NET MVC(上)),不对的地方欢迎指出与交流. 章节出自<Professional C# ...
- TCP/IP网络编程之多进程服务端(二)
信号处理 本章接上一章TCP/IP网络编程之多进程服务端(一),在上一章中,我们介绍了进程的创建和销毁,以及如何销毁僵尸进程.前面我们讲过,waitpid是非阻塞等待子进程销毁的函数,但有一个不好的缺 ...
随机推荐
- python自动化测试(3)- 自动化框架及工具
python自动化测试(3) 自动化框架及工具 1 概述 手续的关于测试的方法论,都是建立在之前的文章里面提到的观点: 功能测试不建议做自动化 接口测试性价比最高 接口测试可以做自动化 后面所谈到 ...
- 深入浅出Alljoyn——实例分析之远程调用(Method)篇
深入浅出就是很深入的学习了很久,还是只学了毛皮,呵呵! 服务端完整代码: #include <qcc/platform.h> #include <assert.h> #incl ...
- JS实战 · 收缩菜单表单布局
获取节点的两种方式: 1.通过event对象的srcElement属性: 2.通过事件源对象用this传入. 代码如下: <html> <head> ...
- 几个最常用的用来代替Div的HTML5元素
虽说html5中大多数功能性的元素如<video><canvas><audio>等还得不到当前主流浏览器的支持(主要就是指IE浏览器了),但至少那些个与布局相关的元 ...
- Css概要与选择器,刻度单位
目录 一.CSS3概要 1.1.特点 1.2.效果演示 1.3.帮助文档与学习 二.选择器 1.1.基础的选择器 1.2.组合选择器 1.3.属性选择器 1.4.伪类 1.5.伪元素 三.特殊性(优先 ...
- 彻底理解nth-child和nth-of-type的区别。
最近又有些天没写博客了,主要写一篇下来,太浪费时间了,其实这不是根本,根本是最近比较忙,忙什么呢?最近发现一个问题觉得学习速度太慢了,时间倒是花的很多,但大部分时间都花在无意义的事情上,所有打算改变政 ...
- 异步方法不能使用ref和out的解决方法
异常处理汇总-后端系列:http://www.cnblogs.com/dunitian/p/4523006.html 应用场景==>后端现在都是用异步方法,那么分页是必不可少的,于是就有了这个问 ...
- Sql Server系列:日期和时间函数
1. 获取系统当前日期函数GETDATE() GETDATE()函数用于返回当前数据库系统的日期和时间,返回值的类型为datetime. SELECT GETDATE() 2. 返回UTC日期的函数G ...
- Unity基础知识学习笔记二
1,object Instantiate(object original,Vector3 position,Quaternion rotation) 克隆原始物体,并返回克隆物体. ...
- 浅谈requireJS
项目中大都使用模块化开发,requireJS作为AMD模块开发的典范,所以有必要学习下.通过一步步利用requireJS编写demo,从而学习requireJS的一个整体开发流程以及自我使用requi ...






