概述
ID生成器独立成一个数据库,数据库名称为:id_generator。数据库中的表设计原则是每一个表对应一个需要获取ID的外部表,不允许多个需要获取ID的外部表共用一个ID生成器里面的一个表。表名的规则是:id_[external_table_names],表的结构如:
CREATE TABLE `id_user` (
`AutoID` INT(11) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`AutoID`)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
ROW_FORMAT=DEFAULT
AUTO_INCREMENT=1
实现原理
ID生成器的程序建立在每个应用服务器的数据访问层DAL中,也就是说每台应用服务器中的ID生成器程序都是一个独立完整体。
ID生成器中内部维护着一个“先进先出”的队列,此队列也起到缓存作用,每次调用ID生成器获取ID时,就从队列取出一个ID给调用者。
ID生成器初始化时,会先向数据库批量写入500次,然后取出最后写入的500个ID,接着写入“先进先出”的队列,供调用者使用。当队列为空了,将再次向数据库写入500次取出最后写入的500个ID写入队列,如此循环。
技术要点说明
为保证每次批量写入数据库并取出来的ID都是正确的,在批量写入数据库时需要启用数据库事务,通过数据库的事务来保证数据的正确性。
当某一个应用服务器重新启动了,ID生成器队列中维护的ID值也将会丢失,但这不会产生ID重复的情况,丢失的ID将是作废的,当ID生成器中队列为空了,会马上从数据库再次获取最新的一批ID回来供调用者使用。如果出现ID丢失的情况,表现出来的结果就是需要ID的目标表的主键ID值和表的总记录数值是不一致的,表的总记录数值将会比表的主键ID的数值小。
性能测试数据
场景一:1次获取获取500个ID和1000个ID的比较,1次就开启一个数据库的connection。
|
500个 |
1000个 |
|
60MS |
122MS |
|
58MS |
119MS |
|
63MS |
141 |
场景二:10次获取5000个ID和10000个ID的比较,分10次依次调用,顺序的开启了10个数据库的connection。
|
5000个 |
10000个 |
|
653MS |
963MS |
|
745MS |
875MS |
|
591MS |
915MS |
场景三:5个线程分别获取500个ID和1000个ID的比较,1个线程开启1个数据库的connection。
|
500个 |
1000个 |
|
143~219MS |
425~479MS |
|
171~225MS |
402~460MS |
|
165~244MS |
380~481MS |
结论
从测试的数据来看,ID生成器的性能表现还是比较理想的,而且整个方案实现起来也比较简单,维护也简单。
第一篇只对Html Agility Pack做了一个大概的介绍,在接下来的章节会比较深入的介绍Html Agility Pack。
Html Agility Pack 源码中的类大概有28个左右,其实不算一个很复杂的类库,但它的功能确不弱,为解析DOM已经提供了足够强大的功能支持,可以跟jQuery操作DOM媲美:)
基础类和基础方法介绍
Html Agility Pack最常用的基础类其实不多,对解析DOM来说,就只有HtmlDocument和HtmlNode这两个常用的类,还有一个 HtmlNodeCollection集合类。
HtmlDocument类
当然在解析DOM前需要加载html原始文件或者html的字符串,HtmlDocument类封装了支持此功能的方法,下面是加载html的方法介绍。
HtmlDocument类定义了多个重载的Load方法来实现以不同方式加载html,其实主要分为两种,一种是从Stream中加载html,另外一种是从物理路径加载html,分别见下面:
方法:public void Load(TextReader reader)
说明:从指定的 TextReader对象中加载Html
示例:
HtmlDcument doc = new HtmlDocument();
StreamReader sr = File.OpenText("file path");
doc.Load(sr);
基于上面方法,衍生出了几个不同重载方法。
以指定的Stream对象为主的有:
(1)public void Load(Stream stream) ///从指定的Stream对象中加载html;
(2)public void Load(Stream stream, bool detectEncodingFromByteOrderMarks) ///指定是否从顺序字节流中解析编码格式
(3)public void Load(Stream stream, Encoding encoding) ///指定编码格式
(4)public void Load(Stream stream, Encoding encoding, bool detectEncodingFromByteOrderMarks)
(5)public void Load(Stream stream, Encoding encoding, bool detectEncodingFromByteOrderMarks, int buffersize)
以指定的物理路径为主的有:
(1)public void Load(string path)
(2)public void Load(string path, bool detectEncodingFromByteOrderMarks) ///指定是否从顺序字节流中解析编码格式
(3)public void Load(string path, Encoding encoding) ///指定编码格式
(4)public void Load(string path, Encoding encoding, bool detectEncodingFromByteOrderMarks)
(5)public void Load(string path, Encoding encoding, bool detectEncodingFromByteOrderMarks, int buffersize)
HtmlDocument类中还定义了直接从html字符串中加载Html,如下:
方法:public void LoadHtml(string html)
说明:从指定的html字符串中加载html
示例:
HtmlDocument doc = new HtmlDocument();
string html = "<div id="demo"><span style="color:red;"><h1>Hello World!</h1></span></div>";
doc.LoadHtml(html);
HtmlDocument类还有其他写DOM方法的定义,这里不作详细介绍,留作以后专门介绍Html Agility Pack写DOM章节介绍吧,这里着重介绍Html Agility pack解析DOM的细节。
HtmlNode类和HtmlNodeCollection类
通过HtmlDocument把html加载进来后,接着是要做什么呢?当然是对html解析了,解析DOM就需要提到HtmlNode类了。 HtmlDocument类由属性DocumentNode属性返回当前Html解析后的一个全局的HtmlNode对象;如果想获取某一个元素的 HtmlNode,可以通过HtmlDocument类的GetElementbyId(string Id)方法来获取,返回指定某一个html元素的HtmlNode对象。如何通过HtmlNode对象来访问DOM呢?介绍之前先对它的功能了解下。
HtmlNode类实现了IXPathNavigable接口,这说明了它可以通过xpath来查询DOM了,如果对System.Xml命名空间下的 XmlDocument类了解的,特别是使用过了SelectNodes()和SelectSingleNode()方法的朋友对使用HtmlNode类将会很熟悉。其实Html Agility Pack内部是把html解析成xml文档格式了的,所以支持xml中的一些常用查询方式。下面对HtmlNode的一些主要的常用成员作简要的说明。
HtmlNode类的主要属性
1)Attributes属性
获取当前Html元素的属性的集合,返回的是一个HtmlAttributeCollection对象。如一个div元素,它可能会定义一些属性,如:<div id="title" name="title" class="class-name" title="title div">***</div>,那Attributes返回的HtmlAttributeCollection就包含了 “id,name,class,title”的信息。HtmlAttributeCollection类是实现了接口 IList<HtmlAttribute>的一个集合类,故此可以通过下面代码方式访问每一个成员。
HtmlNode node = doc.GetElementbyId("title");
string titleValue = node.Attributes["title"].Value;
或者
foreach(HtmlAttribute attr in node.Attributes)
{
Console.WriteLine("{0}={1}",attr.Name,attr.Value);
}
在获取属性值时,如果某一个属性名称不存在的话,Attributes["name"]返回的是null值。
2)FirstChild,LastChild,ChildNodes,ParentNode属性
FirstChild属性:返回所有子节点的第一个节点,如下面代码:
string html = "<div id="demo"><span style="color:red;"><h1>Hello World!</h1></span><div id="innerDiv">inner div</div></div>";
FirstChild则返回的是“<span style="color:red;"><h1>Hello World!</h1></span>” 的节点。
LastChild属性:返回所有子节点的最后一个节点,以上面的html为例,则返回“<div id="innerDiv">inner div</div>”节点。
ChildNodes属性:返回当前节点所有直接一代的子节点的集合,不包括跨代子节点,以上面的html为例,则返回“<span style="color:red;"><h1>Hello World!</h1></span>” 和“<div id="innerDiv">inner div</div>”两个节点。
ParentNode属性:返回当前节点的直接父节点。
3)获取Html源码和文本
HtmlNode类设计了OuterHtml属性和InnerHtml属性用于获取当前节点的Html源码。两者不同之处是,OuterHtml属性返回的是包含当前节点的Html代码在内的所有Html代码,而InnerHtml属性返回的是当前节点里面子节点的所有Html代码。如下面:
代码
HtmlDocument doc = new HtmlDocument();
string html = "<div id="demo"><span style="color:red;"><h1>Hello World!</h1></span></div>";
doc.LoadHtml(html);
HtmlNode node = doc.HtmlDocument;
Console.WriteLine(node.OuterHtml); /// return "<div id="demo"><span style="color:red;"><h1>Hello World!</h1></span></div>";
Console.WriteLine(node.InnerHtml); /// return "<span style="color:red;"><h1>Hello World!</h1></span>";
如要获取节点的文本值,通过InnerText属性来获取,InnerText属性过滤掉了所有的Html标记代码,只返回文本值,如下面:
Console.WriteLine(node.InnerText);/// return "Hello World!";
HtmlNode类的主要方法
HtmlNode类提供了足够丰富的方法供查询当前节点下的子节点(元素),当然也包括查询当前节点的父节点(元素)的方法,下面列出主要的方法和使用说明。
获取父节点的系列方法:
1)public IEnumerable<HtmlNode> Ancestors()
获取当前节点的父节点列表(不包含自身)。
2)public IEnumerable<HtmlNode> Ancestors(string name)
以指定一个名称来获取父节点的列表(不包含自身)。
3)public IEnumerable<HtmlNode> AncestorsAndSelf()
获取当前节点的父节点列表(包含自身)。
4)public IEnumerable<HtmlNode> AncestorsAndSelf(string name)
以指定一个名称来获取父节点的列表(包含自身)。
获取子节点的系列方法:
1)public IEnumerable<HtmlNode> DescendantNodes()
获取当前节点下的所有子节点的列表,包括子节点的子节点(不包含自身)。
2)public IEnumerable<HtmlNode> DescendantNodesAndSelf()
获取当前节点下的所有子节点的列表,包括子节点的子节点(包含自身)。
3)public IEnumerable<HtmlNode> Descendants()
获取当前节点下的直接子节点的列表(不包含自身)。
4)public IEnumerable<HtmlNode> DescendantsAndSelf()
获取当前节点下的直接子节点的列表(包含自身)。
5)public IEnumerable<HtmlNode> Descendants(string name)
获取当前节点下的以指定名称的子节点列表。
6)public IEnumerable<HtmlNode> DescendantsAndSelf(string name)
获取当前节点下的以指定名称的子节点的列表(包含自身)。
7)public HtmlNode Element(string name)
获取第一个符合指定名称的直接子节点的节点元素。
8)public IEnumerable<HtmlNode> Elements(string name)
获取符合指定名称的所有直接子节点的节点列表。
9)public HtmlNodeCollection SelectNodes(string xpath)
获取符合指定的xpath的子节点列表。
10)public HtmlNode SelectSingleNode(string xpath)
获取符合指定的xpath的单个字节点元素。
查询节点的方法主要是上面10个方法,该类还有其他写节点的系列方法,这里不详细介绍写操作的方法,留作以后详细介绍。
结合Xpath进行查询节点是功能比较强大,这像操作xml那样方便。
简单例子的代码
下面例子是把博客园的精华区博客列表查询出来。执行结果如下面:

代码
代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using HtmlAgilityPack;
namespace DemoCnBlogs
{
class Program
{
static void Main(string[] args)
{
HtmlWeb web = new HtmlWeb();
HtmlDocument doc = web.Load("http://www.cnblogs.com/pick/");
HtmlNode node = doc.GetElementbyId("post_list");
StreamWriter sw = File.CreateText("log.txt");
foreach(HtmlNode child in node.ChildNodes)
{
if (child.Attributes["class"] == null || child.Attributes["class"].Value != "post_item")
continue;
HtmlNode hn = HtmlNode.CreateNode(child.OuterHtml);
///如果用child.SelectSingleNode("//*[@class=\"titlelnk\"]").InnerText这样的方式查询,是永远以整个document为基准来查询,
///这点就不好,理应以当前child节点的html为基准才对。
Write(sw, String.Format("推荐:{0}", hn.SelectSingleNode("//*[@class=\"diggnum\"]").InnerText));
Write(sw, String.Format("标题:{0}", hn.SelectSingleNode("//*[@class=\"titlelnk\"]").InnerText));
Write(sw, String.Format("介绍:{0}", hn.SelectSingleNode("//*[@class=\"post_item_summary\"]").InnerText));
Write(sw, String.Format("信息:{0}", hn.SelectSingleNode("//*[@class=\"post_item_foot\"]").InnerText));
Write(sw, "----------------------------------------");
}
sw.Close();
Console.ReadLine();
}
static void Write(StreamWriter writer, string str)
{
Console.WriteLine(str);
writer.WriteLine(str);
}
}
}
c#中是否有javascript中的jQuery类库?
jQuery在访问和操作HTML 的DOM的便捷是前端开发工程师的一种福音,在c#语言里,能否像jQuery那样便捷的访问和操作HTML呢?Html Agility Pack是一个不错的可选工具。
Html Agility Pack是codeplex里的一款开源库(http://htmlagilitypack.codeplex.com/),是一个灵活的html解析器,支持通过简单XPATH 或 XSLT来读和写DOM,最新版本已经支持LINQ。对开发网络爬虫,网络数据挖掘等方面Html Agility Pack能够提供很多功能上的支持。
Html Agility Pack的写作计划
我打算对Html Agility Pack的运用编写下面系列文章:
- Html Agile Pack基础类介绍及运用
- Html Agile Pack核心代码分析及扩展
- Html Agile Pack实现jQuery选择器的扩展
Html Agility Pack的入门
我google了下博客园中关于HtmlAgilityPack的文章还真不少(HtmlAgilityPack在博客园),入门的文字我就省的重复了,贴出几个链接方面大家查看和学习吧。
http://kb.cnblogs.com/a/1627706/ (引用自博客文章)
http://www.cnblogs.com/chuncn/archive/2009/09/07/1561564.html (引用自春夏秋冬博客)
关于WebFormRail
想了很长时间才决定用WebFormRail这个名字的,框架的名字诠释了这是一个基于rail的框架,并且可以用上官方的web控件。框架借鉴和参考了ROR、MonoRail、Spring.net、ProMesh、微软的MVC等框架的优秀的设计思想和技巧。
在NET领域里面,开源的框架很多,每一个框架都有其自身的独特和优势,但就我使用过这些框架体会,总感觉缺少了一样东西,就是web控件,包括微软的MVC框架在内,都没有支持web控件。虽然对于webform有不少的反对声音,但个人感觉web控件还是一个非常优秀的设计,特别是现在第三方提供了非常多的非常优秀的web控件,丰富而好用。
基于此,WebFormRail在总结和参考了前辈的思想和设计的基础上诞生,并且加上了自己特有的可以非常好的支持web控件的特性。
软件工程是1968年在德国的NATO会议上提出的,希望用工程化的原则和方法来克服软件危机;而软件危机就是软件开发和维护过程中的各种问题,由于软件开发阶段缺乏好的方法的指导和好的工具的辅助,而且缺少有关的文档,使得大量的软件难以维护。
软件生命周期是指由软件定义、软件开发和软件维护等阶段组成的全过程,反映软件生存期内各种工作得组织以及各个阶段如何衔接。下表归纳了软件生存周期各个阶段的任务、参与人员和产生文档。
阅读全文
泛型类声明是一种类的声明,它需要提供类型实参才能构成实际类型。
类声明可以有选择地定义类型形参:
class-declaration:
attributesopt class-modifiersopt class identifier type-parameter-listopt class-baseopt
type-parameter-constraints-clausesopt class-body ;opt
只有提供了一个 type-parameter-list,才可以为这个类声明提供 type-parameter-constraints-clauses。
提供了 type-parameter-list 的类声明是一个泛型类声明。此外,任何嵌套在泛型类声明或泛型结构声明中的类本身就是一个泛型类声明,因为必须为包含类型提供类型形参才能创建构造类型。
除了明确指出的地方外,泛型类阅读全文
