[转载]初试jQuery EasyUI

mikel阅读(992)

[转载]初试jQuery EasyUI – GWPBrian – 博客园.

想必关注JQuery的同学们对JQuery EasyUI已经有所耳闻了,目前已经更新到1.0.5版本,风格与EXTJS有点相似,可以很好的满足开发人员对UI的需求。

jQuery EasyUI

jQuery EasyUI是一组基于jQuery的UI插件集合,而jQuery EasyUI的目标就是帮助web开发者更轻松的打造出功能丰富并且美观的UI界面。开发者不需要编写复杂的JavaScript,也不需要对css样式 有深入的了解,开发者需要了解的只有一些简单的html标签。

jQuery EasyUI为我们提供了大多数UI控件的使用,如:accordion,combobox,menu,dialog,tabs,tree,window等等。

OK,下面就开始我们的初探之旅。

jQuery EasyUI—Accordion
手风琴效果,大家应该很熟悉。

基本代码:

代码

<html xmlns=”http://www.w3.org/1999/xhtml”>
<head>
<title>Accordion</title>
<script src=”../jquery-1.4.2.min.js” type=”text/JavaScript></script>
<script src=”../jquery.easyui.min.js” type=”text/javascript”></script>

<link href=”../themes/default/easyui.css” rel=”stylesheet” type=”text/css” />
<link href=”../themes/icon.css” rel=”stylesheet” type=”text/css” />

<script type=”text/javascript”></script>
</head>
<body>
<div style=”overflow:auto;width:600px;height:300px;padding:10px;border:1px solid #ccc;”>
<div id=”aa” class=”easyui-accordion” fit=”true” style=”width:300px;height:200px;”>
<div title=”Title1″ style=”overflow:auto;padding:10px;”>
<h3>Accordion1</h3>
</div>
<div title=”Title2″ style=”padding:10px;”>
<h3>Accordion2</h3>
</div>
<div title=”Title3″>
<h3>Accordion3</h3>
</div>
</div>
</div>
</body>
</html>

代码非常简单,只需要简单的html就可以实现。这里最重要的就是首先要引用jquery-1.4.2.min.js和jquery.easyui.min.js。

效果:

由于只是简单的html,所以我们可以通过js轻松的对Accordion进行操控,控制大小,位置等等。

jQuery EasyUI—DataGrid

从名字就可以知道这是个数据的绑定和显示控件。

基本代码:

代码

<html xmlns=”http://www.w3.org/1999/xhtml”>
<head>
<title>DataGrid</title>
<meta http-equiv=”Content-Type” content=”text/html; charset=UTF-8″>
<script src=”../jquery-1.4.2.min.js” type=”text/javascript”></script>
<script src=”../jquery.easyui.min.js” type=”text/javascript”></script>

<link href=”../themes/default/easyui.css” rel=”stylesheet” type=”text/css” />
<link href=”../themes/icon.css” rel=”stylesheet” type=”text/css” />

<script type=”text/javascript”>
$(
function() {
$(
#test).datagrid({
title:
jQuery EasyUI—DataGrid,
iconCls:
icon-save,
width:
500,
height:
350,
nowrap:
false,
striped:
true,
url:
../Data/datagrid_data.json,
sortName:
ID,
sortOrder:
desc,
idField:
ID,
frozenColumns: [[
{ field:
ck, checkbox: true },
{ title:
ID, field: ID, width: 80, sortable: true }
]],
columns: [[
{ title:
基本信息, colspan: 2 },
{ field:
opt, title: 操作, width: 100, align: center, rowspan: 2,
formatter:
function(value, rec) {
return <span style=”color:red”>编辑 删除</span>;
}
}
], [
{ field:
name, title: Name, width: 120 },
{ field:
addr, title: Address, width: 120, rowspan: 2, sortable: true }
]],
pagination:
true,
rownumbers:
true,
singleSelect:
false,
toolbar: [{
text:
添加,
iconCls:
icon-add,
handler:
function() {
alert(
添加数据)
}
},
, {
text:
保存,
iconCls:
icon-save,
handler:
function() {
alert(
保存数据)
}
}]
});
});

</script>
</head>
<body>
<table id=”test”></table>
</body>
</html>

这里我们从datagrid_data.json中获取数据,代码的编写风格同EXTIS十分相似。ExtJS开发实践

效果:

jQuery EasyUI—Dialog

网页窗体效果。

基本代码:

代码

<html xmlns=”http://www.w3.org/1999/xhtml”>
<head>
<title>Dialog</title>

<script src=”../jquery-1.4.2.min.js” type=”text/javascript”></script>
<script src=”../jquery.easyui.min.js” type=”text/javascript”></script>

<link href=”../themes/default/easyui.css” rel=”stylesheet” type=”text/css” />
<link href=”../themes/icon.css” rel=”stylesheet” type=”text/css” />

<script>
$(
function(){
$(
#dd).dialog({
toolbar:[{
text:
添加,
iconCls:
icon-add,
handler:
function(){
alert(
添加数据)
}
},
,{
text:
保存,
iconCls:
icon-save,
handler:
function(){
alert(
保存数据)
}
}],
buttons:[{
text:
提交,
iconCls:
icon-ok,
handler:
function(){
alert(
提交数据);
}
},{
text:
取消,
handler:
function(){
$(
#dd).dialog(取消);
}
}]
});
});

</script>
</head>
<body>
<div id=”dd” style=”padding:5px;width:400px;height:200px;”>
<p>jQuery EasyUI—Dialog</p>
</div>
</body>
</html>

效果:

jQuery EasyUI—Tabs

无论是网站还是管理软件,我们越来越多的使用Tabs,EasyUI自然也进行了支持。

基本代码:

代码

<html xmlns=”http://www.w3.org/1999/xhtml”>
<head>
<title>Tabs</title>

<script src=”../jquery-1.4.2.min.js” type=”text/javascript”></script>
<script src=”../jquery.easyui.min.js” type=”text/javascript”></script>

<link href=”../themes/default/easyui.css” rel=”stylesheet” type=”text/css” />
<link href=”../themes/icon.css” rel=”stylesheet” type=”text/css” />
</head>
<body>
<div id=”tt” class=”easyui-tabs” style=”width:500px;height:250px;”>
<div title=”Tab1″ style=”padding:20px;display:none;”>
<h1>Tab1 Content</h1>
</div>

<div title=”Tab5″ closable=”true” style=”padding:10px;display:none;”>
<div class=”easyui-tabs” fit=”true” plain=”true” style=”height:100px;width:300px;”>
<div title=”Title1″>Content 1</div>
<div title=”Title2″>Content 2</div>
<div title=”Title3″>Content 3</div>
</div>
</div>
</div>
</body>
</html>

效果:

jQuery EasyUI—Messager

信息提示控件,可以很好的进行数据的提示,推荐。

基本代码:

代码

<html xmlns=”http://www.w3.org/1999/xhtml”>
<head>
<title>Messager</title>
<script src=”../jquery-1.4.2.min.js” type=”text/javascript”></script>
<script src=”../jquery.easyui.min.js” type=”text/javascript”></script>

<link href=”../themes/default/easyui.css” rel=”stylesheet” type=”text/css” />
<link href=”../themes/icon.css” rel=”stylesheet” type=”text/css” />
<script>
function show1() {
$.messager.show({
title:
提示信息1,
msg:
信息1,
showType:
show
});
}
function show2() {
$.messager.show({
title:
提示信息2,
msg:
信息5分钟后消失.,
timeout:
5000,
showType:
slide
});
}
function show3() {
$.messager.show({
title:
渐进显示信息3,
msg:
渐进显示信息3,
timeout:
0,
showType:
fade
});
}
</script>
</head>
<body>
<h1>信息提示</h1>
<div>
<a href=”javascript:void(0)” onclick=”show1()”>显示</a> |
<a href=”#” onclick=”show2()”>滑动</a> |
<a href=”#” onclick=”show3()”>渐进显示</a> |
</div>
</body>
</html>

