今天有被问到:sqlserver锁定一行的最小锁是什么?
当时答曰:行级锁
回来查文档,得有关锁的信息(sql2k用syslockinfo表查, sql2k5用sys.dm_tran_locks表查):
资源类型:
1 = NULL 资源(未使用)
2 = 数据库
3 = 文件
4 = 索引
5 = 表
6 = 页
7 = 键
8 = 区
9 = RID(行 ID)
10 = 应用程序OK,现在来看看锁定到一行的最小级别的锁是什么。
D:\Program Files\Microsoft SQL Server\90\Tools\Binn>osql -Usa -Pdba123 -Sdragon
1> create table t_pk(t_id int primary key, t_desc varchar(50));
2> create table t_heap(t_id int, t_desc varchar(50));
3> go
1> insert into t_pk values(1, 'welcome');
2> insert into t_pk values(2, 'nice to meet you');
3> insert into t_pk values(3, 'wall street, stock');
4> go
(1 行受影响)
(1 行受影响)
(1 行受影响)
1> insert into t_heap select * from t_pk;
2> go
(3 行受影响)
1> begin tran
2> update t_pk set t_desc = 'have a nice day' where t_id = 3;
3> go
(1 行受影响)
现在,我更新有主键的表t_pk,看看sqlserver锁了些什么东东:
这里,sqlserver对t_pk表以及相应的page加上了IX锁,对更新的那一行加上了X锁。
再来,现在试试对堆表的更新:
1> rollback;
2> go
1> begin tran
2> update t_heap set t_desc = 'have a nice day' where t_id = 3;
3> go

