java acctionlistener种添加一个String llong类型转换成string的值,再在另外类中如何进行调

运行Java ssh项目,跳转页面出错。。在acction 写了个方法。。。是查询全部的方法,断点可以看出得到值啦_百度知道
运行Java ssh项目,跳转页面出错。。在acction 写了个方法。。。是查询全部的方法,断点可以看出得到值啦
core.java.apache.servlet.apache.java.ErrorDispatcher.apache.core.apache.apache.action:302) at org.jasper.jasper.jasper.JspServletWrapper.parseElements(Parser.ApplicationDispatcher.service(HttpServlet.jspError(DefaultErrorHandler.jasper:严重.apache.doGet(scrap&#47.action.parseCustomTag(piler.apache.java.java.java:646) at org.servlet:586) at org:317) at org.apache.piler.ParserController.java.apache.piler.parse(pile(Compiler.apache.apache.java.java.doForward(RequestProcessor:40) at org.piler.core.Scrap:1288) at org:103) at org.jasper错误信息如下(复制的).HttpServlet:1020) at org.struts.catalina.java.jasper.java.processForwardConfig(RequestProcessor.struts.core.doForward(ApplicationDispatcher.java.apache.catalina.apache.apache.jasper.struts.JspServlet.java.java:241) at org.java:1196) at org.apache.struts:1462) at org.doParse(ParserController.jasper:1683) at org,0) Unterminated &piler.piler.jasper:170) at org.service(HttpServlet.http.DefaultErrorHandler.apache.ApplicationFilterChain.jasper.java.ApplicationDispatcher.Parser:132) at org.servlet:312) at org.java.process(RequestProcessor:436) at org.servlet:342) piler.jasper.jspError(piler.java.JspCompilationContext.apache:1085) at org.ActionServlet.action.apache.RequestProcessor.Parser:332) at org.c.piler.RequestProcessor.Parser.JspServlet.java.pile(pile(Compiler:255) at org.java.RequestProcessor.doFilter(ApplicationFilterChain.action.java.invoke(ApplicationDispatcher.service(JspServlet.ParserController.Parser.parseOptionalBody(Parser:206) at org.processRequest(ApplicationDispatcher.ErrorDispatcher:290) at org:267) at piler.java.catalina.apache.parseBody(Parser.java.jasper.HttpServlet.core:374) at org.apache.ActionServlet.dispatch(ErrorDispatcher.jasper.java.apache.java: Servlet.jsp(221.java.servlet.apache.java:forEach tag at org:299) at org:717) at org.service(JspServletWrapper.apache:414) at javax:398) at org.internalDoFilter(ApplicationFilterChain.forward(ApplicationDispatcher:407) at org.serviceJspFile(JspServlet.core.ApplicationDispatcher.piler.apache:137) at org.service() for servlet jsp threw exceptionpiler.apache: &#47.ApplicationDispatcher.java.piler.jasper.apache.http
提问者采纳
页面标签用对了吗??
提问者评价
谢谢,我的标签写错啦。。少了半个大括号。。。悲哀啊。。。。。严重悲哀啊。、、
其他类似问题
为您推荐:
ssh的相关知识
等待您来回答
下载知道APP
随时随地咨询
出门在外也不愁因为正在计划做一个微信机器人,需要用,找了一下只有PHP的SDK,没有的,于是动手写了一个,基本功能已经完成。
微信公众平台地址:
Senparc.Weixin.MP官网地址:
用微信扫描下面二维码,添加测试账号为好友(添加后发送文本、位置、图片信息,测试反馈效果):
注意:开始开发之前需要到上面申请一个公众账号,并开启“关键词自动回复 =& 公众平台消息接口”,根据提示设置token等信息。
Senparc.Weixin.MP所有项目文件如下:
Senparc.Weixin.MP几个关键类介绍如下:
Entities/Request*.cs 用于接收微信平台自动发送到服务器的实体(发送过来的是XML),包括文本、位置、图片三类
Entities/Response*.cs 用于反馈给发送人的信息实体(最终会转成XML),包括文本、新闻(图文)两类
Helpers/EntityHelper.cs 用于实体和XML之间的转换(由于其中有许多需要特殊处理的字段和类型,这里不能简单用XML序列化)
Helpers/MsgTypeHelper.cs 用于获取消息类型
CheckSignature.cs 验证请求合法性类
Enums.cs 各种枚举
RequestMessageFactory.cs 用于自动生成不同Request类型的实体,并作必要的数据填充
Senparc.Weixin.MP几个关键类及重要方法(按一般使用过程排序)
生成验证字符串:Senparc.Weixin.MP.CheckSignature.GetSignature(string timestamp, string nonce, string token = null),返回根据微信平台提供的数据,SHA1加密后的验证字符串(注意token必须跟公众平台的设置一直)
验证请求:Senparc.Weixin.MP.CheckSignature.Check(string signature, string timestamp, string nonce, string token = null),验证请求是否合法
获取请求实体:var requestMessage = Senparc.Weixin.MP.RequestMessageFactory.GetRequestEntity(XDocument doc); 根据不同请求的类型,自动生成可用于操作的实体(doc只需要用XDocument.Parse(xmlString)就能生 成),requestMessage.MsgType就是请求枚举类型。
进行判断及各类操作。
根据需要,创建响应类型的实体,如:var responseMessage = ResponseMessageBase.CreateFromRequestMessage(requestMessage, ResponseMsgType.Text) as ResponseMessageT 即可返回文本类型信息。
由于目前微信只接受XML的返回数据,所以在返回之前还需要做一次转换:XDocument responseDoc = Senparc.Weixin.MP.Helpers.EntityHelper.ConvertEntityToXml(responseMessage); var xmlString = responseDoc.ToString();
至此整个微信公众账号的自动响应过程结束。
所有Senparc.Weixin.MP源代码及示例代码已开源(示例是 MVC 4,.NET 4.0,为了提高兼容性,Senparc.Weixin.MP源代码使用.NET 3.5):
(包含三个文件夹:Senparc.Weixin.MP、Senparc.Weixin.MP.BuildOutPut、Senparc.Weixin.MP.Sample,分别对应Senparc.Weixin.MP.dll源代码项目、Senparc.Weixin.MP.dll输出目录、Web示例,Web示例建议放到公网测试,让公众平台自动发送)
目前SDK还在测试中,欢迎大家提出宝贵意见!
新浪微博: QQ:
研究、探讨ASP.NET
转载请注明出处和作者,谢谢!
AJAX技术经过这么多年的发展,出现了一些框架或类库用于简化开发工作,不同的框架类库的使用方法也各不相同。 现在,再回头看看这些技术,看看这些框架类库,我们能感受到技术在不断地发展,AJAX开发越来越容易了。
本文收集了在平台上,一些具体代表性的AJAX开发方法,我将用实际的示例代码来演示如何使用它们, 让您感受AJAX的进化历程,同时也希望将一些优秀的AJAX开发方法介绍给您。
为了方便地介绍这些AJAX开发方法,我将它们划分为四代技术。
注意:按代划分AJAX技术纯属我个人的观点,只为了更好了区分它们。
此外,一些不借助任何框架类库的原始AJAX开发方法,本文将不讨论它们。
第一代技术:生成客户端代理脚本调用服务端
这类技术展示了第一代的AJAX框架的主要设计思想:在服务端为客户端生成代理脚本, 然后由这些代理脚本调用服务端,调用者可以不必知道整个调用过程是如何实现的, 而且在客户端的调用风格也基本与服务端的代码类似。
这类技术的代表作有: AJAX, AjaxPro 二个服务端框架。
下面我将用 AJAX框架来演示如何进行AJAX开发。
首先,我们可以创建一个WebService服务:
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
//若要允许使用 ASP.NET AJAX 从脚本中调用此 Web 服务,请取消对下行的注释。 [System.Web.Script.Services.ScriptService]
public class WebService1 : System.Web.Services.WebService {
[WebMethod]
public int Add(int a, int b)
return a + b;
这段代码就是一个普通的WebService代码,唯独需要注意的是:在类的定义上加了一个ScriptService修饰特性。
接下来,我们还需要在一个ASPX页面中,用ScriptManager为它生成客户端的代理脚本:
&asp:ScriptManager ID="ScriptManager1" runat="server"& &Services& &asp:ServiceReference Path="/WebService1.asmx" InlineScript="true" /& &/Services& &/asp:ScriptManager&
说明:InlineScript=”true”的设置并不是必须的,只是为了让我们看到ScriptManager到底生成了什么代码。
从截图可以看到,除了引入了二个必要的AJAX客户端类库外,还在客户端为WebService1生成了代理脚本。
有了这些代码后,我们可以用下面的代码调用服务端:
function Call_Add(){
WebService1.Add(1,2, ShowResult);
function ShowResult(result){
document.getElementById("output").value =
前面这个示例太简单了,再来个参数复杂的示例吧,还是从先服务端开始,先定义一个参数类型:
public class Customer {
public string Name { get; set; }
public int Age { get; set; }
public string Address { get; set; }
public string Tel { get; set; }
public string Email { get; set; }
WebSerice的代码:
[WebMethod]
public string AddCustomer(Customer customer)
if( customer == null )
return "customer is null.";
// 简单地返回一个XML字符串。 // 告诉客户端:服务端收到了什么样的数据。 return XmlHelper.XmlSerialize(customer, Encoding.UTF8);
仍然借用前面的ScriptManager设置,来看的调用代码:
function Call_AddCustomer(){
var customer = {Name: document.getElementById("txtName").value, Age: document.getElementById("txtAge").value, Address: document.getElementById("txtAddress").value, Tel: document.getElementById("txtTel").value, Email: document.getElementById("txtEmail").value};
WebService1.AddCustomer(customer, ShowResult);
基本上还是与服务端的编码方式差不多,先创建一个customer对象,再传给调用方法。
在那个年代之前(2006年),原始的AJAX实现方式非常复杂,而这种方法让客户端代码风格看起来与服务端十分类似,这确实是个了不起的设计思路。 然而各种技术一直在改进中,现在,2013年,当我们再来回顾这种方法时,会发现它确实存在一些不完善的地方, 以至于现在使用这种方法的人很少了,这种技术被淘汰了!
其实我们可以从另一外角度来思考:如果这种方法真的很优秀,它就不可能被淘汰,正是因为有更优秀的方法的了出现, 它才会遭到淘汰的命运。
新技术的改进方向
前面介绍的那种AJAX方法能让客户端的调用代码与服务端的代码风格基本一致,看似很完美的方法为什么会被淘汰了呢?
我来分析一下这种开发方法的缺陷:
1. 前端代码不够独立,必须要在页面中添加引用之后才能调用服务端,这其实是一种强耦合。
2. 出现了更优秀的前端框架能简少获取调用参数的代码量。
继续阅读本文,您会发现后面我将要介绍的新方法都朝着解决这些缺陷在努力, 这些缺陷也算是指出了新技术的改进方向。
由于前端在调用服务端时,需要事先生成代理脚本,这种设计会阻碍前端代码的封装性。 您可以想象一下:如果客户端需要一个【获取当前用户信息】的功能,而这个功能必须由服务端实现的, 此时,我们就只能指望服务端为客户端生成代理类来调用这个功能了。 但这个功能太有用,许多地方都需要使用,您是不是会想将它提取到一个公用的文件中?
遗憾的是:就算您将这段调用代码提取到一个公共的public.js文件中,每个页面在引用public.js后, 并不能调用【获取当前用户信息】功能,因为代理脚本并不一定存在,public.js中的代码还不能运行起来。 怎么办?
答:为每个引用public.js的页面,再添加ScriptManager引用那个服务吧。
共用性越高的功能,您会发现这种引用代码的重复度也就越高。
简单说来,这种方法将WebService, aspx页面, js代码耦合在一起了。
由于耦合,您越用越发现越麻烦。
这种生成代理脚本的开发方法虽然能让前端代码与后端代码的风格一致,然而, 前端与后端毕竟不是同一种开发语言,它们要关注的方向也是不一样的。尤其是当更优秀的前端框架出现后, 这种后端包办前端的方法不仅让后端与前端耦合在一起,而且还限制了前端技术的发展, 最终只能是被抛弃的命运!
现在请记住我们为了提交一个Customer信息写了什么样的代码:
var customer = {Name: document.getElementById("txtName").value, Age: document.getElementById("txtAge").value, Address: document.getElementById("txtAddress").value, Tel: document.getElementById("txtTel").value, Email: document.getElementById("txtEmail").value};
我在介绍第四代技术时,您会发现它们消失了!
第二代技术:直接调用WebService
随意前端类库的流行,另一种新的开发方法也开始流行起来了。
HTTP调用本来是个很简单很透明的技术,只要指定一个URL,构造一个请求体就可以了, 前端代理脚本的方法将这个过程封装了起来,由于它的封装制造了耦合并限制前端的发展。 新的AJAX技术只能突破这个限制,舍弃这些代理脚本,直接调用后端代码。
下面的示例代码还是基于前面的示例,唯独不同的是:不是需要代理类,现在是直接调用服务端。
由于后端的服务代码没有改变,我也就不再贴出它们了,而且页面也不需要再添加什么引用,我们就直接看前端代码好了:
type:"POST", url: "/WebService1.asmx/Add", contentType:"application/json", data:"{a: 1, b: 2}", dataType:'json', success:function(result){
$("#output").val(result.d);
这段代码也能调用服务端的Add方法。
由于服务端采用JSON数据格式,所以需要在客户端多指定一些请求头,而这些事情以前是由代理脚本完成的。 虽然现在的代码稍微多一点,但是耦合没有了,更便于提取一些公用代码了。
事实上,如果您一直用这种方法调用WebService,那么提供了设置默认参数的功能, 我们可以利用这个特性减少代码量。
还是再来看一下前面那个复杂的参数类型的前端调用代码吧:
var customer = {Name: $("#txtName").val(), Age: $("#txtAge").val(), Address: $("#txtAddress").val(), Tel: $("#txtTel").val(), Email: $("#txtEmail").val()};
var jsonStirng = $.toJSON( {customer: customer} );
type:"POST", url: "/WebService1.asmx/AddCustomer", contentType:"application/json", data: jsonStirng, dataType:'json', success:function(result){
$("#output").val(result.d);
主要的代码还是一样的,集中在获取调用参数,但是要转成JSON格式。
再次一次提醒:不要老是盯着要指定一大堆的参数,它们可以通过设置默认值的方式解决。
我之所以现在不想让它们消失,是因为后面还有更好的方法,先留着它们吧。
说明:这种方法不仅可以用于调用WebService,也可以调用WCF (basicHttpBinding),毕竟它们都使用HTTP协议。 不过,WCF还有一堆烦人的配置要设置,但这不是JQuery的问题,这是服务端框架的缺陷。
第三代技术:更简单的数据格式
前面我们看到了可以利用JQuery调用WebService,不过JSON的转换过程感觉有些多余,浏览器的提交就没有这个转换步骤嘛。 有时看到一些家伙们着还在中拼接JSON字符串,我非常反感,所以这次的示例代码并没有给那种方法抹黑,我采用了一个JSON插件。
第三代技术就完美地解决了输入输出必须采用JSON问题,而且解决了POST的限制。
由于这次变革改变了数据格式,所以服务端也发生了改变, 新的框架解决了这些问题,例如:框架,框架都支持这个开发方式。
来看一下现在服务端的代码:
public int Add(int a, int b)
return a + b;
public string AddCustomer(Customer customer)
// 简单地返回一个XML字符串。 // 告诉客户端:服务端收到了什么样的数据。 return XmlHelper.XmlSerialize(customer, Encoding.UTF8);
注意:这种AJAX技术没有与客户端的任何耦合,只要知道一个URL就可以调用了。 来看客户端的代码吧:
type:"POST", url: "/AjaxDemo/Add.cspx", data: {a: 1, b: 2}, success:function(result){
$("#output").val(result);
// 第二个调用 var customer = {Name: $("#txtName").val(), Age: $("#txtAge").val(), Address: $("#txtAddress").val(), Tel: $("#txtTel").val(), Email: $("#txtEmail").val()};
type:"POST", url: "/AjaxDemo/AddCustomer.cspx", data: customer, success:function(result){
$("#output").val(result);
注意:type:”POST”并不是必须的,您也可以把它们改成GET方式提交。
如果您此时用Fiddler查看请求内容,会发现请求的数据采用的是key=value&key=vlaue的格式,与浏览器的方式一致。 由于没有JSON数据格式的限制,现在的参数项简单了。
现在再看上面这段代码,主要代码量在哪里?
是不是在获取调用参数那块?
继续阅读本文,我要让它消失。
第四代技术:直接提交表单
我们来看一下示例用的表单:
&form id="form1" action="/AjaxDemo/AddCustomer.cspx" method="post"& &p&&b&新增客户资料&/b&&/p& &span&Name: &/span&&input type="text" name="Name" value="abc" /&&br /& &span&Age: &/span&&input type="text" name="Age" value="20" /&&br /& &span&Address: &/span&&input type="text" name="Address" value="武汉" /&&br /& &span&Tel:&/span& &input type="text" name="Tel" value="" /&&br /& &span&Email: &/span&&input type="text" name="Email" value="" /&&br /& &br /& &input type="submit" name="btnAddCustomer" value="保存客户资料" /& &/form&
前面用了三种方法在提交这个表单,下面我们再来看一下更简单的提交方式:
&script type="text/javascript"& $(function(){
// 只需要下面这个调用就可以将表单改成异步提交方式! $("#form1").ajaxForm({
success:function(result){
$("#output").val(result);
为了更清楚展示这种方法,我甚至把script标签也贴出来了。
如果您用过JQuery就应该能发现,真正的代码就只有ajaxForm的那个调用。
服务端的代码继续使用前面示例的代码,所以就不贴出了。
再对比前面几种AJAX的实现方法,您说哪种方法最简单?
多submit按钮的提交(用Jquery.form实现)
您认为前面的示例太简单了,是吗?
可能有人会说,如果有多个submit按钮,这种方法就不合适了,我要响应每个按钮,为它们指定不同的URL !
真是这样吗? 看下面的示例吧。
相关的前端代码如下:
&form id="form1" action="/AjaxTestAutoAction/submit.cspx" method="post"& &p&&span&Input:&/span& &input type="text" name="input" style="width: 300px" value="Fish Li" /&&/p& &p&&span&Output:&/span& &input type="text" id="output" style="width: 300px" readonly="readonly" /&&/p& &input type="submit" name="Base64" value="转换成Base64编码" /&&& &input type="submit" name="Md5" value="计算md5" /&&& &input type="submit" name="Sha1" value="计算sha1" /& &/form& &script type="text/javascript"& $(function(){
$("#form1").ajaxForm(function(result) {
$("#output").val(result);
服务端代码:
public class AjaxTestAutoAction {
public string Base64(string input)
return Convert.ToBase64String(Encoding.Default.GetBytes(input));
public string Md5(string input)
byte[] bb = Encoding.Default.GetBytes(input);
byte[] md5 = (new MD5CryptoServiceProvider()).ComputeHash(bb);
return BitConverter.ToString(md5).Replace("-", string.Empty);
public string Sha1(string input)
byte[] bb = Encoding.Default.GetBytes(input);
byte[] sha1 = (new SHA1CryptoServiceProvider()).ComputeHash(bb);
return BitConverter.ToString(sha1).Replace("-", string.Empty);
代码仍然很清晰:
1. 服务端定义三个方法,对应三个submit按钮。
2. 前端还是只调用一个ajaxForm解决所有问题。
这种方法就是由前端的 jquery, jquery.form 以及服务端的框架 共同实现的。 想像一下利用其它三种方法需要多少代码吧。
批量输入控件的提交(用Jquery.form实现)
再来展示另一个现实的例子,批量输入界面的提交。
页面表单代码如下:
JavaScript代码:
&script type="text/javascript"& $(function(){
$("#form1").ajaxForm({
success:function(result){
$("#output").val(result);
服务端代码如下:
这个示例的全部代码就这么多,废话不想多说,您自己去想用其它方法需要多少代码!
提交复杂表单(用Jquery.form实现)
前面的示例都是直接提交表单,没有验证表单的过程,而且都以Textbox控件为主,再来个复杂的表单示例。
页面表单代码如下:
JavaScript代码:
&script type="text/javascript"& $(function(){
$("#form1").ajaxForm({
beforeSubmit: ValidateForm, success:function(result){
$("#output").val(result);
function ValidateForm(formData, jqForm, options) {
if( jqForm.context.ProductName.value.length == 0 ){
alert("商品名称不能为空。");
$(jqForm.context.ProductName).focus();
return false;
return true;
服务端代码:
public string AddProduct(Product product)
// 简单地返回一个XML字符串。 // 告诉客户端:服务端收到了什么样的数据。 return XmlHelper.XmlSerialize(product, Encoding.UTF8);
各种AJAX开发方法的对比与总结
看过了这些示例后,我们再来回顾这些AJAX方法的进化过程:
1. 以ASP.NET AJAX为代表的【生成客户端代理脚本调用服务端】技术, 为了包装原始AJAX的复杂过程,服务端为客户端生成了代理脚本, 这种封装后的客户端在调用方式上与服务端基本一致,看起来简化了不少,而且降低了开发门槛, 然而,它的优点也是它是它的最大缺点:服务端包办了客户端的事情,它完全没有想到客户端技术也在进步! 当更优秀的前端技术出现时,它的结局只能是淘汰。
2. 【Jquery直接调用WebService】可以看做是第一代技术的改进,它丢弃了服务端生成代理脚本的功能, 直接在客户端准备服务端所需要的数据格式,借助JQuery内部对XmlHttpRequest的封装,也能方便地调用服务端。 这种方法解决了客户端、服务、页面三方的耦合,但是数据格式却受到序列化方式的限制,使得起来怪怪的。 这种怪怪的感觉其实也是不方便的表现。
3. 为了让前端更方便地调用服务端,服务端框架只能改变,框架和MyMVC框架都支持更简单的数据格式, 而且不需要那个多余的asmx文件,直接用类库就可以响应客户端请求。 这类技术的最主要特点是:用更简单的数据格式就可以调用服务端。 由于数据格式简单化,为以后的继续改进留下了机会。
4. 由于服务端不要求序列化的数据格式,且前端技术仍在进步,终于jquery.form插件可以让我们不需要关注表单数据的收集过程, 它能模拟浏览器的提交行为,正确识别【成功控件】并将它们提交到服务端,因此代码得到最大限度的缩减,让AJAX开发过程更加容易。
前面几个采用jquery.form的示例也让我们看到:不管表单是什么样的,永远只需要一个调用。
而且它将JQuery的调用过程也做了非常好的封装,所以我认为这是最容易使用的AJAX开发方法。
1. jquery:
2. jquery.form:
公司需要若干名 .net 方面的高级开发人员,要求熟悉以下技术领域:
1. .net framework
2. ASP.NET
SERVER (T-, SP)
4. JavaScript, jquery
6. 常见的设计模式。
1. 公司名称:
2. 工作地点:武汉。
3. 我只是负责【推荐】,具体细节请发邮件给我:
4. 咨询招聘相关的疑问也请发邮件给我,评论中的疑问一律不回复!
delegate:代表,授权,翻译为“委托”,即用对象代表方法成员或对象被授权执行方法成员。看下面一小段代码:
int Max(int x,int y) { return x&y?x:y; } int Min(int x,int y) { return x&y?x:y; }
上面两个函数的共同特点:具有相同的返回值和参数列表。在C++里,我们使用函数指针来指代(被授权,代表)这两个函数。实际上,我们可以用函数指针指向任意一个具有相同返回值和参数列表的函数(静态方法或实例的方法成员)。
//定义一个函数指针,并声明该指针可以指向的函数的返回值为int类型,参数列表中包括两个int类型的参数
int (*p)(int,int); //让指针p指向Max函数
p= //利用指针调用Max
c=(*p)(5,6);
在里没有提供函数指针,取而代之的是委托(delegate);利用委托,我们可以像使用函数指针一样在程序运行时动态指向具备相同签名(具有相同参数类型、参数个数以及相同类型返回值)的方法。
委托的定义
之前我们在引出委托时已经简单的介绍了委托的本质:函数指针。说的通俗一些,委托就是能够让方法作为变量来传递。我个人喜欢下面这个定义:
委托是一种类型安全的函数回调机制, 它不仅能够调用实例方法,也能调用静态方法,并且具备按顺序执行多个方法的能力。
也就是说,委托可以在程序运行时调用不同方法函数,只要这个方法签名和委托签名保持一致。与函数指针不同的是,委托是类型安全的。所谓类型安全,是指在编译时编译器会检测委托对象的签名是否委托声明一致。看下面一小段简单的代码感受委托的含义:
using S using System.Collections.G using System.L using System.T namespace DelegateSamples { //声明一个委托,参数为string,无返回值
delegate void DelSamples(string msg); class Program { static void Main(string[] args) { DelSamples delSample = new Program().SpeakC //调用实例方法
delSample += SpeakE //调用静态方法
delSample("KoalaStudio"); Console.ReadKey(); } private void SpeakChinese(string msg) { Console.WriteLine("你好,我是{0}",msg); } private static void SpeakEnglish(string msg) { Console.WriteLine("Hello,I'm {0}",msg); } } }
输出结果:
委托的声明
using S using System.Collections.G using System.L using System.T namespace DelegateSamples { //声明一个委托,参数为string,无返回值
delegate void DelSamples(string msg); class Program { static void Main(string[] args) { //使用new关键字
DelSamples delSample = new DelSamples(new Program().SpeakChinese); delSample("Koala工作室"); //不使用new,自动推断委托类型
DelSamples delSample2 = SpeakE delSample2("KoalaStudio"); //利用Lambda表达式
DelSamples delSample3 = (string msg) =& SpeakEnglish(msg); delSample3("KoalaStudio"); Console.ReadKey(); } private void SpeakChinese(string msg) { Console.WriteLine("你好,我是{0}",msg); } private static void SpeakEnglish(string msg) { Console.WriteLine("Hello,I'm {0}",msg); } } }
using S using System.Collections.G using System.L using System.T namespace DelegateSamples { //声明一个委托,参数为string,无返回值
delegate void DelSamples(string msg); class Program { static void Main(string[] args) { //匿名委托
DelSamples delSample4 = delegate(string msg) { Console.WriteLine("你好,我是{0}", msg); }; delSample4("KoalaStudio"); //利用Lambda表达式实现匿名委托
DelSamples delSample5 = (string msg) =& { Console.WriteLine("你好,我是{0}", msg); }; delSample5("KoalaStudio"); Console.ReadKey(); } private void SpeakChinese(string msg) { Console.WriteLine("你好,我是{0}",msg); } private static void SpeakEnglish(string msg) { Console.WriteLine("Hello,I'm {0}",msg); } } }
匿名委托的写法更加优雅,但是需要注意两点:1、在函数内部不能使用跳转语句跳出函数外部;2、不能使用ref和out等关键字
using S using System.Collections.G using System.L using System.T namespace DelegateSamples { //声明一个委托,参数为string,无返回值
delegate void DelSamples(string msg); class Program { static void Main(string[] args) { //多播委托可以带返回值,但是只有最后一个方法的返回值会被返回。
DelSamples delSample6 = new Program().SpeakC delSample6 += SpeakE delSample6("KoalaStudio"); Console.ReadKey(); } private void SpeakChinese(string msg) { Console.WriteLine("你好,我是{0}",msg); } private static void SpeakEnglish(string msg) { Console.WriteLine("Hello,I'm {0}",msg); } } }
多播委托可以连续执行函数,但是如果函数有返回值,那只有最后一个函数的返回值会被正确返回.
泛型委托和一般的委托用法类似,只是习惯了传统委托的使用后在写法上看着有些别扭。泛型委托可能在运行时确定委托的类型,提高了委托的通用性,这和泛型类 的意义是一样的。这里不再介绍泛型的概念,如果你对泛型还不熟悉,园子里有很多优秀的文章已经详细介绍了相关内容。泛型委托包括Action、Func和 Predicate三种委托。
using S using System.Collections.G using System.L using System.T namespace DelegateSamples { class Program { static void Main(string[] args) { /* Action&T&:封装只有一个参数(类型为T),不包括返回值的签名函数,它包括以下几种情况: * Action&T&、Action&T1,T2&、Action&T1,T2,T3&、Action&T1,T2,T3,T4& * 声明: * delegate void Action(); * delegate void Action&T1&(T1 arg1); * delegate void Action&T1,T2&(T1 arg1,T2 arg2); * delegate void Action&T1,T2,T3&(T1 arg1,T2 arg2,T3 arg3); * delegate void Action&T1,T2,T3,T4&(T1 arg1,T2 arg2,T3 arg3,T4 arg4); */ Action&string& action = SpeakE action("KoalaStudio"); Action&string, string& action2 = SpeakTwoL action2("KoalaStudio","Koala工作室"); Console.ReadKey(); } private void SpeakChinese(string msg) { Console.WriteLine("你好,我是{0}",msg); } private static void SpeakEnglish(string msg) { Console.WriteLine("Hello,I'm {0}",msg); } private static void SpeakTwoLanguage(string msg1, string msg2) { Console.WriteLine("你好,我是{0}",msg1); Console.WriteLine("Hello,I'm {0}",msg2); } } }
using S using System.Collections.G using System.L using System.T namespace DelegateSamples { class Program { static void Main(string[] args) { /* Func&T,TResult&:封装一个具有参数(类型为T),返回TResult类型值的签名函数,它包括以下几种情况: * Func&T,TResult&、Func&T1,T2,TResult&、Func&T1,T2,T3,TResult&、Func&T1,T2,T3,T4,TResult& * 声明: * ……略去 */ Func&string,string/*这是返回值类型*/& func = SpeakE func("KoalaStudio"); Func&string, string, string/*这是返回值类型*/& func2 = SpeakTwoL func2("KoalaStudio","Koala工作室"); Console.ReadKey(); } private static string SpeakEnglish(string msg) { return string.Format("Hello,I'm {0}", msg); } private static string SpeakTwoLanguage(string msg1, string msg2) { Console.WriteLine("你好,我是{0}",msg1); Console.WriteLine("Hello,I'm {0}",msg2); return string.Format("你好,我是{0};Hello,I'm {1}", msg1,msg2); } } }
using S using System.Collections.G using System.L using System.T namespace DelegateSamples { class Program { static void Main(string[] args) { /* bool Predicate&T&:表示定义一组条件并确定指定对象是否符合这些条件的方法。 * 通常,此类委托由Array和List类的几种方法使用,用于在集合中搜索元素。 * delegate bool Predicate&T&(T obj),如果obj符合此委托表示的方法中定义的条件,则返回true,否则返回false */ List&string& listString = new List&string&() { "a","abc","koala","xyz","take" }; //List对象的FindAll定义:public List&T& FindAll(Predicate&T& match); //match 类型:System.Predicate&T& 委托,用于定义要搜索的元素应满足的条件。 //返回值 //类型:System.Collections.Generic.List&T& //如果找到,则为一个 List&T&,其中包含与指定谓词所定义的条件相匹配的所有元素;否则为一个空 List&T&。
Predicate&String& match = delegate(string word) { if (word.Length & 4) { return true; } return false; }; List&string& result = listString.FindAll(match); } } }
看到这里相信大家都已经感觉出来了,委托的申明和使用和类非常相似。没错,委托本质上就是一个类。实际上,我们用delegate关键字声明的所有委托都 继承自System.MulticastDelegate类,这个类又继承自System.Delegate类,而System.Delegate类则继 承自System.Object。尽管如此,我们并不能直接声明一个继承自System.MulticastDelegate类的委托,委托必须用 delegate关键字声明。在我们声明委托时,编译器为我们完成了很多复杂的工作,有兴趣的朋友可以查阅相关资料。不过,即使不清楚编译器为我们干了什 么也没有关系,只要知道在我们调用委托时,编译器自动为委托创建了BeginInvoke、EndInvoke和Invoke三个方法。BeginInvoke和EndInvoke方法用来实现异步委托调用,后面我们再详细介绍。
DelSamples delSample2 = SpeakE delSample2("KoalaStudio"); //其实是调用编译器生成的Invoke方法
delSample2.Invoke("KoalaStudio");
写到这儿,其实已经把委托的基本概念介绍完了。接下去的内容会稍微复杂一些,刚刚接触委托的朋友可以跳过这部分,直接阅读委托与事件部分。
协变与逆变
MSDN的解释:从Visual Studio2008开始.NET引入了变体支持,用于委托中匹配方法签名和委托类型。这意味着,我们不仅可以为委托指派具有匹配签名的方法,而且可以指 派这样的方法:它们返回与委托类型指定的派生类型相比,派生程度更大的类型(协变),或者接受相比之下,派生程度更小的类型的参数(逆变)。相当拗口,对 不对?不知道它想说明什么。稍微休息一下,忘记之前那长串的描述。我们来想一个情形:面向对象的一个典型应用就是继承和多态。假如我们定义了一个委托,它 返回的类型是一个基类对象。如果有个方法,它的参数签名符合我们定义的委托参数签名,但是返回的是继承该基类的子类对象,那么这个方法是否能够使用该委 托?又比如,我们定义了一个委托,它具有指定的参数签名。如果有个方法,它的参数是委托签名中的方法参数的基类(委托方法签名中的参数派生自调用方法的参 数),那么这个方法是否能够使用该委托?答案是可以的!这也就是MSDN想说 的:协变就是委托的类型返回值是它所指向函数(即调用的方法)的返回值的基类;逆变就是委托的类型参数是它所指向函数的参数的派生类。协变允许方法具有的 派生返回类型比委托中定义的更多。 逆变允许方法具有的派生参数类型比委托类型中的更少。MSDN上提供的一个协变的例子:
class Mammals{} class Dogs : Mammals{} class Program { // 定义一个委托,返回基类.
public delegate Mammals HandlerMethod(); public static Mammals MammalsHandler() { return null; } public static Dogs DogsHandler() { return null; } static void Test() { HandlerMethod handlerMammals = MammalsH // 被允许.
HandlerMethod handlerDogs = DogsH } }
再看个逆变的例子:
// Event hander接受一个EventArgs类型的参数.
private void MultiHandler(object sender, System.EventArgs e) { label1.Text = System.DateTime.Now.ToString(); } public Form1() { InitializeComponent(); // KeyDown期望接受的是KeyEventArgs对象,但是我们给的是EventArgs对象
this.button1.KeyDown += this.MultiH this.button1.MouseClick += this.MultiH }
协变和逆变先介绍基本的应用,其它还包括泛型委托的协变和逆变,有兴趣的朋友可以参考MSDN里的例子,这里不再赘述。
既然委托可以在运行时调用方法函数,如果调用的方法非常复杂耗时,主线程是不是会被阻塞以等待方法执行?我们看一段代码:
using S using System.Collections.G using System.L using System.T using System.T namespace DelegateSamples { public delegate void delSample (); class Program { static void Main(string[] args) { delSample _sample = DoT _sample(); Console.WriteLine("执行另一项工作。"); Console.ReadKey(); } public static void DoTask() { Console.WriteLine("开始执行复杂工作。"); //线程阻塞5s,模拟进行复杂的工作。
Thread.Sleep(TimeSpan.FromSeconds(5)); Console.WriteLine("工作执行完毕。"); } } }
从下面的输出结果我们看到,委托调用的是主线程,因此复杂的方法函数会导致主线程阻塞,影响用户体验。那有没有办法可以改变呢?有!异步委托。
异步委托会从线程池中开辟一个新的线程用来调用方法,我们改动一下上面的代码,开启异步委托:
namespace DelegateSamples { public delegate void delSample (); class Program { static void Main(string[] args) { delSample _sample = DoT _sample.BeginInvoke(null, null); Console.WriteLine("执行另一项工作。"); Console.ReadKey(); } public static void DoTask() { Console.WriteLine("开始执行复杂工作。"); //线程阻塞5s,模拟进行复杂的工作。
Thread.Sleep(TimeSpan.FromSeconds(5)); Console.WriteLine("工作执行完毕。"); } } }
看一下返回结果:
好像和我们预想的不太一样,主线程并没有等待委托的执行,而是继续执行下面的操作并退出。这是什么原因?还是和线程有关。默认线程池中的线程都是后台线 程,主线程不会等待后台线程的执行,仿佛它根本不存在。那有办法解决这个问题吗?能不能让主线程等待委托线程执行完毕在退出?我们再看一下MSDN给出的 解释:BeingInvoke方法启动异步委托,它具有和异步执行的方法相同的参数,同时还有两个可选参数。第一个参数是AsyncCallBack委 托,该委托引用在异步调用完成时要调用的方法(即回调函数);第二个参数是一个用户定义的对象,可以将信息传入回调函数。BeginInvoke立即返回 而不等待异步调用完成(这就解释了上面的原因),但是会返回一个用于监控异步调用进度的IAsyncResult。EndInvoke方法检索异步调用的 结果。在调用 BeginInvoke 之后随时可以调用该方法。如果异步调用尚未完成,则 EndInvoke 会一直阻止调用线程,直到异步调用完成。我们改一下上面的代码:
namespace DelegateSamples { public delegate void delSample (); class Program { static void Main(string[] args) { delSample _sample = DoT IAsyncResult result = _sample.BeginInvoke(null, null); while (result.IsCompleted) { //可以监控异步方法执行是否完成 //do task
} _sample.EndInvoke(result); Console.WriteLine("执行另一项工作。"); Console.ReadKey(); } public static void DoTask() { Console.WriteLine("开始执行复杂工作。"); //线程阻塞5s,模拟进行复杂的工作。
Thread.Sleep(TimeSpan.FromSeconds(5)); Console.WriteLine("工作执行完毕。"); } } }
从输出结果看,委托线程确实阻塞了主 线程,但是这依然会影响用户体验。我们希望的流程是:主线程调用委托线程后继续执行后面的逻辑业务,等逻辑业务完成后等待委托线程的返回。我们利用 WaitHandle等待异步调用来解决这个问题,异步调用完成时会发出WaitHandle信号,我们可以通过调用WaitOne方法等待该信号。
namespace DelegateSamples { public delegate void delSample (); class Program { static void Main(string[] args) { delSample _sample = DoT IAsyncResult result = _sample.BeginInvoke(null, null); //等待1s,执行主线程
result.AsyncWaitHandle.WaitOne(
,false); //_sample(); //_sample.EndInvoke(result);
Console.WriteLine("执行另一项工作。"); _sample.EndInvoke(result); Console.ReadKey(); } public static void DoTask() { Console.WriteLine("开始执行复杂工作。"); //线程阻塞5s,模拟进行复杂的工作。
Thread.Sleep(TimeSpan.FromSeconds(5)); Console.WriteLine("工作执行完毕。"); } } }
再看一种回调模式
namespace DelegateSamples { public delegate void delSample (); class Program { static void Main(string[] args) { delSample _sample = DoT _sample.BeginInvoke( delegate(IAsyncResult ar) { _sample.EndInvoke(ar); },null ); Console.WriteLine("执行另一项工作。"); Console.ReadKey(); } public static void DoTask() { Console.WriteLine("开始执行复杂工作。"); //线程阻塞5s,模拟进行复杂的工作。
Thread.Sleep(TimeSpan.FromSeconds(5)); Console.WriteLine("工作执行完毕。"); } } }
回调模式是在BeginInvoke后立刻调用回调函数,这个回调函数是在 ThreadPool线程上进行的,因此主线程将继续执行。ThreadPool线程是后台线程,这些线程不会在主线程结束后保持应用程序的运行,因此主线程必须休眠足够长的时间以便回调完成。我们也可以在主线程完成操作后调用IsCompleted属性判断委托函数是否完成。
委托与事件
既然说了委托,自然离不开事件。在这里我不打算详细阐述事件机制及其相关的内容,后面我会再整理一篇有关事件的文章。我打算从委托出发,看看事件是怎么和委托扯上关系的。先看一段代码:
namespace DelegateSamples { public class Program { static void Main(string[] args) { Publish publish = new Publish(); Subscribe subscribe = new Subscribe(); publish.delEventHandler += subscribe.OnLeaveM publish.OnFire("我触发了委托!"); //调用委托
publish.delEventHandler("我触发了委托!"); Console.ReadKey(); } } //定义委托
public delegate void FireEventHandler(string msg); public class Publish { public FireEventHandler delEventH public void OnFire(string msg) { if (delEventHandler != null) { delEventHandler(msg); } } } public class Subscribe { public Subscribe(){} public void OnLeaveMessage(string msg) { Console.WriteLine(msg); } } }
这里我们发现,如果要使用委托变量,那么在类的内部委托变量必须是public,这就显得不安全。我只希望外部通过Publish.OnFire()来执行委托,但是外部仍然可以直接调用委托。于是,我们换一个写法,再看代码:
namespace DelegateSamples { public class Program { static void Main(string[] args) { Publish publish = new Publish(); Subscribe subscribe = new Subscribe(); publish.delEventHandler += subscribe.OnLeaveM publish.OnFire("我触发了委托!"); //调用委托
publish.delEventHandler("我触发了委托!"); Console.ReadKey(); } } //定义委托
public delegate void FireEventHandler(string msg); public class Publish { //public FireEventHandler delEventH //不使用委托关键字delegate,采用event关键字
public event FireEventHandler delEventH public void OnFire(string msg) { if (delEventHandler != null) { delEventHandler(msg); } } } public class Subscribe { public Subscribe(){} public void OnLeaveMessage(string msg) { Console.WriteLine(msg); } } }
publish.delEventHandler(“我触发了委托!”),编译无法通过,这意味着外部不能直接调用委托变量,尽管他的属性还是 public。因为加了event关键字,本质上是生成了私有的委托变量,减少了外部对类内部变量的修改权利。说到这里,我们再来看一下事件和委托的关 系。在CLR综合那个事件模型是建立在委托机制上的,这就是他们之间的联系。委托是对方法的抽象,它将方法的调用与实现分离,方法的调用者(即委托的执行 者)不知道方法内部的实现,而方法的实现者也不知道方法什么时候会被调用。正是因为委托具有这样的特性,才使得它理所当然的用来实现事件机制。因为事件被 触发后执行什么操作,是由触发者决定的,而事件拥有者只知道什么情况下会触发事件,但不知道事件的具体实现。
最后,我们看一下事件的定义。事件用event关键字定义,其类型是一个委托类型,这体现了事件是通过委托来实现的。上面的代码已经展示了最基本的事件定 义方式,即:自定义一个委托,然后再申明一个event事件。在.NET3.5开始,由于支持泛型,定义事件时可以不需要再自定义委托,统一采用 System.EventHandler&TEventArgs&委托,如何改造上面代码,请大家自行修改。
  本来是要对其项目做完再上传给大家的。但是最近因为要在.net 平台下做bt协议的播放器。所以这个真没时间来顾及了。每天9点上9点下班的。所以只能草草收尾,不懂的可以邮箱() 给我,或者博客下面留言,互相交流,另外这个是按照 MVC 3.0高级编程指导写的,只不过是换在了mvc4.0下,基础部分不讲解了,网上这些教程很多,这个项目只是一个提高。里面采用EF框架来实现的,另外自 己在开发过程中也有小小的疑惑,希望有大牛人物帮我解惑,谢谢。
好了,进入正题,先看效果图。这是首页,有个流派分类和最火的专辑呈现在首页
2.这里是点击一个专辑显示的详细页面。还有一个添加到购物车的按钮操作。
3.这是浏览某一个流派类别下的所有专辑,还有一个简单的分页显示
4.这是添加到购物车的页面视图,移除里面商品的时候采用的无刷新
5.一个简单的登录界面,也是我比较疑惑的地方。我没有用他们写的Membership类进行用户的验证,想知道实际项目开发中是不是要用到它呢, 如果可以用自己的数据库设计去实现用户登录的话,怎么去实现传统的web form 登录验证错误时,js提示错误之后,并跳转该怎么实现,虽然这里我实现了,但感觉怪怪的~
样式是用了Base css框架,也有针对性一些修改,代码点击,我这边就不对代码进行说明了(在项目中有些需要注意的地方,我进行了代码注释了的),其实不是很复杂,当然了,我会根据看官的反应再进行一些代码的讲解。管理员和结算这2块功能没实现,如果有时间了我也会写了再上传。(原mvc 3.0的项目代码点击下载,是英文的哦~),下载连接已更新
一: RAID简介
RAID(Redundant Array of Independent Disk 独立冗余磁盘阵列)是一项数据保护策略.
二: RAID的几种常用级别
1. RAID 0:
通过并行读取来提高数据I/O, 读取操作效率很高, 但是不提供数据容错及保护. 不推荐作为 Server使用.
2. RAID 1:
镜像保护,有两个驱动器,一个做主驱动器,一个做镜像, 所以是实际需要两倍的驱动器,第二个所为冗余使用. 使用RAID 1我们的存储容量应该是(n*s/2)。
一次写操作写入到两个磁盘, 所以虽写入速度会稍微有影响, 但是读取速度几乎是大多数情况下的两倍. 因为在读取操作过程中驱动器可以并行地进行访问,从而提高了吞吐量。RAID 1限制于两个驱动器。
3. RAID 5:
带校验的磁盘条带。在这种类型的RAID中,数据以复杂条带的形式写入到阵列中的所有驱动器中,同时所有驱动器中都有分布数校验块。这样RAID 5就可能使用三个或者更多磁盘组成的任意大小的阵列,只牺牲相当于一个磁盘的存储容量用于校验。但是这种校验是分布式的,并不单独存在于任何一个物理磁盘 中.
RAID 5由于在大型阵列中牺牲的存储容量较少,所以它具有成本效益的特点,从而被人们所广泛使用。与镜像不同的是,带有校验的条带要求必须在磁盘之间进行针对每 个写入条带的计算,这造成了一部分的开销。因此,吞吐量并不总是一个容易计算的项目,它在很大程度上取决于系统在做校验计算时候的计算能力。
计算RAID 5的容量非常简单:就是((n-1)*s)。RAID 5阵列可以避免这列中任何单个磁盘的丢失.
对RAID5的每一次写操作, 都会涉及到多个读用于计算并且存储. 对 Server有很多的写操作,并且要求很高效率的时, RAID 5并不是一个很好的选择.
带双重校验的磁盘条带。RAID 6与RAID 5非常相似,但它的每个条带使用两个校验块,而不是一个,这加强了应对磁盘故障的保护能力。
RAID 6是RAID家族中的新成员。RAID 6是其他几个RAID类型实现标准化几年之后增加的。RAID 6比较特殊,因为它可以承受阵列中任意两个驱动器的故障,同时防止数据丢失。但是为了配合额外的冗余度,RAID 6阵列需要牺牲阵列中相当于两个驱动器的容量,并要求真列中最少有四个驱动器。RAID 6的容量可以用((n-2)*s)来计算。
5. RAID 10:
带条带的镜像。从技术上来说,RAID 10是一种混合的RAID,包括存在于一个非校验条带(RAID 0)中的一对RAID镜像。
当一个阵列中只有两个驱动器的时候,很多厂商会称其为RAID 10(或者RAID 10+),但从技术上来说这应该是RAID 1,因为阵列中至少有四个驱动器才会发生条带化。对于RAID 10来说,驱动器必须是一对一对添加的,因此阵列中的驱动器数量只可能是偶数。
RAID 10可以在丢失近半数驱动器组的情况下正常运转,同时最多只能承受每个驱动器中一个驱动器发生故障或者丢失。RAID 10不包含校验计算,这使得它相对RAID 5和RAID 6来说具有一定的性能优势,而且阵列对计算能力的要求也更低。RAID 10提供了超过任何一种常见类型RAID的读取性能,因为在读取操作中阵列中的所有驱动器都可同时使用。但是RAID 10的写入性能要低很多。RAID 10的容量计算方法和RAID 1相同,都是(n*s/2)。
RAID性能比较:
读效率: 因为是并行读取, 读取效率都很高.
写效率: RAID 0 & RAID 1 & RAID 10 & RAID 5
磁盘利用率: RAID 0 & RAID 5 & RAID 1 = RAID 10
RAID 10 = RAID 1 & RAID 5 & RAID 0
作为 Server 的DB Server建议使用RAID 1 或RAID10.
三: RAID与SQL Server
DB server physical disk design with separate RAID volumes for data, log, tempdb and backup files.
OS [要求很好的数据读写效率, 并且有很强的容错能力, 提供数据保护]
D: 做RAID10, 存储DB数据文件 [要求读的效率高, 写效率比较低一些, 容错能力要强,如果数据文件很大, 要求节约磁盘空间]
E: 做RAID1,
存储DB日志文件 [在DB运行过程中, 日志读写比较频繁, 需要很高的数据读写效率]
F: 做RAID10, 存储数据库的tempdb [存放临时数据库]
G(可选): 做RAID1, 数据备份,建议数据备份在远端
SSD硬盘:SSD的英文全称是Solid State Disk/Drive, 中文翻译为固态硬盘. 可以广泛应用于服务器、台式机、笔记本、移动设备、游戏机等, 加速启动, 提高性能, 同时降低功耗.
速度快(高I/O).
SQL Server搭配SSD硬盘可以取得很好的I/O性能
价格高,容量小,做RAID会进一步损失容量, 所以性价比不高. 对于不考虑价格的公司就另当别论.
技术还不是太成熟
针对不同的功能,建立不同的RAID架构可以提高数据效率和利用率.
(以上只是自己对RAID的一点浅显的理解,如有错误或者不当的地方,欢迎提出指正. 谢谢!)
—————————————————– 本人博客地址: 请多多支持,谢谢!———
Index对数据库性能有着举足轻重的作用。Index设计的优劣直接影响到DB执行的效率。所以在做DB Tuning时,一部分会从Index着手处理, Server也提供了很好的工具Database Engine Tuning Advisor,会给出一些建Index和优化方面的建议。
二:Index概述
这方面在各个博客论坛上面已经讲的比较多了,在此大致总结一下:
1. 数据表的基本结构
当建立一个新表时,系统将在磁盘中分配一段以8K为单位的连续空间;当第一个8K用完的时候, Server指针会自动分配8K的空间。每个8K空间成为一个数据页(Page),又称页面或者数据页面,并分配0-7的页号,每个文件的第0页记录引导 信息,叫文件头(File Header);每8个数据页(64K)的组合形成扩展区(Extent),成为扩展。全部的数据页的组合形成堆(Heap)。
2. 索引的基本概念
建立索引的目的就是提高数据检索效率,改善数据库工作性能,提高数据访问速度。系统表sysindexes存储Index的重要信息。以B-Tree为存储结构。
3. 数据表扫描与索引的使用
没有索引时,访问表的数据时按照Table Scan,平均效率比较低。
建立索引时,访问表的数据时按照Index Scan/Seek,平均效率很高。
4. 聚集索引和非聚集索引(Clustered Index and Non Clustered Index)
以B-Tree为存储结构存放的一组数据页
不同阶的节点包含指向另一个阶的数据页
子节点包含所有的键值
在sysindexes中可以找到索引的大小和内容分布
都会提高数据查询的效率
叶子节点存放什么:聚集索引存放实际的数据页;非聚集索引存放指针
注意:子叶层级存放的内容不一样。
5. 覆盖索引(Covering Index)
索引覆盖是指建索引的字段正好是覆盖查询条件中所涉及的字段,这里需要注意的是,必须是从第一个开始覆盖。
6. 死锁(DackLock)
三:性能简述(Performance)
1. Index碎片
1.1 查询碎片
sys.dm_db_index_physical_stats可以用来检测特定索引、表或索引视图的所有索引、数据库中所有索引或所有数据库中所有索引中的碎片。
avg_fragmentation_in_percent
逻辑碎片(索引中的无序页)的百分比
fragment_count
索引中的碎片(物理上连续的叶页)数量
avg_fragment_size_in_pages
索引中一个碎片的平均页数
1.2. 重建索引与重组索引(rebuild and reorganize)
无论何时对基础数据执行插入、更新或删除操作,SQL Server 数据库引擎都会自动维护索引。随着时间的推移,这些修改可能会导致索引中的信息分散在数据库中(含有碎片)。当索引包含的页中的逻辑排序(基于键值)与数 据文件中的物理排序不匹配时,就存在碎片。碎片非常多的索引可能会降低查询性能,导致应用程序响应缓慢。通过重新组织索引或重新生成索引来修复索引碎片, 提高性能。
ALTER INDEX IX_IndexName ON dbo.TableName REBUILD WITH (ONLINE=ON)
ALTER INDEX IX_IndexName ON dbo.TableName REORGANIZE
两种方法的区别:
重新组织索引是通过对叶页进行物理重新排序,使其与叶节点的逻辑顺序(从左到右)相匹配,从而对表或视图的聚集索引和非聚集索引的叶级别进行碎片整理。
重新生成索引将删除该索引并创建一个新索引。此过程中将删除碎片,通过使用指定的或现有的填充因子设置压缩页来回收磁盘空间,并在连续页中对索引行重新排序(根据需要分配新页)。这样可以减少获取所请求数据所需的页读取数,从而提高磁盘性能。
建议根据碎片程度,使用修复碎片的最佳方法:
2. 选择正确而的Index
2.1 主要的考量
以范围查询
常常需要排序的数据
2.2 次要考量
栏位长度要短
会影响所有的非聚集索引
非聚集索引的子也曾都包含所有聚集索引的键值
数据的类型
3.建立索引的方针
所有SQL语法的优先性
优先建立多个查询语法可以共通使用的索引
建立符合索引时,最佳的栏位顺序
与书中的索引一样,数据库中的索引使您可以快速找到表或索引视图中的特定信息。索引包含从表或视图中一个或多个列生成的键,以及映射到指定数据的存 储位置的指针。通过创建设计良好的索引以支持查询,可以显著提高数据库查询和应用程序的性能。索引可以减少为返回查询结果集而必须读取的数据量。索引还可 以强制表中的行具有唯一性,从而确保表数据的数据完整性。
设计良好的索引可以减少磁盘 I/O 操作,并且消耗的系统资源也较少,查询优化器也能够很好的利用索引,提高查询性能。
—————————————————– 本人博客地址: 请多多支持,谢谢!———
本人已经从事公司两套这类架构系统的开发工作啦!对于这套架构,我惊叹不已!BPS和CMS系统都是采用这套架构。但本人也同时渐渐发现了这套架构有诸多 不足之处,于是本人利用闲暇时光进一步改进了这套架构。新架构是基于“领域模型”的企业级应用架构模式,使用了 NHibernater+Spring.Net+MVC3的框架技术搭建。即便的是1.0版本,我也惊叹其几乎趋于完美了!这套架构是马丁.福勒关于“企 业级应用架构模式”理论的.Net实践。
架构基于三层模型,使用了接口技术、工厂模式、MVC模式、适配器模式等设计技巧,使架构支持高度扩展、易于修改、易于维护等诸多优点。
主要特性如下 :
1、三层结构
2、使用接口。降低依赖
3、改变了老架构部分类库职责不清。现在各类库职责清晰
4、改变了老架构,高度依赖外部组件的设计。现在基于“适配器模式”设计使用第三方组件,如:Log4.net
5、支持CodeSmith模版生成Hibernate领域类、配置文件等。
6、在老架构的基础上改进了业务层和数据层的依赖,使其彻底分离。
7、MVC层的Model分离。
8、增加了Facade类库作为表现层和业务层的隔离层。
重用代码:
NHibernater代码生成模版:
北风数据库:
所需环境:
VS2010、MVC3、.NetFramework4.0、Window XP以上、 NorthWind数据库
注意:因为我没有时间去写个什么文档,所以提供以下有助于理解的若干设计图:
  所谓“不想当架构师的程序员不是一个好的程序员”,那么如何进入软件架构师行列呢?软件架构师 Daniel Mohl 给出了。
下面这个列表是一个很好的起点,帮助你通向软件架构师之路:
你必须不断寻求改善。这里有一些很不错的书籍,可以提升你的技能:
每一到两年学习一门新的编程语言。
选择一个重点领域,尽可能对技术有一个高层次的理解。
针对你的重点领域,开始写博客,并继续扩大你的知识面,在你的重点领域中成为专家。
尝试不同的技术、编程语言、设计模式、架构等。
向你的听众介绍技术,并努力让每个听众都能理解。
阅读博客,浏览并参与到 Twitter 和 Google+ 中,收听播客、看杂志、参加用户组会议和技术会议,并在这些会议上发言。
每天安排时间学习新的东西,即使它只需 15 分钟。
有效利用一些被浪费掉的时间。
了解各种可用的工具,以帮助你更有效地做好本职工作。
了解大量不同项目中的不同架构。
了解不同的项目管理方法。
你所用的技术可以提供给业务多少价值?了解评估的方法。
在的第二个Step就是“Can you make a build in one step?”。从自己负责以来,一直就想把生成 APK的过程给自动化,因为通过Eclipse + ADT的做release的APK实在太繁琐,而且需要经常 做APK给QA测试。一直忙着做feature,今天得空,在网上搜索了一下,还真被我找到了,方 案如下:
Step1:下载安装Ant
这个直接follow ant官方的安装说明就可以了。
Step2:生成build.xml
在 project的根目录(有manifest的那个文件夹),运行下面这个命令:
android update project --path .
到此,运行
已经可以生成 build。但是native的code还是没有参与build的过程。
Step3:添加native code的支持
在根目录下添加customrules.xml,并添加如下语句:
&target name="-pre-build"&
&exec executable="${ndk.dir}/ndk-build" failonerror="true"/&
&target name="clean" depends="android_rules.clean"&
&exec executable="${ndk.dir}/ndk-build" failonerror="true"&
&arg value="clean"/&
&/project&
并且在local.properies指定ndk的位置,类似sdk.dir:
ndk.dir=/home/wangjiay/software/android-ndk-r8b
至此,我们已经可以自动build native code了。但是还是不能生产release build,因为我 们没有指定key store。
Step4:指定key store,支持release build
这个其实比较简单了,只要在local.properies中指定key store的一下设置就可以了:
key.store=&PathOfYourKeyStore&
key.alias=&...&
key.store.password=&...&
key.alias.password=&...&
就说到这里了,详情请移步或者联系我。
(转载请注明出处)
er 工具介绍
用MS做大型,基本上会牵涉到群集、复制、消息队列 、镜像、日志传送 、always On.
SQLer 作者有 多年 大型
一线 DBA工作 经验,深刻理解自动化运维、自动化工具重要型 。
自动化 工具必须 满足精细化管理,准确无误的定位到问题点。DBA工作本身是未雨绸缪,要走在前面,走的快,还不累趴下,自动化工具必须到位。
数据库字符集 报警
需要重启的 sql服务器 默认阀值是90
数据库增加设置报警
数据库所有者报警
数据库日志报警
Repliaction Error 报警
根据 邮件提示信息查看 error sql
练一技,修百艺,而成于自然.

我要回帖

更多关于 string类型 的文章

 

随机推荐