效果:

页面左下角信息提示

jQuery EasyUI—ValidateBox

数据验证控件,可以很好的对表单数据进行验证。

基本代码:

代码

<html xmlns=”http://www.w3.org/1999/xhtml”>
<head>
<title>ValidateBox</title>

<script src=”../jquery-1.4.2.min.js” type=”text/javascript”></script>
<script src=”../jquery.easyui.min.js” type=”text/javascript”></script>

<link href=”../themes/default/easyui.css” rel=”stylesheet” type=”text/css” />
<link href=”../themes/icon.css” rel=”stylesheet” type=”text/css” />
</head>
<body>
<div>
<table>
<tr>
<td>姓名:</td>
<td><input class=”easyui-validatebox” required=”true” validType=”length[1,3]”></td>
</tr>
<tr>
<td>电子邮件:</td>
<td><input class=”easyui-validatebox” required=”true” validType=”email”></td>
</tr>
<tr>
<td>URL:</td>
<td><input class=”easyui-validatebox” required=”true” validType=”url”></td>
</tr>
<tr>
<td>说明:</td>
<td><textarea class=”easyui-validatebox” required=”true” style=”height:100px;”></textarea></td>
</tr>
</table>
</div>
</body>
</html>

不需要写任何函数,只需对要验证的控件required=”true” validType=”url”就可以。

效果:

jQuery EasyUI—LayOut

页面布局,可以将整个页面划分成几个区域。类似ExtJS中的Border布局。

基本代码:

代码

<html xmlns=”http://www.w3.org/1999/xhtml”>
<head>
<title>LayOut</title>
<script src=”../jquery-1.4.2.min.js” type=”text/javascript”></script>
<script src=”../jquery.easyui.min.js” type=”text/javascript”></script>

<link href=”../themes/default/easyui.css” rel=”stylesheet” type=”text/css” />
<link href=”../themes/icon.css” rel=”stylesheet” type=”text/css” />
</head>
<body>
<div class=”easyui-layout” style=”width:600px;height:400px;”>
<div region=”north” border=”false” style=”overflow:hidden;height:60px;background:#A4BED4;”>
<h2>Border布局</h2>
</div>
<div region=”south” split=”true” style=”height:50px;background:#efefef;”>
</div>
<div region=”east” icon=”icon-reload” title=”Menu2″ split=”true” style=”width:180px;”>
</div>
<div region=”west” split=”true” title=”Menu1″ style=”width:100px;”>
</div>
<div region=”center” title=”Main Form” style=”background:#eee;”>
</div>
</div>
</body>
</html>

效果:

jQuery EasyUI—换肤

jQuery EasyUI使用了统一的CSS样式,在修改方面也很是方便:

如图所示,对于每一个控件,都有专有的CSS。相应对其修改就可以,只需简单的了解CSS即可。

小结:jQuery EasyUI的体验就到这里,还有一些控件这里没有介绍,比如:combobox,splitbutton等等。

官方网站http://jquery-easyui.wikidot.com/start

下载地址:http://jquery-easyui.wikidot.com/download

本文代码:/Files/gaoweipeng/EasyUITest.rar

[转载]Visual Studio自带报表Report Viewer使用体验

mikel阅读(1025)

[转载]Visual Studio自带报表Report Viewer使用体验

概述

我的Visual Studio是2010,2005和2008也可以直接使用微软自带的报表工具开发报表。如果购买了SQL Server 2005企业版或者SQL Server 2008 R2,可以考虑使用Reporting Service,Reporting Service包括专门的报表工具,如Report Builder3.0,可以在微软网站上下载,使用Reporting Service开发需要专门的服务器存放报表文件和处理报表数据,其他应用程序仅是呈现报表而已。另外也可以考虑使用本地模式来开发和使用Report Viewer呈现报表,本地模式简单易用、方便灵活,报表寄存在应用程序中运行,本地模式可以视具体场景,使用Web和WinForm方式开发。

环境准备

Report Viewer是Visual Studio 2010自带的报表呈现控件,是微软自带的.Net Ajax控件之一,所以使用Report Viewer之前需要先添加ScriptManager和做好Web.config的相关配置,运行.Net Ajax控件需要预先安装.Net Ajax的插件,具体内容参考msdn的网站。在安装.Net Ajax插件之后,新建项目时可以选择新建Web Application,Web.config中的相关配置默认是支持.Net Ajax的。
.Net Ajax的插件下载地址请参考:
ASPAJAXExtSetup.msi:http://download.microsoft.com/download/5/4/6/5462bcbd-e738-45fa-84ca-fa02b0c4e1c2/ASPAJAXExtSetup.msi
ASPAJAXSourceCode.msi:http://download.microsoft.com/download/6/d/6/6d6c7c47-b9ff-4934-bb03-8a45b8418d35/ASPAJAXSourceCode.msi
AjaxControlToolkit:http://ajax.ASP.NET/downloads/default.aspx?tabid=47
or http://www.codeplex.com/AtlasControlToolkit/Release/ProjectReleases.aspx?ReleaseId=1425

制作第一个报表

创建好Web项目之后,选择添加新项,可以选择添加”报表”或者”报表向导”来生成报表文件,报表数据源可以选择数据源(使用DataTable)和业务对象(通过指定特定业务类特定方法获取List<>类型的数据对象列表)。
创建报表文件(.rdlc文件的创建过程)和通过Report Viewer呈现报表数据的详细过程请参考msdn:http://msdn.microsoft.com/zh-cn/library/ms251671.aspx

注意事项和工具

注意事项
1.报表文件需要存放在站点根目录中,放在文件夹中会报异常,在Reporting Service已存在类似的问题。
2.Report Viewer控件不支持URL路径中包含中文字符,如果路径存在中文字符,则会出现无法预知的JS错误。
3.VS2010传递参数时,不需要添加@字符,记得在某个版本的Reporting Service传递参数时需要添加@字符

非常有用的工具
1.打开报表文件之后,可以通过视图->报表数据菜单打开报表的相关信息窗口
2.工具栏中包含报表字样的工具栏对于格式报表非常有用。

示例代码:ReportDemo_ReportViewer.zip

作者:HorsonJin
出处:http://www.cnblogs.com/HorsonJin
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

[转载]XML to tree XML 树

mikel阅读(945)

[转载]XML to tree XML 树 – 柴哥 – 博客园.

前面发了一个 html to tree 再发一个 xml to tree

以下为代码:

/*
版权所有:版权所有(C) 2009
系统名称:树型控件
文件名称:xml2tree.js
作  者:DEVIN
完成日期:2009-12-22
压缩方式:jspacker
主    页:http://www.chaige.net
*/
var XML2Tree = function (ini) {
var $ = document, _this = this, $$ = 'documentElement';
this.getTitle = ini.getTitle || String;
this.click = ini.click || String;
this.box = ini.shell.big ? $.getElementById(ini.shell) : ini.shell;
this.edit = ini.edit ? true : false;
this.color = ini.color ? ini.color : '#v';
this.row = ini.row ? ini.row : '';
this.box.innerHTML = '
<p style="margin-left: 10px;"><img src="/load3.gif" alt="" /> loading...</p>
';
this.getValue = ini.getValue || String;
/* 异步下载Xml (chrome不能创建XMLDOC,使用Ajax构造) */
this.xml = !!$.all ? (new ActiveXObject('Microsoft.XMLDOM')) : (new XMLHttpRequest());
this.xml.onreadystatechange = function () {
if (_this.xml.readyState == 4) {
_this.box.innerHTML = '';
_this.addSub($.all ? _this.xml[$$] : _this.xml.responseXML[$$], _this.box)
}
}
if (!!$.all) {
this.xml.async = true; this.xml.load(ini.url)
}
else {
this.xml.open("GET", ini.url, true); this.xml.send(null)
};
}
/*
共享接口
*/
XML2Tree.prototype = {
folder: function (node) {
var UI = function (_) { return document.createElement(_) }
, caption = UI('DT'), shell = UI('DL'), body = UI('DD'), $ = XML2Tree.ini;
shell.appendChild(caption);
shell.appendChild(body);
var folderIco = this.selectIco($.folder, $.node, XML2Tree.hasChild(node));
caption.innerHTML = (this.edit ? '<label>' + this.expand(this.getValue.call(node)) + '</label>' : '')
+ this.getLineIco(node) + this.getHasIco(node)
+ folderIco + '<a href="javascript://"><span>'
+ this.getTitle.call(node) + '</span></a>';
caption.mapNode = node;
var co = this.color;
caption.onmouseover = function () {
this.style.backgroundColor = co;
}
caption.onmouseout = function () {
this.style.backgroundColor = '';
}
return { 'shell': shell, 'caption': caption };
},
addSub: function (node, shell) {
if (node == null) return;
var nodes = node.childNodes, _tree = this;
for (var i = 0; i &lt; nodes.length; i++) {
if (nodes[i].nodeType != 1) continue; /* for FF find textNode */
var _ = this.folder(nodes[i]);
shell.appendChild(_.shell);
_.caption.onclick = function (e) {
var $ = XML2Tree, childShell = $.next(this);
if (this.mapNode) {
var wrap = this.parentNode.getElementsByTagName('DD')[0];
if (XML2Tree.hasChild(this.mapNode)) {
_tree.addSub(this.mapNode, wrap);
$.toggle(this, true)
};
this.mapNode = null;
} else {
if (!childShell) return;
if (XML2Tree.hasChild(childShell)) {
var hide = childShell.style.display == 'none';
childShell.style.display = hide ? '' : 'none';
$.toggle(this, hide);
};
};
e = e || window.event;
var sE = e.srcElement || e.target;
if (sE.tagName.toUpperCase() == 'SPAN') {
var title = sE.innerHTML;
if (!XML2Tree.hasChild(childShell)) {
_tree.click.call(sE, title, false); /* 叶节点单击, this 重置为 span */
} else {
_tree.click.call(childShell, title, true); /* 文件夹节点单击, this 重置为 子节点的壳DD */
}
}
};
};
},
getLineIco: function (node) {
var icos = [], root = node.ownerDocument;
if (!root) return null;
node = node.parentNode;
while (node.parentNode != root) {
var $ = XML2Tree, img = this.selectIco($.ini.line, $.ini.empty, !!$.next(node));
icos = [img].concat(icos);
node = node.parentNode;
}
return icos.join('');
},
getHasIco: function (node) {
var last = !!XML2Tree.next(node), $ = XML2Tree.ini;
return XML2Tree.hasChild(node) ?
this.selectIco($.plus, $.plusBottom, last) :
this.selectIco($.join, $.joinBottom, last)
},
expand: function (i) {
var r = this.row, s = [];
for (var k = 0; k &lt; r.length; k++) {
var url = r[k][0].replace('{0}', i);
s.push('<a href="' + url + '">' + r[k][1] + '</a>' + (k == r.length - 1 ? '' : ' | '));
}
return s.join('');
},
selectIco: function (_1, _2, bool) {
return '<img src="' + (bool ? _1 : _2) + '" alt="" align="absimddle" />'
}
};
/*
静态接口
*/
XML2Tree.ini = {
root: 'ui/base.gif',
folder: 'ui/folder.gif',
folderOpen: 'ui/folderopen.gif',
node: 'ui/page.gif',
empty: 'ui/empty.gif',
line: 'ui/line.gif',
join: 'ui/join.gif',
joinBottom: 'ui/joinbottom.gif',
plus: 'ui/plus.gif',
plusBottom: 'ui/plusbottom.gif',
minus: 'ui/minus.gif',
minusBottom: 'ui/minusbottom.gif',
nlPlus: 'ui/nolines_plus.gif',
nlMinus: 'ui/nolines_minus.gif'
};
/* 图标预载 */
XML2Tree.prevLoad = function () {
for (var key in this.ini) {
var $ = new Image();
$.src = this.ini[key];
}
};
XML2Tree.next = function (node) {
var $ = node, _ = 'nextSibling';
for ($ = $[_]; $; $ = $[_]) {
if ($.nodeType == 1) { return $ }
};
return null;
};
XML2Tree.hasChild = function (node) {
var $ = node.childNodes;
for (var i = 0; i &lt; $.length; i++)
if ($[i].nodeType == 1) return true;
return false;
};
XML2Tree.toggle = function (node, isOpen) {
var imgs = node.getElementsByTagName('IMG')
, f = imgs.length - 1, $ = XML2Tree.ini;
imgs[f].src = isOpen ? $.folderOpen : $.folder;
if (this.next(node.parentNode)) {
imgs[f - 1].src = isOpen ? $.minus : $.plus;
} else {
imgs[f - 1].src = isOpen ? $.minusBottom : $.plusBottom;
}
};
/*
生成实例树
参数:
url: xml 地址
shell: 树容器
loading: 下载中的效果html
getTitle: 标题来源属性操作 this 重置为 xml node
chick: 节点或者叶节点的单击事件(可得到参数title,isFolder与重置后的this)
*/
XML2Tree.prevLoad();

下载地址

点我下载

~!~~~ 民工的命

原创代码,转载请联系 柴哥!!!

[转载]android之远程服务的调用

mikel阅读(956)

[转载]android之远程服务的调用 – jack.li – 博客园.

何为Android中的RPC模式?

相信有的读者还不是很理解,这里和大家做一个简单的介绍.RPC模式:Remote Procedure Call即远程进程调用.

Android操作系统中,各个组件运行在各自的进程中,它们相互之间是不能访问的.但是在程序之间不可避免的要传递一些对象、参数等,这就需要 实现进程间的相互通信.android采用了一种轻量级的实现方式—>RPC模式来完成进程之间的通信.通过定义接口语言(android interface definition language——AIDL)来完成进程之间相互访问的代码.例如:#1你需要在Activity中访问Service中的某一个方法,就可以采用这种方式来实现了.

AIDL语言是android的一种接口描述语言,编译器可以通过AIDL文件生成一段代码(注意:这段代码是自动生成的),通过预先定义的接口达到两个进程内部通信进程的目的.

详细的说下#1例子是什么个意思:如果需要在一个Activity中访问另一个Service中的某个对象,需要先将对象转化成AIDL可识别的参数(可能是多个参数),然后使用AIDL来传递这些参数,在消息的接收端,使用这些参数封装成自己需要的对象.

总的来说:android中的AIDL RPC是通过接口来实现的,类似Windows中的COM或者Corba,但它是轻量级的,客户端和被调用实现之间是通过代理模式实现的,代理类和被代理类实现同一个Ibinder接口.

接下来我就一个具体的案例和大家讲讲RPC模式的具体实现步骤:

第一步:毫无疑问,是创建AIDL接口文件.第一个问题来了,怎样创建AIDL文件?

其实有这个疑问很正常,我上网搜了一些资料,问题解决.

在当前的Activity所在的Package右击,new一个file,取名BookInfo.aidl.该文件中的具体内容如下:

package com.ceo.remoteservice.activity;
//BookInfo的接口文件
interface BookInfo {
   void setName(String name);
   void setPrice(float price);
   void setPublish(String publish);
    
   //显示book信息
   String display();
}

该接口文件中主要包括:当前的package name,接口中的方法的声明.编写完成后ctrl+s,可以发现在gen文件夹下自动生成了BookInfo.java文件.如下图所示:

需要注意的是该文件是系统自动生成的,尽量不要改动里面的代码,以免带来不必要的错误.

第二步:声明一个类public class BookInfoImpl extends BookInfo.Stub

private float price;
private String name,publish;
    
@Override
public String display() throws RemoteException {
    return "书名:" + name + "价格:" + price + "出版社:" + publish;
}
    
@Override
public void setName(String name) throws RemoteException {
    this.name = name;
}
    
@Override
public void setPrice(float price) throws RemoteException {
    this.price = price;
}
    
@Override
public void setPublish(String publish) throws RemoteException {
    this.publish = publish;
}

该文件下实现的这些方法都是在接口文件中定义的.

第三步:向客户端暴露我们的接口,定义一个远程服务的类public class RemoteService extends Service

private Stub bookifo = new BookInfoImpl();

在onBind方法里面直接return bookifo;

第四步:主要就是MainActivity的编写了

01 public class MainActivity extends Activity {
02 //声明接口
03 private BookInfo bookinfo;
04 //声明Button
05 private Button btnShow;
06 //最重要的一点就是----->实例化ServiceConnection
07 private ServiceConnection conn = new ServiceConnection(){
08
09 @Override
10 public synchronized void onServiceConnected(ComponentName name, IBinder service) {
11 //--->获得BookInfo的接口
12 bookinfo = BookInfo.Stub.asInterface(service);
13 if(bookinfo != null) {
14 try {
15 bookinfo.setName("android开发之远程服务的调用--jack.li");
16 bookinfo.setPrice(99.99f);
17 bookinfo.setPublish("苏州xxx软件有限公司");
18 String msg = bookinfo.display();
19
20 //Toast显示
21 Toast.makeText(MainActivity.this, msg, 1).show();
22 } catch (RemoteException e) {
23 e.printStackTrace();
24 }
25 }
26 }
27
28 @Override
29 public void onServiceDisconnected(ComponentName name) {
30
31 }
32
33 };
34
35 @Override
36 public void onCreate(Bundle savedInstanceState) {
37 super.onCreate(savedInstanceState);
38 setContentView(R.layout.main);
39
40 btnShow = (Button)findViewById(R.id.btnShow);
41 btnShow.setOnClickListener(new View.OnClickListener() {
42
43 @Override
44 public void onClick(View v) {
45 Intent intent = new Intent();
46 intent.setAction("com.ceo.remoteservice.activity.action.MY_REMOTE_SERVICE");
47 bindService(intent, conn, Service.BIND_AUTO_CREATE);
48 }
49 });
50 }
51 }

最后运行结果如图:


至此,所有关于Android中的RPC模式、AIDL接口语言、以及怎样在Activity中访问另一个Service中的对象就全部介绍完毕了.

有需要整个项目源代码的留下邮箱,或直接加我qq,我会发给大家.

2011.10.20.pm

jack.li

QQ:523072842
Email:523072842@qq.com

[转载]JavaScript中模拟 Dictionary键值对

mikel阅读(772)

[转载]JavaScript中模拟 Dictionary键值对 – BirchLee – 博客园.

原文发表在:http://www.birchlee.com/post/2011/10/19/27.aspx

JavaScript常常遇到一些键值对,以前用二维数组实现,今天索性模拟了一下Dictionary帮助类。

原理:创建一个对象,包含两个数组,键数组和值数组,调用JavaScript Array对象的方法。

W3C参考地址:http://www.w3school.com.cn/js/jsref_obj_array.asp

BuildDictionary()方法用于创建一个包含两个数组的Dictionary对象

AddItem方法 调用JavaScript的 Array对象的push方法,用于将key,value追加到相应的数组。

UpdateItem方法用于更改相应的value

DeleteItem方法 调用JavaScript的Array对象的Splice方法用于删除元素,第一个参数是需要删除的元素的index,第一个参数代表删除的个数。

GetKeyStr用于得到Keys数组拼接后的字符串

GetValueStr用于得到Values数组拼接后的字符串

共包含五个方法:

/*创建Dictionary*/
function BuildDictionary() {
dic = new Object();
dic.Keys = new Array(); //键数组
dic.Values = new Array(); //值数组
return dic;
}

/*添加 key,value*/
function AddItem(key, value, dic) {
var keyCount = dic.Keys.length;
if (keyCount > 0) {
var flag = true;
for (var i = 0; i < keyCount; i++) {
if (dic.Keys[i] == key) {
flag = false;
break; //如果存在则不添加
}
}
if (flag) {
dic.Keys.push(key)
dic.Values.push(value);
}
}
else {
dic.Keys.push(key)
dic.Values.push(value);
}
return dic;
}
/*更改key,value*/
function UpdateItem(key, value, dic) {
var keyCount = dic.Keys.length;
if (keyCount > 0) {
var flag = -1;
for (var i = 0; i < keyCount; i++) {
if (dic.Keys[i] == key) {
flag = i;
break; //查找相应的index
}
}
if (flag > -1) {
dic.Keys[flag] = key;
dic.Values[flag] = value;
}
return dic;
}
else {
return dic;
}
}
/*移除key value*/
function DeleteItem(key, dic) {
var keyCount = dic.Keys.length;
if (keyCount > 0) {
var flag = -1;
for (var i = 0; i < keyCount; i++) {
if (dic.Keys[i] == key) {
flag = i;
break; //查找相应的index
}
}
if (flag > -1) {
dic.Keys.splice(flag,1); //移除
dic.Values.splice(flag, 1); //移除
}
return dic;
}
else {
return dic;
}
}

/*获取Key字符串,用符号拼接*/
function GetKeyStr(separator,dic)
{
var keyCount=dic.Keys.length;
if(keyCount>0)
{
return dic.Keys.join(separator);
}
else
{
return ”;
}
}
/*获取Value字符串,用符号拼接*/
function GetValueStr(separator,dic)
{
var keyCount=dic.Keys.length;
if(keyCount>0)
{
return dic.Values.join(separator);
}
else
{
return ”;
}
}

使用方法:创建一个全局的变量,操作这个全局变量就可以使用了。

在此抛砖引玉了

[转载]再谈C#的装箱和拆箱

mikel阅读(1033)

[转载]再谈C#的装箱和拆箱 – 玉开 – 博客园.

上一篇写了一下装箱拆箱的定义和IL分析,这一篇我们看下使用泛型和不使用泛型引发装箱拆箱的情况

1. 使用非泛型集合时引发的装箱和拆箱操作

看下面的一段代码:

1 var array = new ArrayList();
2 array.Add(1);
3 array.Add(2);
4
5 foreach (int value in array)
6 {
7 Console.WriteLine(“value is {0}”,value);
8 }

代码声明了一个ArrayList对象,向ArrayList中添加两个数字1,2;然后使用foreach将ArrayList中的元素打印到控制台。

在这个过程中会发生两次装箱操作和两次拆箱操作,在向ArrayList中添加int类型元素时会发生装箱,在使用foreach枚举 ArrayList中的int类型元素时会发生拆箱操作,将object类型转换成int类型,在执行到Console.WriteLine时,还会执行 两次的装箱操作;这一段代码执行了6次的装箱和拆箱操作;如果ArrayList的元素个数很多,执行装箱拆箱的操作会更多。

你可以通过使用ILSpy之类的工具查看IL代码的box,unbox指令查看装箱和拆箱的过程

2. 使用泛型集合的情况

请看如下代码:

var list = new List<int>();
list.Add(1);
list.Add(2);
foreach (int value in list)
{
Console.WriteLine("value is {0}", value);
}

代码和1中的代码的差别在于集合的类型使用了泛型的List,而非ArrayList;我们同样可以通过查看IL代码查看装箱拆箱的情况,上述代码只会在Console.WriteLine()方法时执行2次装箱操作,不需要拆箱操作。

