[转载]浅谈SQL SERVER中事务的ACID

mikel阅读(1031)

[转载]浅谈SQL SERVER中事务的ACID – CareySon – 博客园.

简介

ACID,是指在可靠数据库管理系统(DBMS)中,事务(transaction)所应该具有的四个特性:原子性(Atomicity)、一致性 (Consistency)、隔离性(Isolation)、持久性(Durability).这是可靠数据库所应具备的几个特性.下面针对这几个特性进 行逐个讲解.

理解原子性(Atomicity)

原子性意味着数据库中的事务执行是作为原子。即不可再分,整个语句要么执行,要么不执行。

SQL SERVER中,每一个单独的语句都可以看作是默认包含在一个事务之中:

1

所以,每一个语句本身具有原子性,要么全部执行,这么全部不执行,不会有中间状态:

2

上面说了,每一条T-SQL语句都可以看作是默认被包裹在一个事务之中的,SQL Server对于每一条单独的语句都实现了原子性,但这种原子粒度是非常小的,如果用户想要自己定义原子的大小,则需要包含在事务中来构成用户自定义的原子粒度:

3

对于用户来说,要用事务实现的自定义原子性往往是和业务相关的,比如银行转账,从A账户减去100,在B账户增加100,如果这两个语句不能保证原子性的 话,比如从A账户减去100后,服务器断电,而在B账户中却没有增加100.虽然这种情况会让银行很开心,但作为开发人员的你可不希望这种结果.而默认事 务中,即使出错了也不会整个事务进行回滚。而是失败的语句抛出异常,而正确的语句成功执行。这样会破坏原子性。所以SQL SERVER给予了一些选项来保证事务的原子性.

SQL SERVER提供了两大类方式来保证自定义事务的原子性:

1.通过SET XACT_ABORT ON来设置事务必须符合原子性

利用设置XACT_ABORT选项设置为ON,来设置所有事务都作为一个原子处理.下面例子利用两个语句插入到数据库,可以看到开启SET XACT_ABORT ON选项后,事务具有了原子性:

4

2.按照用户设置进行回滚(ROLLBACK)

这种方式具有更高的灵活性,开发人员可以自定义在什么情况进行ROLLBACK,利用TRY CATCH语句和@@ERROR进行判断都属于这种方式.

5

理解一致性(Consistency)

一致性,即在事务开始之前和事务结束以后,数据库的完整性约束没有被破坏。

一致性分为两个层面

1.数据库机制层面

数据库层面的一致性是,在一个事务执行之前和之后,数据会符合你设置的约束(唯一约束,外键约束,Check约束等)和触发器设置.这一点是由SQL SERVER进行保证的.

2.业务层面

对于业务层面来说,一致性是保持业务的一致性.这个业务一致性需要由开发人员进行保证.很多业务方面的一致性可以通过转移到数据库机制层面进行保证.比如,产品只有两个型号,则可以转移到使用CHECK约束使某一列必须只能存这两个型号.

理解隔离性(Isolation)

隔离性。事务的执行是互不干扰的,一个事务不可能看到其他事务运行时,中间某一时刻的数据。

在Windows中,如果多个进程对同一个文件进行修改是不允许的,Windows通过这种方式来保证不同进程的隔离性:

Lock

而SQL Server中,通过SQL SERVER对数据库文件进行管理,从而可以让多个进程可以同时访问数据库:

6

SQL Server利用加锁和阻塞来保证事务之间不同等级的隔离性.

一般情况下,完全的隔离性是不现实的,完全的隔离性要求数据库同一时间只执行一条事务,这样的性能可想而知.想要理解SQL Server中对于隔离性的保障,首先要了解事务之间是如何干扰的.

事务之间的互相影响的情况分为几种,分别为:脏读(Dirty Read),不可重复读,幻读

脏读

脏读意味着一个事务读取了另一个事务未提交的数据,而这个数据是有可能回滚的:

7

下面来看一个例子:

两个事务,事务A插入一条数据,但未提交,事务B在此期间进行了读取,读取到了事务A未提交的数据,造成脏读

8

不可重复读(Unrepeatable Read)

不可重复读意味着,在数据库访问中,一个事务范围内两个相同的查询却返回了不同数据。这是由于查询时系统中其他事务修改的提交而引起的。

9

下面来看一个不可重复读的例子:

事务B中对某个查询执行两次,当第一次执行完时,事务A对其数据进行了修改。事务B中再次查询时,数据发生了改变:

10

11

幻读(phantom read)

幻读,是指当事务不是独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。同时,第二个事务也修改这 个表中的数据,这种修改是向表中插入一行新数据。那么,以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行,就好象发生了幻觉一样.

13

下面来看一个例子:

事务B更新表中所有的数据,在此期间事务A插入了一条数据,事务B再次查询后,发现居然还有没有修改的数据,产生幻读:

12

理解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通过阻塞来阻止脏读,所以保持独立性会以付出性能作为代价:

14

理解持久性(Durability)

持久性,意味着在事务完成以后,该事务所对数据库所作的更改便持久的保存在数据库之中,并不会被回滚。

即使出现了任何事故比如断电等,事务一旦提交,则持久化保存在数据库中.

SQL SERVER通过write-ahead transaction log来保证持久性。write-ahead transaction log的意思是,事务中对数据库的改变在写入到数据库之前,首先写入到事务日志中。而事务日志是按照顺序排号的(LSN)。当数据库崩溃或者服务器断点 时,重启动SQL SERVER,SQL SERVER首先会检查日志顺序号,将本应对数据库做更改而未做的部分持久化到数据库,从而保证了持久性.

总结

本文简单讲述了ACID的概念和ACID在SQL SERVER中的实现.ACID只是一个理念,并不是某项具体的技术.对于健壮数据库来说,保证ACID是可靠数据库的前提.

[转载]真心好用的VS扩展--NuGet

mikel阅读(898)

转载真心好用的VS扩展–NuGet – 黄云坤 – 博客园.

无聊中手机上网翻到的,先没明白这是什么东西,等我实际体验了一把以后完全震惊了,太给力了!

NuGet的官方说明是:NuGet是一款Visual Studio的扩展,它可以简单的安装、升级开源库和工具。

官网地址:http://www.nuget.org/

官网最醒目的位置就是下载链接,安装完成后我们来快速体验一把。

手上有个小项目需要使用到json格式,一般情况我会先Google一下有没有相关的开源库(这个肯定是有的)。

然后从一些博文中发现了Json.net,然后继续Google之,找到Json.net的官网,然后下载最新的稳定版本,找出DLL文件引用它。

是不是很复杂?很繁琐?(其实没用NuGet之前我一直觉得这样干很方便的)

使用NuGet我们就可以很快搞定了。

右键Managet NuGet Packages

nuget1

搜索json,然后看看结果和右侧的介绍,Json.net排在第一位,点Install安装。

nuget2

然后等待下载完成,可以看到引用里面已经有了Json.net了。

nuget3

那么NuGet到底干了什么呢?下载的开源库在何处呢?看一下输出结果就知道了。