作者:jll 日期:2006-04-30
出处:http://jll.cnblogs.com
一、前言
2005年7月下旬至8月中旬,我做了一个实现联通sgip1.2二级网关的项目,由于种种原因这个项目只完成了核心模块的2/5左右。此系统的源码几番周折,从硬盘转到邮箱,又从邮箱转到QQ网络硬盘。我想,应该赶在它“发霉”之前共享出来,一则可以让需要有的朋友作为参考; 二则或许可以得到相关朋友的指正,以此提高自已的水平。
二、为什么要选择.net 2.0作为开发平台
开始这个项目的时候,我有几个会用的平台或工具作为选择:
(1) Delphi 这东东就不用说了,组件多,开发资料也丰富,Indy 开发网络程序就足够强大
(2) C++ Builder 跟Delphi差不多,但是调用Socket API方便些
(3) .net 在多线程编程方面相对简单,同时对Socket也提供了很好地封装
之所以选择.net, 一方面是看中它强大的多线程库的支持,另一方面则是为了体验一下.net的威力[当时(当然也包括现在)对.net不是很熟悉]。考虑到这个项目是应用在服务器端且服务器性能较好,而用户也不会反感装一个20多兆的Framework,所以俺选择了它。
三、.net下socket编程的一些注意事项
(1) 如何将一个结构体转换为byte[],或者如何将byte[]转换为相应的结构体
有3种方式可以作为选择:
a) 一是采用序列化的方式,在发送前将对象序列化成byte[], 通过socket转发之后再将byte[]还原
b)用BitConvert类来处理
c)使用Unsafe方式
三种方式的详细实现请参见我的这篇blog: http://jll.cnblogs.com/archive/2005/07/23/198851.aspx
(2) 网络字节顺序与主机字节顺的转换
在写socket程序时要注意,如果要发送整型(short, int, long等)类型的数据,需要将这些值转换成网络字节顺序后才后再发送,同时接收方也要将网络字节顺序的值转为主机字节顺序的。System.Net.IPAddress类提供了HostToNetworkOrder 、HostToNetworkOrder 来完成相应的功能。
(3) 如何判断socket已经断开了
tcp的实现机制决定了这个处理这个问题的复杂性。 已连接的socket, 如果网络突然断开了或者是对方突然死机,tcp的默认实现机制是不能检测到这种情况的。然而,在.net下的Socket,即使你按照正常的程序来关闭Socket,它也不会有相应的事件或属性来告知您。
我的这篇blog: http://jll.cnblogs.com/archive/2005/07/29/203090.html 较详细地叙述了这个问题。
四、联通的sgip 1.2协议
网上资料很多,请自行google或baidu,^_^
五、程序源码及开发文档
这篇blog的核心就在于这里(http://files.cnblogs.com/JLL/sgipSMG.rar)了, 包括整个源代码和开发文档。请阅读里面的 "开发文档.doc" 文件; 用vs 2005打开sgipSMG.sln后,在“解决方案资源管理器”下会看到4个项目,其中 "sgipSMG 项目" 为核心代码所在。
需要的朋友请下载之。
good luck and have a good day!
class TreeNodeHelper
{
TreeNode treeNode = null;
public TreeNodeHelper(TreeNode tr)
{
treeNode = tr;
}

/**//// <summary>
/// 返回TreeNode是否有子结点
/// </summary>
public bool HasChildren
{
get
{
return IsTreeNodeHasChildren(treeNode);
}
set
{
MakeTreeNodeHasChildren(treeNode, value);
}
}
public const UInt32 TV_FIRST = 4352;
public const UInt32 TVSIL_NORMAL = 0;
public const UInt32 TVSIL_STATE = 2;
public const UInt32 TVM_SETIMAGELIST = TV_FIRST + 9;
public const UInt32 TVM_GETNEXTITEM = TV_FIRST + 10;
public const UInt32 TVIF_HANDLE = 16;
public const UInt32 TVIF_STATE = 8;
public const UInt32 TVIS_STATEIMAGEMASK = 61440;
public const UInt32 TVM_SETITEM = TV_FIRST + 13;
public const UInt32 TVM_GETITEM = TV_FIRST + 12;
public const UInt32 TVGN_ROOT = 0;
public const int TVIF_CHILDREN = 64;
// Use a sequential structure layout to define TVITEM for the TreeView.
[StructLayout(LayoutKind.Sequential, Pack = 8, CharSet = CharSet.Auto)]
public struct TV_ITEM
{
public uint mask;
public IntPtr hItem;
public uint state;
public uint stateMask;
public IntPtr pszText;
public int cchTextMax;
public int iImage;
public int iSelectedImage;
public int cChildren;
public IntPtr lParam;
}
// Declare two overloaded SendMessage functions. The
// difference is in the last parameter: one is ByVal and the
// other is ByRef.
[DllImport("user32.dll")]
public static extern UInt32 SendMessage(IntPtr hWnd, UInt32 Msg,
UInt32 wParam, UInt32 lParam);
[DllImport("User32", CharSet = CharSet.Auto)]
public static extern IntPtr SendMessage(IntPtr hWnd, UInt32 msg,
UInt32 wParam, ref TV_ITEM lParam);

/**//// <summary>
/// 指定TreeNode是否有子结点(有子结点则TreeNode会显示+号,没有则不会显示)
/// </summary>
/// <param name="tr"></param>
/// <param name="bHasChildren"></param>
public static void MakeTreeNodeHasChildren(TreeNode tr, bool bHasChildren)
{
TV_ITEM tvItem = new TV_ITEM();
tvItem.mask = TVIF_CHILDREN | TVIF_HANDLE;
tvItem.hItem = tr.Handle;
tvItem.cChildren = bHasChildren ? 1 : 0;
SendMessage(tr.TreeView.Handle, TVM_SETITEM, 0, ref tvItem);
}

/**//// <summary>
/// 返回树结点是否有子结点
/// </summary>
/// <param name="?"></param>
/// <returns></returns>
public static bool IsTreeNodeHasChildren(TreeNode tr)
{
if (tr.Nodes.Count > 0)
{
return true;
}
TV_ITEM tvItem = new TV_ITEM();
tvItem.mask = TVIF_CHILDREN | TVIF_HANDLE;
tvItem.hItem = tr.Handle;
SendMessage(tr.TreeView.Handle, TVM_GETITEM, 0, ref tvItem);
return tvItem.cChildren == 1;
}
}
<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
protected void Page_Load(object sender, EventArgs e)
{
string strEmployeeID = Request.QueryString["ID"];
if (strEmployeeID == null)
{
return;
}
SqlConnection con = new SqlConnection(WebConfigurationManager.ConnectionStrings["Northwind"].ConnectionString);
SqlCommand cmd = new SqlCommand("select Photo from Employees where EmployeeID=" + strEmployeeID, con);
con.Open();
byte[] buffer = (byte[])cmd.ExecuteScalar();
con.Close();
Response.BinaryWrite(buffer);
Response.End();
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
</div>
</form>
</body>
</html>
<asp:TemplateField HeaderText="Picture">
<EditItemTemplate>
<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
</EditItemTemplate>
<ItemTemplate>
<asp:Image ID="Image1" runat="server" ImageUrl='<%# "GetEmployeeImage.aspx?ID=" + Eval("EmployeeID") %>'/>
</ItemTemplate>
</asp:TemplateField>
<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:SqlDataSource ID="employeeDataSource" runat="server" ConnectionString="<%$ ConnectionStrings:Northwind %>"
SelectCommand="SELECT [EmployeeID], [LastName], [FirstName], [Photo], [Country] FROM [Employees]">
</asp:SqlDataSource>
</div>
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" DataKeyNames="EmployeeID"
DataSourceID="employeeDataSource" Height="172px" Width="335px">
<Columns>
<asp:BoundField DataField="EmployeeID" HeaderText="EmployeeID" InsertVisible="False"
ReadOnly="True" SortExpression="EmployeeID" />
<asp:BoundField DataField="LastName" HeaderText="LastName" SortExpression="LastName" />
<asp:BoundField DataField="FirstName" HeaderText="FirstName" SortExpression="FirstName" />
<asp:BoundField DataField="Country" HeaderText="Country" SortExpression="Country" />
<asp:TemplateField HeaderText="Picture">
<EditItemTemplate>
<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
</EditItemTemplate>
<ItemTemplate>
<asp:Image ID="Image1" runat="server" ImageUrl='<%# "GetEmployeeImage.aspx?ID=" + Eval("EmployeeID") %>'/>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
</form>
</body>
</html>