可以看出泛型可以避免装箱拆箱带来的不必要的性能消耗;当然泛型的好处不止于此,泛型还可以增加程序的可读性,使程序更容易被复用等等。

本文使用的C#代码如下:

01 using System;
02 using System.Collections;
03 using System.Collections.Generic;
04
05 namespace boxOrUnbox
06 {
07 class Program
08 {
09 static void Main(string[] args)
10 {
11 //do nothing
12 }
13
14 static void Box()
15 {
16 object objValue = 9;
17 }
18
19 static void Unbox()
20 {
21 object objValue = 4;
22 int value = (int)objValue;
23 }
24
25 static void LookatArrayList()
26 {
27 var array = new ArrayList();
28 array.Add(1);
29 array.Add(2);
30
31 foreach (int value in array)
32 {
33 Console.WriteLine("value is {0}", value);
34 }
35 }
36
37 static void LookatGenericList()
38 {
39 var list = new List<int>();
40 list.Add(1);
41 list.Add(2);
42
43 foreach (int value in list)
44 {
45 Console.WriteLine("value is {0}", value);
46 }
47 }
48 }
49 }

C#的IL代码如下:

001 .class private auto ansi beforefieldinit boxOrUnbox.Program
002 extends [mscorlib]System.Object
003 {
004 // Methods
005 .method private hidebysig static
006 void Main (
007 string[] args
008 ) cil managed
009 {
010 // Method begins at RVA 0x2050
011 // Code size 2 (0x2)
012 .maxstack 8
013 .entrypoint
014
015 IL_0000: nop
016 IL_0001: ret
017 } // end of method Program::Main
018
019 .method private hidebysig static
020 void Box () cil managed
021 {
022 // Method begins at RVA 0x2054
023 // Code size 10 (0xa)
024 .maxstack 1
025 .locals init (
026 [0] object objValue
027 )
028
029 IL_0000: nop
030 IL_0001: ldc.i4.s 9
031 IL_0003: box [mscorlib]System.Int32
032 IL_0008: stloc.0
033 IL_0009: ret
034 } // end of method Program::Box
035
036 .method private hidebysig static
037 void Unbox () cil managed
038 {
039 // Method begins at RVA 0x206c
040 // Code size 16 (0x10)
041 .maxstack 1
042 .locals init (
043 [0] object objValue,
044 [1] int32 'value'
045 )
046
047 IL_0000: nop
048 IL_0001: ldc.i4.4
049 IL_0002: box [mscorlib]System.Int32
050 IL_0007: stloc.0
051 IL_0008: ldloc.0
052 IL_0009: unbox.any [mscorlib]System.Int32
053 IL_000e: stloc.1
054 IL_000f: ret
055 } // end of method Program::Unbox
056
057 .method private hidebysig static
058 void LookatArrayList () cil managed
059 {
060 // Method begins at RVA 0x2088
061 // Code size 114 (0x72)
062 .maxstack 2
063 .locals init (
064 [0] class [mscorlib]System.Collections.ArrayList 'array',
065 [1] int32 'value',
066 [2] class [mscorlib]System.Collections.IEnumerator CS$5$0000,
067 [3] bool CS$4$0001,
068 [4] class [mscorlib]System.IDisposable CS$0$0002
069 )
070
071 IL_0000: nop
072 IL_0001: newobj instance void [mscorlib]System.Collections.ArrayList::.ctor()
073 IL_0006: stloc.0
074 IL_0007: ldloc.0
075 IL_0008: ldc.i4.1
076 IL_0009: box [mscorlib]System.Int32
077 IL_000e: callvirt instance int32 [mscorlib]System.Collections.ArrayList::Add(object)
078 IL_0013: pop
079 IL_0014: ldloc.0
080 IL_0015: ldc.i4.2
081 IL_0016: box [mscorlib]System.Int32
082 IL_001b: callvirt instance int32 [mscorlib]System.Collections.ArrayList::Add(object)
083 IL_0020: pop
084 IL_0021: nop
085 IL_0022: ldloc.0
086 IL_0023: callvirt instance class [mscorlib]System.Collections.IEnumerator [mscorlib]System.Collections.ArrayList::GetEnumerator()
087 IL_0028: stloc.2
088 .try
089 {
090 IL_0029: br.s IL_004a
091 // loop start (head: IL_004a)
092 IL_002b: ldloc.2
093 IL_002c: callvirt instance object [mscorlib]System.Collections.IEnumerator::get_Current()
094 IL_0031: unbox.any [mscorlib]System.Int32
095 IL_0036: stloc.1
096 IL_0037: nop
097 IL_0038: ldstr "value is {0}"
098 IL_003d: ldloc.1
099 IL_003e: box [mscorlib]System.Int32
100 IL_0043: call void [mscorlib]System.Console::WriteLine(string, object)
101 IL_0048: nop
102 IL_0049: nop
103
104 IL_004a: ldloc.2
105 IL_004b: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext()
106 IL_0050: stloc.3
107 IL_0051: ldloc.3
108 IL_0052: brtrue.s IL_002b
109 // end loop
110
111 IL_0054: leave.s IL_0070
112 } // end .try
113 finally
114 {
115 IL_0056: ldloc.2
116 IL_0057: isinst [mscorlib]System.IDisposable
117 IL_005c: stloc.s CS$0$0002
118 IL_005e: ldloc.s CS$0$0002
119 IL_0060: ldnull
120 IL_0061: ceq
121 IL_0063: stloc.3
122 IL_0064: ldloc.3
123 IL_0065: brtrue.s IL_006f
124
125 IL_0067: ldloc.s CS$0$0002
126 IL_0069: callvirt instance void [mscorlib]System.IDisposable::Dispose()
127 IL_006e: nop
128
129 IL_006f: endfinally
130 } // end handler
131
132 IL_0070: nop
133 IL_0071: ret
134 } // end of method Program::LookatArrayList
135
136 .method private hidebysig static
137 void LookatGenericList () cil managed
138 {
139 // Method begins at RVA 0x2118
140 // Code size 90 (0x5a)
141 .maxstack 2
142 .locals init (
143 [0] class [mscorlib]System.Collections.Generic.List`1<int32> list,
144 [1] int32 'value',
145 [2] valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32> CS$5$0000,
146 [3] bool CS$4$0001
147 )
148
149 IL_0000: nop
150 IL_0001: newobj instance void class [mscorlib]System.Collections.Generic.List`1<int32>::.ctor()
151 IL_0006: stloc.0
152 IL_0007: ldloc.0
153 IL_0008: ldc.i4.1
154 IL_0009: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<int32>::Add(!0)
155 IL_000e: nop
156 IL_000f: ldloc.0
157 IL_0010: ldc.i4.2
158 IL_0011: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<int32>::Add(!0)
159 IL_0016: nop
160 IL_0017: nop
161 IL_0018: ldloc.0
162 IL_0019: callvirt instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<!0> class [mscorlib]System.Collections.Generic.List`1<int32>::GetEnumerator()
163 IL_001e: stloc.2
164 .try
165 {
166 IL_001f: br.s IL_003c
167 // loop start (head: IL_003c)
168 IL_0021: ldloca.s CS$5$0000
169 IL_0023: call instance !0 valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32>::get_Current()
170 IL_0028: stloc.1
171 IL_0029: nop
172 IL_002a: ldstr "value is {0}"
173 IL_002f: ldloc.1
174 IL_0030: box [mscorlib]System.Int32
175 IL_0035: call void [mscorlib]System.Console::WriteLine(string, object)
176 IL_003a: nop
177 IL_003b: nop
178
179 IL_003c: ldloca.s CS$5$0000
180 IL_003e: call instance bool valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32>::MoveNext()
181 IL_0043: stloc.3
182 IL_0044: ldloc.3
183 IL_0045: brtrue.s IL_0021
184 // end loop
185
186 IL_0047: leave.s IL_0058
187 } // end .try
188 finally
189 {
190 IL_0049: ldloca.s CS$5$0000
191 IL_004b: constrained. valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32>
192 IL_0051: callvirt instance void [mscorlib]System.IDisposable::Dispose()
193 IL_0056: nop
194 IL_0057: endfinally
195 } // end handler
196
197 IL_0058: nop
198 IL_0059: ret
199 } // end of method Program::LookatGenericList
200
201 .method public hidebysig specialname rtspecialname
202 instance void .ctor () cil managed
203 {
204 // Method begins at RVA 0x2190
205 // Code size 7 (0x7)
206 .maxstack 8
207
208 IL_0000: ldarg.0
209 IL_0001: call instance void [mscorlib]System.Object::.ctor()
210 IL_0006: ret
211 } // end of method Program::.ctor
212
213 } // end of class boxOrUnbox.Program

请尊重作者的劳动,转载请保留链接 玉开的技术博客

[转载]IIS 内部运行机制

mikel阅读(733)

[转载]IIS 内部运行机制 – ※森林小居※ – 博客园.

ASP.NET是一个非常强大的构建Web应用的平台,它提供了极大的灵活性和能力以致于可以用它来构建所有类型的Web应用。

绝大多数的人只熟悉高层的框架如: WebForms 和 WebServices –这些都在ASP.NET层次结构在最高层。

这篇文章的资料收集 整理自各种微软公开的文档,通过比较 IIS5、IIS6、IIS7 这三代 IIS 对请求的处理过程, 让我们熟悉 ASP.NET的底层机制并对请求(request)是怎么从Web服务器传送到ASP.NET运行时有所了解。通过对底层机制的了解,可以让我们对 ASP.net 有更深的理解。

IIS 5 的 ASP.net 请求处理过程

对图的解释:

IIS 5.x 一个显著的特征就是 Web Server 和真正的 ASP.NET Application 的分离。作为 Web Server 的IIS运行在一个名为 InetInfo.exe 的进程上,InetInfo.exe 是一个Native Executive,并不是一个托管的程序,而我们真正的 ASP.NET Application 则是运行在一个叫做 aspnet_wp 的 Worker Process 上面,在该进程初始化的时候会加载CLR,所以这是一个托管的环境。

ISAPI:  指能够处理各种后缀名的应用程序。 ISAPI 是下面单词的简写 :Internet Server Application Programe Interface,互联网服务器应用程序接口。

IIS 5 模式的特点:

1、首先,同一台主 机上在同一时间只能运行一个 aspnet_wp 进程,每个基于虚拟目录的 ASP.NET Application 对应一个 Application Domain ,也就是说每个 Application 都运行在同一个 Worker Process 中,Application之间的隔离是基于 Application Domain 的,而不是基于Process的。

2、其 次,ASP.NET  ISAPI 不但负责创建 aspnet_wp Worker Process,而且负责监控该进程,如果检测到 aspnet_wp 的 Performance 降低到某个设定的下限,ASP.NET  ISAPI 会负责结束掉该进程。当 aspnet_wp 结束掉之后,后续的 Request 会导致ASP.NET ISAPI 重新创建新的 aspnet_wp Worker Process。

3、最后,由于 IIS 和 Application 运行在他们各自的进程中,他们之间的通信必须采用特定的通信机制。本质上 IIS 所在的 InetInfo 进程和 Worker Process 之间的通信是同一台机器不同进程的通信(local interprocess communications),处于Performance的考虑,他们之间采用基于Named pipe的通信机制。ASP.NET ISAPI和Worker Process之间的通信通过他们之间的一组Pipe实现。同样处于Performance的原因,ASP.NET ISAPI 通过异步的方式将Request 传到Worker Process 并获得 Response,但是 Worker Process 则是通过同步的方式向 ASP.NET ISAPI 获得一些基于 Server 的变量。

IIS6 的 ASP.net 请求处理过程

对图的解释:

IIS 5.x 是通过 InetInfo.exe 监听 Request 并把Request分发到Work Process。换句话说,在IIS 5.x中对Request的监听和分发是在User Mode中进行,在IIS 6中,这种工作被移植到kernel Mode中进行,所有的这一切都是通过一个新的组件:http.sys 来负责。

注:为了避免用户应 用程序访问或者修改关键的操作系统数据,windows提供了两种处理器访问模式:用户模式(User Mode)和内核模式(Kernel Mode)。一般地,用户程序运行在User mode下,而操作系统代码运行在Kernel Mode下。Kernel Mode的代码允许访问所有系统内存和所有CPU指令。

在User Mode下,http.sys接收到一个基于 aspx 的http request,然后它会根据IIS中的 Metabase 查看该基于该 Request 的 Application 属于哪个Application Pool, 如果该Application Pool不存在,则创建之。否则直接将 request 发到对应Application Pool 的 Queue中。

每个 Application Pool 对应着一个Worker Process:w3wp.exe,毫无疑问他是运行在User Mode下的。在IIS Metabase 中维护着 Application Pool 和worker process的Mapping。WAS(Web Administrative service)根据这样一个mapping,将存在于某个Application Pool Queue的request 传递到对应的worker process(如果没有,就创建这样一个进程)。在 worker process 初始化的时候,加载ASP.NET ISAPI,ASP.NET ISAPI 进而加载CLR。最后的流程就和IIS 5.x一样了:通过AppManagerAppDomainFactory 的 Create方法为 Application 创建一个Application Domain;通过 ISAPIRuntime 的 ProcessRequest处理Request,进而将流程进入到ASP.NET Http Runtime Pipeline。

IIS 7  的 ASP.net 请求处理过程

IIS7 站点启动并处理请求的步骤如下图:

步骤 1 到 6 ,是处理应用启动,启动好后,以后就不需要再走这个步骤了。

上图的8个步骤分别如下:

1、当客户端浏览器开始HTTP 请求一个WEB 服务器的资源时,HTTP.sys 拦截到这个请求。

2、HTTP.sys contacts WAS to obtain information from the configuration store.

3、WAS 向配置存储中心请求配置信息。applicationHost.config。

4、WWW 服务接受到配置信息,配置信息指类似应用程序池配置信息,站点配置信息等等。

5、WWW 服务使用配置信息去配置 HTTP.sys 处理策略。

6、WAS starts a worker process for the application pool to which the request was made.

7、The worker process processes the request and returns a response to HTTP.sys.

8、客户端接受到处理结果信息。

W3WP.exe 进程中又是如果处理得呢?? IIS 7 的应用程序池的托管管道模式分两种: 经典和集成。 这两种模式下处理策略各不相通。

IIS 6 以及 IIS7 经典模式的托管管道的架构

在IIS7之前,ASP.NET 是以 IIS ISAPI extension 的方式外加到 IIS,其实包括 ASP 以及 PHP,也都以相同的方式配置(PHP 在 IIS 采用了两种配置方式,除了 IIS ISAPI extension 的方式,也包括了 CGI 的方式,系统管理者能选择 PHP 程序的执行方式),因此客户端对 IIS 的 HTTP 请求会先经由 IIS 处理,然后 IIS 根据要求的内容类型,如果是 HTML 静态网页就由 IIS 自行处理,如果不是,就根据要求的内容类型,分派给各自的 IIS ISAPI extension;如果要求的内容类型是 ASP.NET,就分派给负责处理 ASP.NET 的 IIS ISAPI extension,也就是 aspnet_isapi.dll。下图是这个架构的示意图。

IIS  7 应用程序池的托管管道模式  经典  模式也是这样的工作原理。 这种模式是兼容IIS 6 的方式, 以减少升级的成本。

IIS6 的执行架构图,以及 IIS7  应用程序池配置成经典模式的执行架构图

IIS  7 应用程序池的 托管管道模式  集成模式

而 IIS 7 完全整合 .NET 之后,架构的处理顺序有了很大的不同(如下图),最主要的原因就是 ASP.NET 从 IIS 插件(ISAPI extension)的角色,进入了 IIS 核心,而且也能以 ASP.NET 模块负责处理 IIS 7 的诸多类型要求。这些 ASP.NET 模块不只能处理 ASP.NET 网页程序,也能处理其他如 ASP 程序、PHP 程序或静态 HTML 网页,也因为 ASP.NET 的诸多功能已经成为 IIS 7 的一部份,因此 ASP 程序、PHP 程序或静态 HTML 网页等类型的要求,也能使用像是Forms认证(Forms Authentication)或输出缓存(Output Cache)等 ASP.NET 2.0 的功能(但须修改 IIS 7 的设定值)。也因为 IIS 7 允许自行以 ASP.NET API 开发并加入模块,因此 ASP.NET 网页开发人员将更容易扩充 IIS 7 和网站应用程序的功能,甚至能自行以 .NET 编写管理 IIS 7 的程序(例如以程控 IIS 7 以建置网站或虚拟目录)。

IIS 7 的执行架构图(集成托管信道模式下的架构)

小结

IIS5 到 IIS6 的改进,主要是 HTTP.sys 的改进。

IIS6 到 IIS7 的改进,主要是 ISAPI 的改进。

参考资料:

ASP.NET Process Model之一:IIS 和 ASP.NET ISAPI

http://www.cnblogs.com/artech/archive/2007/09/09/887528.html

ASP.NET Internals – IIS and the Process Model

http://dotnetslackers.com/articles/iis/ASPNETInternalsIISAndTheProcessModel.aspx

模组化的IIS 7 与.NET 能力整合

http://www.microsoft.com/taiwan/technet/columns/profwin/33-iis7-componentization-integration.mspx

Introduction to IIS 7.0 Architecture

http://learn.iis.net/page.aspx/101/introduction-to-iis7-architecture/

[转载]SQL Server 的事务和锁(一)

mikel阅读(871)

[转载]SQL Server 的事务和锁(一) – 夏天可是个好季节 – 博客园.

最近在项目中进行压力测试遇到了数据库的死锁问题,简言之,如下的代码在 SERIALIZABLE 隔离级别造成了死锁:

01 SELECT @findCount=COUNT(id) FROM MyTable
02 WHERE [fk_related_id]=@Argument
03
04 IF (@findCount > 0)
05 BEGIN
06 ROLLBACK TRANSACTION
07 RETURN ERROR_CODE
08 END
09
10 INSERT INTO MyTable ([fk_related_id],…)
11 VALUES (@Argument,…)
12
13 COMMIT TRANSACTION
14 RETURN SUCCESS_CODE

在搞清楚这个问题的过程中做了不少的实验,与各位共享。这一篇是开篇,主要说明的是 SQL Server 的四种(其实还有别的)经典的事务隔离级别,以及在不同的隔离级别下锁的使用手段,以及所带来的不同的数据一致性。

SQL Server 中锁的种类(Schema操作就暂时不涉及了)

锁类型 描述
(Shared Lock) 用于只读操作数据锁定
(Update Lock) 用于数据的更新,在数据真正的需要更新的时候会申请升级为X锁。
X(Exclusive Lock) 独占锁,用于数据的更改。
Key-Range Lock(稍后讨论) 仅仅在 Serializable 隔离级别保护数据,以避免任何有可能使得本事务第二次读取信息产生错误的数据插入操作

各个事务隔离级别下锁的使用

SQL Server 中有四种事务隔离级别,具体的大家去参建 MSDN。下面列出在不同的事务隔离级别下这些锁是如何使用的:

隔离级别 读数据锁状态 写数据锁状态 锁持有时间
Read Uncommitted 不获得任何锁 不获得任何锁
Read Committed 数据获得S锁 对于 INSERT、DELETE、UPDATE的执行,获得X锁;对于UPDATE的标记,获得U锁; 读完即释放,并不持有至事务结束。
Repeatable Read 数据获得S锁 对于 INSERT、DELETE、UPDATE的执行,获得X锁;对于UPDATE的标记,获得U锁; 持有至事务结束
Serializable 数据获得S锁,同时获得Key-Range锁。 对于 INSERT、DELETE、UPDATE的执行,获得X锁;对于UPDATE的标记,获得U锁,同时获得Key-Range锁。 持有至事务结束

我们可以利用这些知识形象说明各个隔离级别下的数据一致性:

Read Uncommitted 级别

(1)脏读

image

(2)更新丢失

image

(3)不可重复读

image

(4)幻读

clip_image001

Read Committed 级别

(1)脏读

clip_image001[5]

(2)更新丢失

clip_image002

(3)不可重复读

clip_image003

(4)幻读

clip_image004

Repeatable Read 级别

(1)脏读

clip_image005

(2)更新丢失

clip_image006

(3)不可重复读

clip_image007

(4)幻读

clip_image008

Serializable 级别

(1)脏读

clip_image009

(2)更新丢失

clip_image010

(3)不可重复读

clip_image011

(4)幻读

clip_image012

我们从上图可以比较直观的看到以下的结论

脏读 更新丢失 不可重复读 幻读
Read Uncommitted 可能 可能 可能 可能
Read Committed 不可能 可能 可能 可能
Repeatable Read 不可能 不可能 不可能 可能
Serializable 不可能 不可能 不可能 不可能

这一篇到此为止,下一篇详细介绍 Key-Range Lock 并分析开篇提到的死锁问题。

[转载]SQL Server 中几个有用的特殊函数

mikel阅读(905)

转载SQL Server 中几个有用的特殊函数 – 钢钢 – 博客园.

SQL Server 的使用过程中,发现几个很有用,但不太常用(或细节不太清楚)的函数(存储过程):

isnumeric,isdate,patindex,newid,collate,sp_executeSQL,checksum

遂记下,以备日后查询。不敢独享,与君共之。有用且看,无用略过。

1> isnumeric( expression )

— 返回值 1 | 0,判断是否是数字类型。

数值类型包括(int、bigint、smallint、tinyint、numeric、money、smallmoney、float、decimal、real)

示例:

select * from tablename
where isnumeric(columnname)<> 1;
go
以上示例使用 isnumeric 返回所有非数值的数据行。

2> isdate( expression )

— 如果 expression 是有效的 date、time 或 datetime 值,则返回 1;否则返回 0。

示例:

if isdate(2009-05-12 10:19:41.177= 1
print 有效的日期
else
print 无效的日期
上面的示例使用 isdate 测试某一字符串是否是有效的 datetime。

3> patindex( ‘%pattern%’ , expression )

— 返回指定表达式中某模式第一次出现的起始位置;

如果在全部有效的文本和字符数据类型中没有找到该模式,则返回零。

‘pattern’ : 一个通配符字符串。pattern 之前和之后必须有 % 字符(搜索第一个或最后一个字符时除外)。
expression : 通常为要在其中搜索指定模式的字符串数据类型列。

示例:

select patindex(%BB%,AA_BB_CC_DD_AA_BB_CC_DD)
返回:4

上面示例返回的是第一个‘BB’的开始位置。

其实,使用 charindex 函数也能实现上面示例的查询,如下:

select charindex(BB,AA_BB_CC_DD_AA_BB_CC_DD)
返回:4
patindex 函数与 charindex 函数的区别:
select patindex(%[0-9][A-Z]%AA_BB_9C_DD_AA_9F_CC_DD)
返回:7
select charindex(%[0-9][A-Z]%,AA_BB_9C_DD_AA_9F_CC_DD)
返回:0

看出来没有?patindex 函数可以使用通配符,而charindex 函数不能。也就是说:patindex 函数功能更强大!

4> newid( )

— 创建 uniqueidentifier 类型的唯一值。
这个函数总是能返回一个新的GUID号码,它永远不会重复,而且毫无规律。

示例:

declare @myid uniqueidentifier
set @myid = newid()
print @myid 的值是: + convert(varchar(255), @myid)

@myid 的值是: 0B939411-4827-485E-884B-5BEB1699CFEE

5> collate

— 一个子句,可应用于数据库定义或列定义以定义排序规则,或应用于字符串表达式以应用排序规则转换。
collate 子句只能应用于 char、varchar、text、nchar、nvarchar 和 ntext 数据类型。

示例:

drop table #tempTalbe
go
create table #tempTalbe
(
_id    int,
_name  varchar(30)
)
go
insert into #tempTalbe values(1,);
insert into #tempTalbe values(2,);
insert into #tempTalbe values(3,);

select * from #tempTalbe
order by _name
collate latin1_general_cs_as_ks_ws asc;
go
/* 显示结果:
_id         _name
———– ——————————
1           中
2           国
3           人
*/

select * from #tempTalbe
order by _name
collate Chinese_PRC_CS_AS_KS_WS asc;
go
/* 显示结果:
_id         _name
———– ——————————
2           国
3           人
1           中
*/

注意:

可以执行系统函数 fn_helpcollations 来检索 Windows 排序规则和 SQL Server 排序规则的所有有效排序规则名称的列表:

select * from fn_helpcollations()
6> sp_executesql 存储过程
建议您在执行字符串时,使用 sp_executesql 存储过程而不要使用 execute 语句。

由于此存储过程支持参数替换,因此 sp_executesql 比 execute 的功能更多;

由于 sql server 更可能重用 sp_executesql 生成的执行计划,因此 sp_executesql 比 execute 更有效。

示例:

create table #tb_suer( id int)
go
insert into #tb_suer values(1234)
go

declare @tbname nvarchar(20)
declare @sql nvarchar(500)
set @tbname=#tb_suer
set @sql=select * from + @tbname
execute sp_executesql @sql
/* 结果:
id
———–
1234
*/

上面示例演示了SQL语句的拼接。

7> checksum

—  返回按照表的某一行或一组表达式计算出来的校验和值。 checksum 用于生成哈希索引。

checksum ( * | expression [ ,…n ] )
*    指定对表的所有列进行计算。如果有任一列是非可比数据类型,则 checksum 返回错误。
非可比数据类型有 text、ntext、image、xml 和 cursor,还包括以上述任一类型作为基类型的 sql_variant。
expression    除非可比数据类型之外的任何类型的表达式。

示例:

找出在T1有,T表没有的记录。
select * from t1 where checksum(*not inselect checksum(*from t )

上面示例,等于是把t1表里的一行数据hash和t表一行数据hash后相比,就是说两个表里有没有行完全相当的。

[转载]用 ASP.NET MVC 实现基于 XMLHttpRequest long polling(长轮询) 的 Comet

mikel阅读(970)

[转载]用 ASP.NET MVC 实现基于 XMLHttpRequest long polling(长轮询) 的 Comet – dudu – 博客园.

之前在“反向Ajax,第1部分:Comet介绍”(英文版)文章中学习了“基于 Multipart XMLHttpRequest 的 Comet”的知识,然后用 ASP.NET MVC 实现了一个,详见用 ASP.NET MVC 实现基于 Multipart XMLHttpRequest 的 Comet

今天继续学习了基于 XMLHttpRequest long polling 的 Comet,又用 ASP.NET MVC 实现了一个,在这篇文章中分享一下。

先了解一下什么是XMLHttpRequest long polling?

这是一种推荐的实现Comet的做法,打开一个到服务器端的Ajax请求然后等待响应。服务器端需要一些特定的功能来允许请求被挂起,只要一有事件 发生,服务器端就会在挂起的请求中送回响应并关闭该请求。然后客户端就会使用这一响应并打开一个新的到服务器端的长生存期的Ajax请求。

This is a recommended method to implement Comet is to open an Ajax request to the server and wait for the response. The server requires specific features on the server side to allow the request to be suspended. As soon as an event occurs, the server sends back the response in the suspended request and closes it. The client then consumes the response and opens a new long-lived Ajax request to the server.

我个人的理解是,看起来就像在Web环境中客户端能订阅服务端的事件,服务器端通过事件去通知客户端。如果服务器端用 ASP.NET 来实现,可以利用 .NET 的事件驱动机制,很有意思,下面的示例代码将展示这一点。

先看Web前端js代码:

jQuery(function ($) {
    function long_polling() {
        $.getJSON('/comet/LongPolling', function (data) {
            if (data.d) {
                $('#logs').append(data.d + "<br/>");
            } 
            long_polling();
        });
    }
    long_polling();
});

js代码很简单,就是一个递归调用(调用在callback时进行的),通过JQuery的$.getJSON发起Ajax请求,’/comet /LongPolling’ 表示请求的服务端 CometController 的 LongPolling Action 的网址。这里我们可以看出实现 Comet 的难点不在 Web 前端,而是在服务器端。

接下来重点看 Web 服务器 ASP.NET MVC Controller 的代码。

首先要注意的是为了响应 XMLHttpRequest long polling 请求,我们需要实现一个异步控制器(AsyncController),如果您对 AsyncController 不熟悉,建议阅读MSDN上的文章 Using an Asynchronous Controller in ASP.NET MVC

先上 Controller 的实现代码:

(注:该控制器实现的功能是每隔5秒钟向客户端发送服务器当时间)

public class CometController : AsyncController
{
    //LongPolling Action 1 - 处理客户端发起的请求
    public void LongPollingAsync()
    {
        //计时器,5秒种触发一次Elapsed事件
        System.Timers.Timer timer = new System.Timers.Timer(5000);
        //告诉ASP.NET接下来将进行一个异步操作
        AsyncManager.OutstandingOperations.Increment();
        //订阅计时器的Elapsed事件
        timer.Elapsed += (sender, e) =>
            {
                //保存将要传递给LongPollingCompleted的参数
                AsyncManager.Parameters["now"] = e.SignalTime;
                //告诉ASP.NET异步操作已完成,进行LongPollingCompleted方法的调用
                AsyncManager.OutstandingOperations.Decrement();
            };
        //启动计时器
        timer.Start();
    }

    //LongPolling Action 2 - 异步处理完成,向客户端发送响应
    public ActionResult LongPollingCompleted(DateTime now)
    {
        return Json(new { d = now.ToString("MM-dd HH:mm:ss ") + 
            "-- Welcome to cnblogs.com!" }, 
            JsonRequestBehavior.AllowGet);
    }
}

实现异步控制器需要继承 System.Web.Mvc.AsyncController,并将 Action 分解为两个,比如 Action 叫 LongPolling,则分解为 LongPollingAsync 与 LongPollingCompleted 。LongPollingAsync 接受客户端请求,并发起异步操作;异步操作完成,调用LongPollingCompleted。

AsyncManager.OutstandingOperations.Increment(); 告诉ASP.NET接下来将进行一个异步操作。

AsyncManager.OutstandingOperations.Decrement(); 告诉ASP.NET异步操作完成,请调用LongPollingCompleted()方法。

示例代码中的异步操作就是将服务器当前时间作为参数传递给 LongPollingCompleted() 方法,LongPollingCompleted() 获取服务器当前时间并传递给客户端,客户端收到后将之显示出来,将继续发起 Ajax 请求 … 这样周而复始,实现了基于 XMLHttpRequest long polling 的 Comet。

示例代码运行结果如下:

小结

以前觉得 Comet 是很高深的东西,自己动手做了之后,发觉原来没那么难。所以,重要的是动手去做

如果不能在实际项目中去做,那就写一篇博客吧!

代码下载

CometMvcDemo_LongPolling.rar