nuget4

在packages文件夹下可以找到相关dll文件。

nuget5

还有命令行模式可以选用

还是以Json.net举例,输入Install-Package Newtonsoft.Json即可。

nuget7

NuGet还有一个优势就是可以处理依赖(我个人觉得Net的依赖复杂程度没有java麻烦)。以Spring.Core为例子,它依赖Common.Logging。

自然NuGet完美解决了。

nuget9

我没有试升级库功能,但是个人感觉NuGet还是有一些局限的。

首先需要联网,其次是每次都下载新的,而且会把针对不同.Net版本的都down下来。

[转载]C#字符串与享元(Flyweight)模式

mikel阅读(874)

[转载]C#字符串与享元(Flyweight)模式 – winter-cn – 博客园.

写这个文章,主要是因为网上对C#字符串和享元模式的误解比较多。

Flyweight模式

先说这名字,fly呢,就是苍蝇,没错这里面不是飞的意思,是苍蝇的意思,weight大家都知道,就是重量,苍蝇的重量,就是非常非常轻的意思。所以Flyweight模式就是处理非常非常轻量级对象的一个东西。

Flyweight的目标是解决大量细粒度对象的内存消耗问题,当然,巧妇难为无米之炊,任何模式和手法都不能凭空造出内存来,所以享元模式针对的情况是这些细粒度对象的中数据有重复的情况。

Flyweight的做法是,把对象的状态(通常用属性表示),分成两个部分,一部分是内部状态,另一部分是外部状态。内部状态是不易重复的(或者说必要的),外部状态是易重复的。所以,Flyweight把外部状态提取出来共享,这样就一定程度解决了内存占用问题。

C#中的字符串不是Flyweight模式

在网上常常可以看到一个说法,说C#中的字符串使用了Flyweight模式,开门见山地说,这个说法是错误的。

错在哪里呢?按照上文的介绍,错就错在字符串它没有所谓的“内部状态”。

通常讲字符串是享元的原因就是以下代码:

string a = “Hello World”;
Console.WriteLine(Object.ReferenceEquals(a, “Hello World”)); //True

当使用字符串直接量的时候,不论你写了多少个”Hello World”,最终内存里面只有一个字符串对象。

运行时创建的字符串并不在此列,可以使些手段,强制在内存里面产生新的字符串。

string a = “Hello World”;
Console.WriteLine(Object.ReferenceEquals(a, new String(“Hello World”.ToCharArray())));  //False

因为我们强行调用了new,所以这个字符串跟内存中的直接量”Hello World”对应的对象不是同一个。

有趣的是,C#还允许强制把一个字符串加入到(如果已经有了,就只是找出来)字符串池里面。

string a = “Hello World”;
string b = String.Intern(new String(“Hello World”.ToCharArray()));
Console.WriteLine(Object.ReferenceEquals(a,b) );

或者

string a = String.Intern(new String(“Hello World”.ToCharArray()));
string b = String.Intern(new String(“Hello World”.ToCharArray()));
Console.WriteLine(Object.ReferenceEquals(a,b) );

前面提到了,这个行为跟Flyweight使用的内部状态和外部状态不同,是两个对象实实在在就是同一个对象。

C#中的字符串与Flyweight模式

好吧,前面说了不少,C#中的字符串不是Flyweight模式,但是是不是就意味着C#里面字符串跟Flyweight没有关系呢?

当然不是,否则我写这么一篇文章岂不是太蛋疼了……

字符串池和Intern方法简直是实现Flyweight的神器啊!

考虑我们有某一类对象,可能会创建几百万个,对象里面恰巧有这么一个属性叫做颜色,它在对象构造的时候随机产生,颜色用的是rgb色,用rgb24来表示,于是颜色字符串类似#ccc这样子。

代码写起来就像下面的样子:

    class Element
    {
	static Random rnd = new Random();
	static char[] table;
	static Element() 
	{
	    table = "0123456789abcdef".ToCharArray();
	}

	public string color;
	public Element()
	{
	    color = "" + table[rnd.Next() % 16] + table[rnd.Next() % 16] + table[rnd.Next() % 16];
	}
    }

接下来我们创建3千万个对象看看如何

	    Element[] eles = new Element[30000000];
	    for (var i = 0; i < 30000000; i++)
	    {
		eles[i] = new Element();
	    }

从任务管理器看到一大块内存被吃掉了

QFOMR9}(NR%(T3`V3Q35MSY

接下来我们使用String.Intern来实现Flyweight:

    class Element
    {
	static Random rnd = new Random();
	static char[] table;
	static Element() 
	{
	    table = "0123456789abcdef".ToCharArray();
	}

	public string color;
	public Element()
	{
	    color = String.Intern("" + table[rnd.Next() % 16] + table[rnd.Next() % 16] + table[rnd.Next() % 16]);
	}
    }

同样来看看运行结果:
@XMI6L75IKU}S%NGI6L31@K

可以看到内存占用量的明显变化。

因为字符串对象的不可更改性质,使用了String.Intern之后,我们完全看不出前后color的区别,也就是说,修改前后的Element类是完全等效的,但是Flyweight为我们节约了大量的内存。

更多思考

这个典型的使用flyweight场景为我们揭示了享元外部状态的特征:像字符串一样不可更改的对象。GoF原书的例子中的字型对象Glyph也是如此。

String.Intern这种对象池的方式实现flyweight也值得借鉴,我们可以考虑自己设计flyweight的外部状态对象时使用类似的方式。

[转载]WCF RESTful服务的Google Protocol Buffers超媒体类型

mikel阅读(1141)

[转载]WCF RESTful服务的Google Protocol Buffers超媒体类型 – 张善友 – 博客园.

Protocol Buffers 是在一个很理想的结构化数据的语言中立的序列化格式。你可以考虑一下XML或JSON,但更轻,更小的协议缓冲区。 这种格式的广应用于谷歌不同的系统之间交换数据。

由于其结构化数据的最佳表现,protocol buffers 是一个代表RESTful服务处理的数据很好的选择。要遵循REST的原则, protocol buffers 应作为一个新的超媒体类型的代表。 在当前版本(.NET 4) 的Windows通讯基础(WCF),包含一个新的媒体类型,需要相当数量的努力。 幸运的是,新版本的WCF HTTP堆栈,使媒体类型的WCF编程模型的一等公民,大家可以Glenn Block’s 博客去了解更详细的内容。推荐大家假期可以看下这本书《REST实战》http://book.douban.com/subject/6854551/

下面我们来介绍如何使用Google Protocol Buffers,只定义一个超媒体类型 ProtoBufferFormatter:

自 定义超媒体类型是通过创建自定义的MediaTypeFormatter,实现OnWritetoStream() 和 OnReadFromStream() 方法进行序列化和反序列化处理。人们经常认为媒体类型只是在服务端使用,但是它用来在客户端控制序列化和反序列化的要求,下图显示了一个HTTP 请求/响应和媒体类型格式化扮演的角色:

MediaTypeFormatterProcess

这个例子我们使用入门:构建简单的Web API 的代码和WCF Web API Preview 6。使用的媒体类型是application/x-protobuf ,REST服务的核心原则就是服务器和客户端之间的松耦合性,客户端需要知道书签的URI,但不应该知道任何其他的URI的知识,但是客户端必须知道链接关系。

image

下面的代码是自定义的ProtoBufferFormatter,构造函数里指明了支持的媒体类型 application/x-protobuf。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Net.Http.Formatting;
using System.IO;
using ProtoBuf;
using ProtoBuf.Meta;

namespace WcfWebFormat.Formatters
{
public class ProtoBufferFormatter : MediaTypeFormatter
{
public ProtoBufferFormatter()
{
this.SupportedMediaTypes.Add(new System.Net.Http.Headers.MediaTypeHeaderValue(“application/x-protobuf”));
}

protected override void OnWriteToStream(Type type, object value, Stream stream, System.Net.Http.Headers.HttpContentHeaders contentHeaders, System.Net.TransportContext context)
{
Serializer.Serialize(stream, value);
}

protected override object OnReadFromStream(Type type, Stream stream, System.Net.Http.Headers.HttpContentHeaders contentHeaders)
{
object obj = (RuntimeTypeModel.Default).Deserialize(stream, null, type);
return obj;
}

}
}

如上所示,我们在OnWriteToStream方法中将.NET对象序列化为ProtoBuf格式,在OnReadFromStream方法中将ProtoBuf格式饭序列化为.NET对象。

现在需要给我们的.NET对象加入ProtoBuf 序列化的标签:

using System.Collections.Generic;
using System.Xml.Serialization;
using ProtoBuf;

namespace ContactManager.Resources
{
[ProtoContract]
public class Contact
{
[ProtoMember(1)]
public int ContactId { get; set; }
[ProtoMember(2)]
public string Name { get; set; }
}
}

把ProtoBufferFormatter 加入到WCF运行时的超媒体类型集合里。

using Microsoft.ApplicationServer.Http;
using WcfWebFormat.Formatters;

namespace ContactManager
{
public class ContactManagerConfiguration : HttpConfiguration
{
public ContactManagerConfiguration()
{
this.Formatters.Add(new ProtoBufferFormatter());
}
}
}

修改服务配置,使用ContactManagerConfiguration:

var config = new ContactManagerConfiguration() { EnableTestClient = true };
routes.Add(new ServiceRoute(“api/contacts”, new HttpServiceHostFactory() { Configuration = config }, typeof(ContactsApi)));

在客户端调用的代码如下:

var serviceUri = new Uri(“http://localhost:9000/api/contacts/”);
var httpClient = new HttpClient();
httpClient.BaseAddress = serviceUri;
httpClient.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue(“application/x-protobuf”));

var response = httpClient.GetAsync(“1”).Result;
Contact obj = (RuntimeTypeModel.Default).Deserialize(response.Content.ReadAsStreamAsync().Result, null, typeof(Contact)) as Contact;

var formatters = new MediaTypeFormatterCollection() { new ProtoBufferFormatter() };
var content = new ObjectContent<Contact>(obj, “application/x-protobuf”,formatters);
content.Headers.ContentType = new MediaTypeHeaderValue(“application/x-protobuf”);

httpClient.PostAsync(serviceUri,content);

即使目前来说Google Protocol Buffers没有XML/JSON那样普及,RESTful服务使用中ProtoBuf无疑是一个非常有效的超媒体类型。祝大家龙年新春愉快,吉祥如意!

相关文章:

[转载]Android读写文件基于Java的文件输入输出流

mikel阅读(1215)

[转载]Android读写文件基于Java的文件输入输出流 – 小文字 – 博客园.

一、向本地默认地址存储文件

1 public void save(String filename, String content) throws Exception 
2 { 
3       FileOutputStream outStream = context.openFileOutput(filename, Context.MODE_PRIVATE); 
4       outStream.write(content.getBytes()); 
5       outStream.close(); 
6 }

首先创建一个文件输出流对象,它的值等于上下文context调用openFileOutput()方法的返回值,这个openFileOutput()方法将为本应用打开指定的私有文件以供写操作,如果当前文件不存在将创建一个。

方法的两个参数分别指定了文件的名称和读写模式,其中文件名称不能包含路径,文件的位置在:data/data/<package name>/files里面(这个目录可以用getFilesDir()方法得到,类似的getCacheDir()方法可以得到和files同级的cache目录)。读写模式分为4种基本模式,分别是:

MODE_PRIVATE或0 即私有模式:默认模式,文件只能被当前应用操作,而对其它应用透明。如果文件已经存在,新数据会把原有数据覆盖。

MODE_APPEND或32768 即附加模式:文件只能被当前应用操作,而对其它应用透明。如果文件已经存在,新数据会添加在旧数据之后。

MODE_WORLD_READABLE或1 即读模式:允许其他应用对本模式下创建的文件进行读操作。

MODE_WORLD_WRITEABLE或2 即写模式:允许其他应用对本模式下创建的文件进行写操作。

如果允许其他应用对该文件读和写两种操作,参数可以为Context.MODE_WORLD_READABLE+ Context.MODE_WORLD_WRITEABLE或者3,也就是读,写的组合。

然后调用输出流对象的write()写方法,其参数是字节类型,所以要把字符串类型转换为字节,调用getBytes()方法。

最后记得关闭输出流。

二、向SD卡存储文件

1 public void saveToSDCard(String filename, String content) throws Exception 
2 { 
3      File file = new File(Environment.getExternalStorageDirectory(), filename); 
4      FileOutputStream outStream = new FileOutputStream(file); 
5      outStream.write(content.getBytes()); 
6      outStream.close(); 
7 }

首先在清单文件里配置操作SD卡的权限

1 <!-- 在SDCard中创建与删除文件权限 --> 
2 <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/> 
3 <!-- 往SDCard写入数据权限 --> 
4 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

要想将文件存放到SD卡上面,必须指定目录,这时我们不再像之前一样调用openFileOutput()方法,因为它存放的文件是位于手机本身“内存” 里面的,利用File的构造函数可以传入文件地址,有三种常用的,参数分别是目录与文件名,绝对路径,目录路径与文件名

1 public File(File dir, String name)
2 public File(String path) 
3 public File(String dirPath, String name)

案例中通过Environment.getExternalStorageDirectory()方法获得Android手机中扩展卡的根目录,然后把file作为参数传给文件输出流的构造器,返回一个输出流,后面的操作和前面的相同。

[转载]番茄工作法——专治拖延症、精神涣散、再要五分钟综合症

mikel阅读(972)

[转载][推荐]番茄工作法——专治拖延症、精神涣散、再要五分钟综合症 – 1-2-3 – 博客园.

首先向仍然在工作岗位上奋战以及回到家还不忘刷博客园的兄弟们致敬。
最近读了一点《The Clean Coder》,一个意外的收获是,知道了原来还有个“番茄工作法”。尝试了几天,觉得很有效,推荐给你。
XX工作法,一听这名字你就能猜到,是时间管理,而时间管理又往往等同于成功学,所以你看了标题之后习惯性地无视本文的话,我也不怪你。成功学没有效果,是因为每个人的特质、境遇都不相同,成功往往无法复制。相反的,想办法改掉自己的一些坏习惯会更有效果。
我同时患有严重的拖延症、精神涣散和再要五分钟综合症,用了番茄工作法之后,好转了很多。
先说说我的病情。
拖延症——一直在心里想着“那件事必须得做了”,可就是迟迟不能开始。越是困难的、重要的事情,越容易这样。
再要五分钟综合症——无论娱乐还是工作,都容易烂尾。想好了娱乐到9点就工作,结果拖拖拉拉到10点还没开始干正经事;下定决心要在11点之前睡觉,但是天天都会磨蹭到11点半,12点还没上床。
精神涣散——我们都知道打断的危害。但是仔细想想,被别人打断的次数远没有被自己打断自己的次数多。譬如编译程序的时候,感觉好慢呐,赶快趁机刷下微博或者豆瓣吧,然后看到网友上传了美女图片,呦,韩寒写了新博客啦,完了又想起周报还没写呢……
这三种毛病综合发作的结果就是,整天愁眉苦脸、心急火燎,好像忙忙叨叨累的不行,到了该睡觉的时候却发现其实没干多少正经事,越发舍不得睡觉。脸色苍白,目光空洞,神疲气短,恶性循环。

番茄工作法

番茄工作法用一句话来概括就是——工作25分钟休息5分钟。详细条款如下:
0. 准备工作:买一个厨房计时器,或者使用软件计时器也行pcmaciphoneAndroid)。
1. 把计时器设定为25分钟,开始工作,直到响铃,算工作了一个番茄时间。然后在你的本子的工作项后面画一个叉叉表示此项工作已经耗费了一个番茄时间(如果使用软件会自动记录,更为方便)。
在一个番茄时间内,不可以被打断。这意味着等待编译的时候也不可以刷微博,也不要去泡咖啡或者吃东西。如果想到周报还没写,在本子上记上“需要写周 报”然后马上回到工作中。如果有同事打扰你或者接到客户的电话,礼貌地请求他等待20分钟,在本子上记上“需要给王科长回电话”然后马上回到工作中。当然 有时人家也会大喊一声“我等不了了!”,需要你立即紧急处理,那么这个番茄时间就相当于白费了,回到工作中时要重新开始这个番茄时间,就当这个番茄时间从 来没有开始过。响铃之后,你就可以看一下你的本子,处理刚刚记下的事情。如果这些零碎的小事很多,可以开启一个番茄时间集中处理它们。
在 一个番茄时间内,只做一件工作。如果工作了20分钟就完成了,也不要开始下一项工作或者去娱乐,可以回顾一下,检查/测试,总结经验,做一些优化或美化。 如果工作了5分钟就完成了,而且你觉得它本可以在上一个番茄时间里就完成的,并且再去复查一遍也没什么必要,可以将这个番茄时间作废。
2. 休息5分钟。
响铃之后必须立即停止手中的工作,想象你在考试,时间到,马上停笔。即使你觉得在休息的几分钟里就能完成它,也不能继续工作。而且,脑子里也不要再去想任何有关你工作的事情。这其实挺难做到的,我的建议是——离开你的座位——去做运动,或者跟同事聊聊天。
3. 每4个番茄之后休息15分钟。
如果感到疲劳,也可3个番茄就长休一次。或者把休息时间延长,但是不应超过25分钟。

更为详细的内容可以参考网站,电子书英文版中文版(仅32页,值得一读)。番茄工作法由意大利人Francesco Cirillo(弗朗切斯科•齐立罗)发明于1992年。因发明人最开始使用的是番茄形状的计时器而得名。

番茄工作法的好处

健康。 这个世界上有太多好玩的事情让人目不暇接。今晚有NFL季后赛野马vs爱国者耶,另外巴萨的比赛也不能错过,还有NBA快船vs湖人也想看一看。《The Clean Coder》看了一半不能扔下,还想再研究下ios编程……一件接着一件,一直不休息,直到累得实在难受才去床上趴一会儿,要么睡不着要么一睡不起。这种 被动的休息方式对健康极为不利。最好的休息方式是在感到累之前就做短暂的休息。
保持大脑的活力。由于特定 的生化原理,大脑内每个神经元都只能连续工作几分钟,之后就必须休息。连续的娱乐和工作会让大脑处于一种麻木、呆滞的状态。番茄团队经过大量研究发现,为 保持大脑的活力和效率最大化,最佳番茄时间为25~35分钟。我们大多数人连续工作的时间都是1小时或2小时,所以直觉上会怀疑25分钟的工作时间是不是 短了点?会不会刚刚进入状态就被休息打断了?其实,5分钟的休息并不会中断你的思路,反而可以让大脑里的清洁工有时间打扫战场,给脑细胞做做马杀鸡,之后 你会文思泉涌也说不定。
成就感。每个番茄代表一个纯的25分钟的工作时间。每天数一下番茄数就知道自己做了多少有用功,对每项工作耗费了多少时间也会有更具体的感觉。你可以知道自己娱乐了几个番茄,看了几个番茄的书,做了几个番茄的练习,对时间更有掌控感。
安全感。你可以安全地先娱乐一个番茄,然后再看一个番茄的书,不必担心一娱乐起来就停不下。
专心。 娱乐的时候想着工作,工作的时候不忘娱乐,这是我们大多数人的工作方式,也是低效和焦虑的根源。稀里糊涂地就到了下午,到了晚上,计划难以完成,好像做了 很多额外的事情,却又想不起来都干了些什么了。要想摆脱精神涣散的阴影,必须明确地强迫自己“一次只做一件事情,并且必须连续做25分钟”。
张弛有度。根据我的经验,对于一个严重的“再要五分钟综合症”患者,只是自己在心里想着“到九点就休息”是不够的,到时候不是差一点没完成,就是有了新的兴趣点。借助于计时器和“铃声响起立即停止”条款,才能干净利落地根治此症。
不再拖延。拖延症患者大多喜欢追求完美。越是想要做得好,就越容易否定自己,觉得没思路,不够好,信心受挫之下更容易精神涣散。使用番茄法,按下计时器,叮咚,强迫自己没思路也不许干别的,就算干想也要想满25分钟。

娱乐也番茄

书里说空闲的时间就不要用番茄法了。但是我的问题是,因为我觉得刚刚吃饱就工作不太合适,总想先娱乐一会儿。可是一旦娱乐起来就停不下来,所以我想娱乐 也可以使用番茄法。比如“看一个番茄的电影”,或者“看一个番茄的比赛”,之后休息五分钟。这样既有利于健康,也有机会决定之后是继续娱乐一个番茄,还是 工作一个番茄。

番茄你的计划

把番茄法与你的工作计划结合起来也很简单,就是使用番茄数作为工作项的时间单位。首先,你可以通过经验知道你每天平均能做几个番茄的工作。然后,估算每 个工作项需要的番茄数,这样你就能知道明天可以完成哪几个工作项了。每天结束的时候,再回顾一下每个工作项实际使用的番茄数。简单实用,是吧?
小贴士 一个工作项最多5到7个番茄,如果多于这个数,就认为这个任务太过复杂,最好把它分解为几个小任务。如果一个工作项的估值小于一个番茄,把它与其它的小任务组合成一个大任务。
小贴士 你可以在做计划的时候用空心方框“[]”表示一个番茄时间,3个番茄时间就是“[][][]”,把它标记在工作项的后面。实际工作时,每耗费一个番茄时间 就在空心方框里打个叉叉,耗费2个番茄时间是就是“[x][x][]”,耗费4个番茄时间时是“[x][x][x]x”)。

[转载]Asp.net MVC 基于规则的权限设计

mikel阅读(969)

[转载]Asp.net MVC 基于规则的权限设计 – 胡以谦 – 博客园.

上面一篇文章我们简单介绍了一个一级菜单的应用。

在实际的设计中菜单的的信息基本存储在sitemap的xml文件中,菜单还涉及到权限问题。

本章将介绍并举例说明如何设计基于规则的MVC应用程序的安全性。

基于角色的授权

在计算机系统的安全,基于角色的访问控制(RBAC)是一个系统访问限制授权用户的方法。在一个组织内,角色创建的各项工作职能。来执行某些操作的权限分配给特定的角色。
业务上我们必须定义一套针对不同的业务功能的角色体系,例如管理员,数据管理员,普通用户的角色… …

基于规则的访问控制

以规则为基础的授权框架,一般利用XML文档存储简单的规则设置,来控制系统访问权限。(也可以存储在数据库中,读者可以扩展Enterprise Library)

请参见下面的例子。

<rules>
    <add expression="R:Administrator" name="IsAdministrator" />
     <add expression="R:Administrator OR R:DataSteward" name="IsDataSteward" />
     <add expression="R:User OR R:DataSteward OR R:Administrator"  name="IsUser" />
 </rules>

规则“IsAdministrator”会检查当前用户是否有Administrator的角色。 “IsUser”将对角色User, DataSteward或者Administrator都有效。

SecurityHelper

SecurityHelper类利用了Enterprise Library 的默认的AuthorizationRuleProvider,它是我们整个系统的权限核心。主要代码如下。

using System.Collections.Generic;
using Microsoft.Practices.EnterpriseLibrary.Security;
using Microsoft.Practices.Unity;
using Volvo.CustomerMaster.Infrastructure.Common.Utilities.Entities;
using Volvo.CustomerMaster.Infrastructure.Common.Utilities.Unity;
using Volvo.POS.UserDomain.ServiceLayer;
using Volvo.POS.UserDomain.DomainLayer;
using Volvo.CustomerMaster.Web.Common.Session;
namespace Volvo.CustomerMaster.Web.Common.Security
{
public class SecurityHelper
{
[Dependency]
public static IUserService UserService { get; set; }
/// <summary>
/// Authenticate the user to verify that the user is a logged in user and that the user is approved
/// by the external authorization system.
/// </summary>
/// <returns></returns>
public static bool Authenticate()
{
// Inject implementation of the UserService through DI
if (UserService == null)
{
UserService = Container.Resolve<UserService>();
}
string userName = GetWindowsVcnUserName();
// Get user from external authorization system
GenericUser user = UserService.GetUser(userName);
if (user == null)
{
return false;
}
// Set session
SessionWrapper.CurrentUser = user;
return true;
}
/// <summary>
/// Returns true if the user contain roles that is valid for selected rule
/// </summary>
/// <param name="rule"></param>
/// <returns></returns>
public static bool Authorized(string rule)
{
try
{
IList<string> rules = new List<string> { rule };
return Authorized(rules);
}
catch
{
return false;
}
}
/// <summary>
/// Returns true if the user contain roles that is valid for selected rules
/// </summary>
/// <param name="rules"></param>
/// <returns></returns>
public static bool Authorized(IList<string> rules)
{
// If user is not defined, try to authenticate it
if (SessionWrapper.CurrentUser == null)
{
if (!Authenticate())
{
return false;
}
}
// Get authorization provider from Entlib
IAuthorizationProvider auth = AuthorizationFactory.GetAuthorizationProvider("RulesProvider");
if (rules.Count > 0 && SessionWrapper.CurrentUser.Principal != null)
{
foreach (string rule in rules)
{
// Authorize user (with its roles) agains the rule
if (!auth.Authorize(SessionWrapper.CurrentUser.Principal, rule))
{
return false;
}
}
}
else
{
return false;
}
return true;
}
private static string GetWindowsVcnUserName()
{
// Get windows user
System.Security.Principal.WindowsIdentity loggedInUser =
System.Security.Principal.WindowsIdentity.GetCurrent();
if (loggedInUser != null)
{
string username = loggedInUser.Name;
username = username.Substring(username.IndexOf('\\') + 1);
username = username.ToUpper();
return username;
}
return null;
}
}
}

其中对当前用户检查某个规则的有效性代码如下。

IAuthorizationProvider auth = AuthorizationFactory.GetAuthorizationProvider("RulesProvider");
if (rules.Count > 0 && SessionWrapper.CurrentUser.Principal != null)
{
foreach (string rule in rules)
{
// Authorize user (with its roles) agains the rule
if (!auth.Authorize(SessionWrapper.CurrentUser.Principal, rule))
{
return false;
}
}
}
else
{
return false;
}
return true;

菜单的访问控制

在Web.sitemap文件中我们对每个节点增加一个属性,AuthorizationRule这样菜单和用户角色就关联起来了。

<?xml version="1.0" encoding="utf-8" ?>
<siteMap enableLocalization="true">
  <siteMapNode title="Menu">
    <siteMapNode controller="Home" title="Home"    action="Index" resourceKey="Tab_Home" AuthorizationRule="IsUser"/>
    <siteMapNode controller="Customer" title="Manage Customers"    action="Index" resourceKey="Tab_ManageCustomers" AuthorizationRule="IsDataSteward"/>
    <siteMapNode title="Switching Brands" resourceKey="Tab_SwitchingBrands" AuthorizationRule="IsUser">
      <siteMapNode title="Violin" controller="Home" action="SetTheme/Violin"  AuthorizationRule="IsUser"/>
      <siteMapNode title="Mack" controller="Home" action="SetTheme/Mack" AuthorizationRule="IsUser"/>
      <siteMapNode title="Mack Dual" controller="Home" action="SetTheme/MackDual" AuthorizationRule="IsUser"/>
      <siteMapNode title="Renault" controller="Home" action="SetTheme/Renault"  AuthorizationRule="IsUser"/>
      <siteMapNode title="Volvo BA" controller="Home" action="SetTheme/VolvoBA" AuthorizationRule="IsUser"/>
      <siteMapNode title="Volvo Group" controller="Home" action="SetTheme/VolvoGroup" AuthorizationRule="IsUser"/>
    </siteMapNode>
  </siteMapNode>
</siteMap>

菜单的规则如何、什么时候被加载呢?在渲染菜单的SiteMapBinding.cshtml文件中,我们的代码如下。(示例利用了Telerik for ASP.NET MVC控件)

@using Volvo.CustomerMaster.Web.Common.Security
@using Volvo.CustomerMaster.Web

 @{ Html.Telerik().Menu()
        .Name("Menu")
        .BindTo("Web",(item, node) =>{
             if (node.Attributes["resourceKey"] !=null)
                item.Text = UI_Resources.ResourceManager.GetString(node.Attributes["resourceKey"] as string) ?? item.Text;
            if(node.Attributes["imageurl"] != null)
            item.ImageUrl = node.Attributes["imageurl"].ToString();
            item.Visible = SecurityHelper.Authorized(node.Attributes["AuthorizationRule"].ToString());
        })
         .Effects(fx =>
          fx.Toggle()
          .OpenDuration(200)
          .CloseDuration(200))
       .Render();
 }

其中item.Visible=SecurityHelper.Authorized(node.Attributes[“AuthorizationRule”].ToString());这行代码就决定了菜单的可见性由我们定义的规则控制。

UI元素访问控制

利用同样原理,按钮的enable/disable也可以基于规则来控制。我们首先构造一个类 (HtmlHelper)用于在页面上显示按钮。

ButtonHelper

以下核心代码将权限规则和按钮的显示关联。

Button

在页面中,我们如何利用ButtonHelper呢?下面的例子利用Telerik来显示一个Grid,在Grid的头上我么将显示edit, add, delete 按钮。

按钮的生成就利用了我么的ButtonHelper类。它提供了一些扩展方法。

@(Html.Telerik().Grid<Customer>()
         .Name("CustomerGrid")
         .EnableCustomBinding(true)
         .DataBinding(bind => bind.Ajax().Select("ListCustomerAjax", "Customer"))
         .ToolBar(toolBar => toolBar.Template
          (
             @Html.Button("toolbarEditRow", UI_Resources.ListCustomer_EditCustomerButton, 
             ButtonHelper.SetButtonDisability("toolbarEditRow", "IsAdministrator"), 
             new { title = UI_Resources.ListCustomer_EditCustomerButtonTooltip, @class = "icon edit" })
             +"<span >&nbsp;</span>"+
             @Html.Button("toolbarAddRow", UI_Resources.ListCustomer_AddNewCustomerButton, ButtonHelper.SetButtonDisability("toolbarAddRow", "IsAdministrator"), new { title = UI_Resources.ListCustomer_AddNewCustomerButtonTooltip, @class = "icon add" })
             +"<span >&nbsp;</span>"+
             @Html.Button("toolbarDeleteRow", UI_Resources.ListCustomer_DeleteCustomerButton, ButtonHelper.SetButtonDisability("toolbarDeleteRow", "IsAdministrator"), new { title = UI_Resources.ListCustomer_DeleteCustomerButtonTooltip, @class = "icon delete" })
          ))
         .Columns(columns =>
                    {
                        columns.Bound(o => o.Number).Title("Number").Width(40);
                        columns.Bound(o => o.Name).Title("Name").Width(100);
                        columns.Bound(o => o.Address).Title("Address").Width(100);
                    }
                 )
        .ClientEvents(x => x.OnLoad("CustomerGrid_OnLoad"))
        .Selectable()
        .Pageable(paging => paging.PageSize(10).Total(Model.CustomerCount))
        .Sortable())

显示按钮的时候,我们调用了ButtonHelper.SetButtonDisability来控制按钮的enable/disable状态,我们也可以通过它来控制显示、不显示按钮。

MVC Controller类的访问控制

有些用户可能会直接在浏览器中输入URL来绕过菜单的权限控制,我们必须在MVC的Controller级别加上我们的基于规则的权限管理。

我们增加一个新的类RuleAuthorizeAttribute,它继承于System.Web.Mvc.AuthorizeAttribute

View Code

代码很简单,它也利用了我们前面提到的SecurityHelper类的功能。

我们把这个属性设置的示例程序中的CustomerController类中。

    [HandleError]
    [RuleAuthorize(Allow="IsDataSteward")]
    public class CustomerController : BaseController
    {
        public ICustomerService CustomerService { get; set; }

        public CustomerController(ICustomerService customerService)
        {
            CustomerService = customerService;  
            
        }

假设我们登录的用户没有DataSteward或Administrator角色,但是他尝试直接在浏览器里面输入URL:http://localhost:2967/Customer。

新增的Filter控制了直接URL的权限管理。

按钮显示的控制

———————————————————————-
示例代码.

http://files.cnblogs.com/huyq2002/Sample.zip

运行程序您需要生成数据库CustomerMaster,运行CustomerMaster.SQL,同时修改NHibernate.config中的connection.connection_string

系统适用于域认证,也很容易扩展到其他认证方式,如form认证等

通过改变代码中的UserService的GetUser方法可以模拟不同的角色来使用系统

// 2. Get roles defined for the user
            if (userName.Equals("v0cn174", StringComparison.CurrentCultureIgnoreCase))
            {
                //user.AddRole(new UserRole(UserRoleConstants.Administrator));
                user.AddRole(new UserRole(UserRoleConstants.DataSteward));
                //user.AddRole(new UserRole(UserRoleConstants.User));
            }
            else
            {
                // All users are superusers in this mock
                //user.AddRole(new UserRole(UserRoleConstants.Administrator));
                //user.AddRole(new UserRole(UserRoleConstants.DataSteward));
                user.AddRole(new UserRole(UserRoleConstants.User));
            }
            return user;

[转载]SqlServer批量清理指定数据库中所有数据

mikel阅读(1009)

[转载][推荐] (SqlServer)批量清理指定数据库中所有数据 – 海南.胡勇 – 博客园.

——通过知识共享树立个人品牌。

在实际应用中,当我们准备把一个项目移交至客户手中使用时,我们需要把库中所有表先前的测试数据清空,以给客户一个干净的数据库,如果涉及的表很多,要一 一的清空,不仅花费时间,还容易出错以及漏删,在这儿我提供了一个方法,可快捷有效的清空指定数据库所有表的数据。仅供参考,欢迎交流不同意见。

Remove all data from a database

SET NOCOUNT ON
Tables to ignore
DECLARE @IgnoreTables
TABLE (TableName varchar(512))
INSERT INTO @IgnoreTables (TableName) VALUES (sysdiagrams)
DECLARE @AllRelationships
TABLE (ForeignKey varchar(512)
,TableName varchar(512)
,ColumnName varchar(512)
,ReferenceTableName varchar(512)
,ReferenceColumnName varchar(512)
,DeleteRule varchar(512))
INSERT INTO @AllRelationships
SELECT f.name AS ForeignKey,
OBJECT_NAME(f.parent_object_id) AS TableName,
COL_NAME(fc.parent_object_id,
fc.parent_column_id) AS ColumnName,
OBJECT_NAME (f.referenced_object_id) AS ReferenceTableName,
COL_NAME(fc.referenced_object_id,
fc.referenced_column_id) AS ReferenceColumnName,
delete_referential_action_desc as DeleteRule
FROM sys.foreign_keys AS f
INNER JOIN sys.foreign_key_columns AS fc
ON f.OBJECT_ID = fc.constraint_object_id

DECLARE @TableOwner varchar(512)
DECLARE @TableName varchar(512)
DECLARE @ForeignKey varchar(512)
DECLARE @ColumnName varchar(512)
DECLARE @ReferenceTableName varchar(512)
DECLARE @ReferenceColumnName varchar(512)
DECLARE @DeleteRule varchar(512)

PRINT(Loop through all tables and switch all constraints to have a delete rule of CASCADE)
DECLARE DataBaseTables0
CURSOR FOR
SELECT SCHEMA_NAME(t.schema_id) AS schema_name, t.name AS table_name
FROM sys.tables AS t;

OPEN DataBaseTables0;

FETCH NEXT FROM DataBaseTables0
INTO @TableOwner,@TableName;

WHILE @@FETCH_STATUS = 0
BEGIN
IF (NOT EXISTS(SELECT TOP 1 1 FROM @IgnoreTables WHERE TableName = @TableName))
BEGIN
PRINT [+@TableOwner+].[ + @TableName + ];

DECLARE DataBaseTableRelationships CURSOR FOR
SELECT ForeignKey, ColumnName, ReferenceTableName, ReferenceColumnName
FROM @AllRelationships
WHERE TableName = @TableName

OPEN DataBaseTableRelationships;
FETCH NEXT FROM DataBaseTableRelationships INTO @ForeignKey@ColumnName@ReferenceTableName@ReferenceColumnName;

IF @@FETCH_STATUS <> 0
PRINT =====> No Relationships ;

WHILE @@FETCH_STATUS = 0
BEGIN
PRINT =====> switching delete rule on + @ForeignKey + to CASCADE;
BEGIN TRANSACTION
BEGIN TRY
EXEC(

ALTER TABLE [+@TableOwner+].[ + @TableName + ]
DROP CONSTRAINT
+@ForeignKey+;

ALTER TABLE [+@TableOwner+].[ + @TableName + ] ADD CONSTRAINT
+@ForeignKey+ FOREIGN KEY
(
+@ColumnName+
) REFERENCES
+@ReferenceTableName+
(
+@ReferenceColumnName+
) ON DELETE CASCADE;
);
COMMIT TRANSACTION
END TRY
BEGIN CATCH
PRINT =====> cant switch + @ForeignKey + to CASCADE, – +
CAST(ERROR_NUMBER() AS VARCHAR+ + ERROR_MESSAGE();
ROLLBACK TRANSACTION
END CATCH;

FETCH NEXT FROM DataBaseTableRelationships INTO @ForeignKey@ColumnName@ReferenceTableName@ReferenceColumnName;
END;

CLOSE DataBaseTableRelationships;
DEALLOCATE DataBaseTableRelationships;

END
PRINT ;
PRINT ;

FETCH NEXT FROM DataBaseTables0
INTO @TableOwner,@TableName;
END
CLOSE DataBaseTables0;
DEALLOCATE DataBaseTables0;

PRINT(Loop though each table and DELETE All data from the table)

DECLARE DataBaseTables1 CURSOR FOR
SELECT SCHEMA_NAME(t.schema_id) AS schema_name, t.name AS table_name
FROM sys.tables AS t;

OPEN DataBaseTables1;

FETCH NEXT FROM DataBaseTables1
INTO @TableOwner,@TableName;

WHILE @@FETCH_STATUS = 0
BEGIN
IF (NOT EXISTS(SELECT TOP 1 1 FROM @IgnoreTables WHERE TableName = @TableName))
BEGIN
PRINT [+@TableOwner+].[ + @TableName + ];
PRINT =====> deleting data from [+@TableOwner+].[ + @TableName + ];
BEGIN TRY
EXEC(
DELETE FROM [
+@TableOwner+].[ + @TableName + ]
DBCC CHECKIDENT ([
+ @TableName + ], RESEED, 0)
);
END TRY
BEGIN CATCH
PRINT =====> cant FROM [+@TableOwner+].[ + @TableName + ], – +
CAST(ERROR_NUMBER() AS VARCHAR+ + ERROR_MESSAGE();
END CATCH;
END

PRINT ;
PRINT ;

FETCH NEXT FROM DataBaseTables1
INTO @TableOwner,@TableName;
END
CLOSE DataBaseTables1;
DEALLOCATE DataBaseTables1;

PRINT(Loop through all tables and switch all constraints to have a delete rule they had at the beggining of the task)

DECLARE DataBaseTables2 CURSOR FOR
SELECT SCHEMA_NAME(t.schema_id) AS schema_name, t.name AS table_name
FROM sys.tables AS t;
OPEN DataBaseTables2;

FETCH NEXT FROM DataBaseTables2
INTO @TableOwner,@TableName;

WHILE @@FETCH_STATUS = 0
BEGIN

IF (NOT EXISTS(SELECT TOP 1 1 FROM @IgnoreTables WHERE TableName = @TableName))
BEGIN
PRINT [+@TableOwner+].[ + @TableName + ];

DECLARE DataBaseTableRelationships CURSOR FOR
SELECT ForeignKey, ColumnName, ReferenceTableName, ReferenceColumnName, DeleteRule
FROM @AllRelationships
WHERE TableName = @TableName

OPEN DataBaseTableRelationships;
FETCH NEXT FROM DataBaseTableRelationships INTO @ForeignKey@ColumnName@ReferenceTableName@ReferenceColumnName@DeleteRule;

IF @@FETCH_STATUS <> 0
PRINT =====> No Relationships ;

WHILE @@FETCH_STATUS = 0
BEGIN
DECLARE @switchBackTo varchar(50=
CASE
WHEN @DeleteRule = NO_ACTION THEN NO ACTION
WHEN @DeleteRule = CASCADE THEN CASCADE
WHEN @DeleteRule = SET_NULL THEN SET NULL
WHEN @DeleteRule = SET_DEFAULT THEN SET DEFAULT
END

PRINT =====> switching delete rule on + @ForeignKey + to + @switchBackTo;

BEGIN TRANSACTION
BEGIN TRY
EXEC(

ALTER TABLE [+@TableOwner+].[ + @TableName + ]
DROP CONSTRAINT
+@ForeignKey+;

ALTER TABLE [+@TableOwner+].[ + @TableName + ] ADD CONSTRAINT
+@ForeignKey+ FOREIGN KEY
(
+@ColumnName+
) REFERENCES
+@ReferenceTableName+
(
+@ReferenceColumnName+
) ON DELETE
+@switchBackTo+
);

COMMIT TRANSACTION
END TRY
BEGIN CATCH
PRINT =====> cant change +@ForeignKey + back to + @switchBackTo +, – +
CAST(ERROR_NUMBER() AS VARCHAR+ + ERROR_MESSAGE();
ROLLBACK TRANSACTION
END CATCH;

FETCH NEXT FROM DataBaseTableRelationships
INTO @ForeignKey@ColumnName@ReferenceTableName@ReferenceColumnName@DeleteRule;
END;

CLOSE DataBaseTableRelationships;
DEALLOCATE DataBaseTableRelationships;

END
PRINT ;
PRINT ;

FETCH NEXT FROM DataBaseTables2
INTO @TableOwner,@TableName;
END
CLOSE DataBaseTables2;

DEALLOCATE DataBaseTables2;

© 2011 EricHu

原创作品,转贴请注明作者和出处,留此信息。

[转载]SqlServer分离所有用户数据库

mikel阅读(1029)

[转载][推荐] (SqlServer)分离所有用户数据库 – 海南.胡勇 – 博客园.

在实际应用中,有时我们需要一次性分离所有用户数据库,下面给出代码,供大家参考。

USE [master]
GO
IF EXISTSSELECT *
FROM sys.objects
WHERE [object_id] = OBJECT_ID(N[dbo].[spDetachAllUserDatabases])
AND type IN ( NP, NPC ) )
DROP PROCEDURE [dbo].[spDetachAllUserDatabases]
GO

CREATE PROCEDURE [dbo].[spDetachAllUserDatabases]
AS
BEGIN
Declare Variables
DECLARE @DatabaseName VARCHAR(100)
DECLARE @MinDatabaseID INT
DECLARE @MaxDatabaseID INT
DECLARE @SQL VARCHAR(4000)
Check for temporary table and drop it if it exists
IF OBJECT_ID(tempDB.dbo.#DatabaseIS NOT NULL
DROP TABLE [#Database];

Create temporary table
CREATE TABLE #Database
(
ID INT IDENTITY(11),
DatabaseName VARCHAR(100)
)

Check for existing user databases
IF EXISTSSELECT name
FROM sys.databases
WHERE database_id > 4
AND name NOT INSQLDBAReportServer,
ReportServerTempDB,
distribution ) )
BEGIN
Insert all database names into a temporary table
INSERT INTO #Database ( DatabaseName )
SELECT name
FROM sys.databases
WHERE database_id > 4
AND name NOT INSQLDBAReportServer,
ReportServerTempDB,
distribution )

Set Variables for the detach database loop
SELECT @MinDatabaseID = MIN(ID),
@MaxDatabaseID = MAX(ID)
FROM #Database

Begin loop to detach databases
WHILE @MinDatabaseID <= @MaxDatabaseID
BEGIN

Get DatabaseName
SELECT @DatabaseName = DatabaseName
FROM #Database
WHERE ID = @MinDatabaseID

Build Detach Database Command
SET @SQL = EXEC sp_detach_db + ”” + @DatabaseName
+ ”” + ;

Try Catch block to execute SQL and handle errors
BEGIN TRY

Detach Database
EXEC@SQL
)
PRINT Detached + @DatabaseName
END TRY
BEGIN CATCH
SELECT @DatabaseName,
message_id,
severity,
[text],
@SQL
FROM sys.messages
WHERE message_id = @@ERROR
AND language_id = 1033 British English
END CATCH

Get the next DatabaseName ID
SET @MinDatabaseID = @MinDatabaseID + 1

End Loop
END
END
END

GO

© 2011 EricHu

原创作品,转贴请注明作者和出处,留此信息。

————————————————

[转载]存储过程和触发器笔记

mikel阅读(967)

[转载]存储过程和触发器笔记 – snidget – 博客园.

1. 存储过程和触发器是什么?

存储过程不能可以显著提高系统的执行速度,还能提高效率确保一致性.

1.1存储过程:一种数据库对象,将负责不同功能的语句分类放置起来,以便能反复使用.

1.2特点:


1.3存储过程的分类

分为五类,系统存储过程,用户定义存储过程,临时存储过程,远程存储过程,扩展存储过程.

临时存储过程又分为本地临时存储过程,全局临时存储过程.

分类

说明

系统存储过程 存储在master中,以sp开头,调用时不必加库名,如果参数是保留字或者数据库对象,用单引号包围.
用户定义存储过程 用户为完成一定的功能定义在数据库中存储过程.
临时存储过程 本地临时:#开头,放在tempdb中,连接断开之后自动删除,本库使用.
全局临时:##开头,放在tempdb中,连接断开后使用完之后自动删除,本连接的所有库可以使用.注意命名.
远程存储过程 位于远程服务器上的存储过程.通过分布式查询和execute执行.
扩展存储过程 外部程序写的存储过程,xp开头,动态链接库形式存在,也放在master

1.4存储过程优点


1.5存储过程和视图的比较


1.6创建存储过程

格式:


例子:

create procedure ShowAllStudent

as

begin

select * from students

end

1.7执行存储过程

格式:exec procedure_name

例子:exec  ShowAllStudent

1.8带输入参数存储过程

格式:


例子:

create procedure SelectStudentByStu_no

@sno char(12)=‘200501020319’

as

begin

select * from students where stu_no=@sno

end

1.9执行带输入参数的存储过程

格式:


例子:

exec SelectStudentByStu_no

@sno=‘200501030218’

当参数比较少的时候,可以按照位置传递参数.

例子:

exec SelectStudentByStu_no ‘200501030218’

1.10带输出参数的存储过程

格式:


例子:

create procedure GetStudentCountByStu_sex

@sex char(2)=,

@count int=0 output

as

begin

set

@count=(select count(*) from students where stu_gender=@sex)

print @count

end

执行带输出参数的存储过程

例子:

declare @sex char(2) ,@count int

set @sex=

exec GetStudentCountByStu_sex @sex,@count

1.11 删除存储过程

Drop procedure GetPostsByBlogId

1.12 更新存储过程

alter procedure GetPostsByBlogId

(@blogid varchar(50))

As

Select top 5* from Posts where BlogId=@blogid

1.13 重命名存储过程

对象浏览器中修改.

1.14 重新编译存储过程

有三种方法:

1)创建的时候使用with Recompile 语句.

2)在执行过程中设定重新编译

3)调用系统存储过程重新编译

2. 触发器

基本表被在修改的时候通过事件触发而执行的存储过程.

作用是保证了由主键和外键所不能保证的参照完整性和数据完整性.

2.1触发器的优点

触发器可以包含复杂的处理逻辑,主要用来保持低级的数据完整性.优点如下.



2.2创建触发器

删除触发器:


例子:

create trigger dropStudent

on students

for delete

as

print 成功删除一条数据.’

更新触发器:

create trigger updateStudentName

on students

for update

as

if update (stu_name)

begin

print 不能更新主键,学生号码.’

rollback transaction

end

update students set

stu_name=五哥

where stu_no=‘200501020319’


删除触发器:略

查看触发器:

1) 使用系统的存储过程查看: exec sp_helptrigger students


使用系统表: select name from sysobjects where type=‘TR’


2) 管理器查看 略

删除触发器: drop trigger updateStudent

修改触发器:


重命名: sp_rename dropStudent,deleteStudentItem

启动和停止触发器:

alter table students enable trigger all