用过logExplorer的朋友都会被他强悍的功能吸引,我写过一篇详细的操作文档可以参考
http://blog.csdn.net/jinjazz/archive/2008/05/19/2459692.aspx

我们可以自己用开发工具来实现sql日志的读取,这个应用还是很酷的,具体思路

1、首先要了解一个没有公开的系统函数::fn_dblog,他可以读取sql日志,并返回二进制的行数据
2、然后要了解sql的二进制数据是如何存储的,这个可以参考我的blog文章
http://blog.csdn.net/jinjazz/archive/2008/08/07/2783872.aspx
3、用自己擅长的开发工具来分析数据,得到我们需要的信息

我用c#写了一个测试样例,分析了int,char,datetime和varchar的日志情况而且没有考虑null和空字符串的保存,希望感兴趣的朋友能和我一起交流打造属于自己的日志分析工具

详细的试验步骤以及代码如下:

1、首先建立sqlserver的测试环境,我用的sql2005,这个过程不能保证在之前的版本中运行
以下sql语句会建立一个dbLogTest数据库,并建立一张log_test表,然后插入3条数据之后把表清空

  1. use master
  2. go
  3. create database dbLogTest
  4. go
  5. use  dbLogTest
  6. go
  7. create table log_test(id int ,code char(10),name varchar(20),date datetime,memo varchar(100))
  8. insert into log_test select 100, 'id001','jinjazz',getdate(),'剪刀'
  9. insert into log_test select 65549,'id002','游客',getdate()-1,'这家伙很懒,没有设置昵称'
  10. insert into log_test select -999,'id003','这家伙来自火星',getdate()-1000,'a'
  11. delete from log_test
  12. --use master
  13. --go
  14. --drop database dbLogTest

2、我们最终的目的是要找到被我们删掉的数据

3、分析日志的c#代码:我已经尽量详细的写了注释

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. namespace ConsoleApplication21
  5. {
  6. class Program
  7. {
  8. /// <summary>
  9. /// 分析sql2005日志,找回被delete的数据,引用请保留以下信息
  10. /// 作者:jinjazz (csdn的剪刀)
  11. /// 作者blog:http://blog.csdn.net/jinjazz
  12. /// </summary>
  13. /// <param name="args"></param>
  14. static void Main(string[] args)
  15. {
  16. using (System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection())
  17. {
  18. conn.ConnectionString = "server=localhost;uid=sa;pwd=sqlgis;database=dbLogTest";
  19. conn.Open();
  20. using (System.Data.SqlClient.SqlCommand command = conn.CreateCommand())
  21. {
  22. //察看dbo.log_test对象的sql日志
  23. command.CommandText = @"SELECT allocunitname,operation,[RowLog Contents 0] as r0,[RowLog Contents 1]as r1
  24. from::fn_dblog (nullnull)
  25. where allocunitname like 'dbo.log_test%'and
  26. operation in('LOP_INSERT_ROWS','LOP_DELETE_ROWS')";
  27. System.Data.SqlClient.SqlDataReader reader = command.ExecuteReader();
  28. //根据表字段的顺序建立字段数组
  29. Datacolumn[] columns = new Datacolumn[]
  30. {
  31. new Datacolumn("id", System.Data.SqlDbType.Int),
  32. new Datacolumn("code", System.Data.SqlDbType.Char,10),
  33. new Datacolumn("name", System.Data.SqlDbType.VarChar),
  34. new Datacolumn("date", System.Data.SqlDbType.DateTime),
  35. new Datacolumn("memo", System.Data.SqlDbType.VarChar)
  36. };
  37. //循环读取日志
  38. while (reader.Read())
  39. {
  40. byte[] data = (byte[])reader["r0"];
  41. try
  42. {
  43. //把二进制数据结构转换为明文
  44. TranslateData(data, columns);
  45. Console.WriteLine("数据对象{1}的{0}操作:", reader["operation"], reader["allocunitname"]);
  46. foreach (Datacolumn c in columns)
  47. {
  48. Console.WriteLine("{0} = {1}", c.Name, c.Value);
  49. }
  50. Console.WriteLine();
  51. }
  52. catch
  53. {
  54. //to-do...
  55. }
  56. }
  57. reader.Close();
  58. }
  59. conn.Close();
  60. }
  61. Console.WriteLine("************************日志分析完成");
  62. Console.ReadLine();
  63. }
  64. //自定义的column结构
  65. public class Datacolumn
  66. {
  67. public string Name;
  68. public System.Data.SqlDbType DataType;
  69. public short Length = -1;
  70. public object Value = null;
  71. public Datacolumn(string name, System.Data.SqlDbType type)
  72. {
  73. Name = name;
  74. DataType = type;
  75. }
  76. public Datacolumn(string name,System.Data.SqlDbType type,short length)
  77. {
  78. Name = name;
  79. DataType = type;
  80. Length = length;
  81. }
  82. }
  83. /// <summary>
  84. /// sql二进制结构翻译,这个比较关键,测试环境为sql2005,其他版本没有测过。
  85. /// </summary>
  86. /// <param name="data"></param>
  87. /// <param name="columns"></param>
  88. static void TranslateData(byte[] data, Datacolumn[] columns)
  89. {
  90. //我只根据示例写了Char,DateTime,Int三种定长度字段和varchar一种不定长字段,其余的有兴趣可以自己补充
  91. //这里没有暂时没有考虑Null和空字符串两种情况,以后会补充。
  92. //引用请保留以下信息:
  93. //作者:jinjazz
  94. //sql的数据行二进制结构参考我的blog
  95. //http://blog.csdn.net/jinjazz/archive/2008/08/07/2783872.aspx
  96. //行数据从第5个字节开始
  97. short index = 4;
  98. //先取定长字段
  99. foreach (Datacolumn c in columns)
  100. {
  101. switch (c.DataType)
  102. {
  103. case System.Data.SqlDbType.Char:
  104. //读取定长字符串,需要根据表结构指定长度
  105. c.Value = System.Text.Encoding.Default.GetString(data,index,c.Length);
  106. index += c.Length;
  107. break;
  108. case System.Data.SqlDbType.DateTime:
  109. //读取datetime字段,sql为8字节保存
  110. System.DateTime date = new DateTime(1900, 1, 1);
  111. //前四位1/300秒保存
  112. int second = BitConverter.ToInt32(data, index);
  113. date = date.AddSeconds(second/300);
  114. index += 4;
  115. //后四位1900-1-1的天数
  116. int days = BitConverter.ToInt32(data, index);
  117. date=date.AddDays(days);
  118. index += 4;
  119. c.Value = date;
  120. break;
  121. case System.Data.SqlDbType.Int:
  122. //读取int字段,为4个字节保存
  123. c.Value = BitConverter.ToInt32(data, index);
  124. index += 4;
  125. break;
  126. default:
  127. //忽略不定长字段和其他不支持以及不愿意考虑的字段
  128. break;
  129. }
  130. }
  131. //跳过三个字节
  132. index += 3;
  133. //取变长字段的数量,保存两个字节
  134. short varColumnCount = BitConverter.ToInt16(data, index);
  135. index += 2;
  136. //接下来,每两个字节保存一个变长字段的结束位置,
  137. //所以第一个变长字段的开始位置可以算出来
  138. short startIndex =(short)( index + varColumnCount * 2);
  139. //第一个变长字段的结束位置也可以算出来
  140. short endIndex = BitConverter.ToInt16(data, index);
  141. //循环变长字段列表读取数据
  142. foreach (Datacolumn c in columns)
  143. {
  144. switch (c.DataType)
  145. {
  146. case System.Data.SqlDbType.VarChar:
  147. //根据开始和结束位置,可以算出来每个变长字段的值
  148. c.Value =System.Text.Encoding.Default.GetString(data, startIndex, endIndex - startIndex);
  149. //下一个变长字段的开始位置
  150. startIndex = endIndex;
  151. //获取下一个变长字段的结束位置
  152. index += 2;
  153. endIndex = BitConverter.ToInt16(data, index);
  154. break;
  155. default:
  156. //忽略定长字段和其他不支持以及不愿意考虑的字段
  157. break;
  158. }
  159. }
  160. //获取完毕
  161. }
  162. }
  163. }

4、更改你的sql连接字符串后运行以上代码,会看到如下输出信息:

  1. 数据对象dbo.log_test的LOP_INSERT_ROWS操作:
  2. id = 100
  3. code = id001
  4. name = jinjazz
  5. date = 2008-8-7 18:14:03
  6. memo = 剪刀
  7. 数据对象dbo.log_test的LOP_INSERT_ROWS操作:
  8. id = 65549
  9. code = id002
  10. name = 游客
  11. date = 2008-8-6 18:14:03
  12. memo = 这家伙很懒,没有设置昵称
  13. 数据对象dbo.log_test的LOP_INSERT_ROWS操作:
  14. id = -999
  15. code = id003
  16. name = 这家伙来自火星
  17. date = 2005-11-11 18:14:03
  18. memo = a
  19. 数据对象dbo.log_test的LOP_DELETE_ROWS操作:
  20. id = 100
  21. code = id001
  22. name = jinjazz
  23. date = 2008-8-7 18:14:03
  24. memo = 剪刀
  25. 数据对象dbo.log_test的LOP_DELETE_ROWS操作:
  26. id = 65549
  27. code = id002
  28. name = 游客
  29. date = 2008-8-6 18:14:03
  30. memo = 这家伙很懒,没有设置昵称
  31. 数据对象dbo.log_test的LOP_DELETE_ROWS操作:
  32. id = -999
  33. code = id003
  34. name = 这家伙来自火星
  35. date = 2005-11-11 18:14:03
  36. memo = a
  37. ************************日志分析完成

c#读取并分析sql Server2005数据库日志的更多相关文章

  1. 收缩sql server数据库日志

    项目中,可能数据库(sql server数据库)日志太多,占了很多磁盘空间,可以通过收缩数据库日志,减少日志文件大小. 下面以Northwind数据库为例: 1.把数据库的恢复模式设置为“简单模式”: ...

  2. SQL 收缩数据库日志的几种办法 (2005与2008 略有区别)

    在SQL Server 2000/2005中可以快速压缩日志log文件,通过SQL, 方法一: ---DBTEST 为数据库名,顺序最好别乱.注意:要先截断再清空,最后收缩! backup log D ...

  3. MS SQL SERVER 数据库日志压缩方法与代码

    MS SQL性能是很不错的,但是数据库用了一段时间之后,数据库却变得很大,实际的数据量不大.一般都是数据库日志引起的!数据库日志的增长可以达到好几百M. DUMP TRANSACTION [数据库名] ...

  4. 查询SQL SERVER数据库日志工具

    在SQL SERVER中查看操作日志,一直是一个比较麻烦的事情,因为微软并没有提供直接的系统工具可以查看日志内容,虽然可以通过非正式的隐藏接口dbcc log 获取日志的非解析编码但是要还原是个非常麻 ...

  5. 解决SQL server2005数据库死锁的经验心得

    前段时间提到的"sql server 2005 死锁解决探索",死锁严重,平均每天会发生一次死锁,在解决和处理SQL server2005死锁中查了很多资料和想了很多办法,后来我们 ...

  6. SQL Server 数据库开启日志CDC记录,导致SQL Server 数据库日志异常增大

    这几天单位的SQL Server业务数据生产库出现数据库日志增长迅速,导致最终数据无法写入数据库,业务系统提示"数据库事务日志已满",经过多方咨询和请教,终于将日志异常的数据库处理 ...

  7. 纯C++ 连接SQL Server2005 数据库读写操作的小例子

    一个测试c++链接 sql server 数据库的例子// 数据库说明// 数据库用户为 sa , 密码为 空// 数据库为 MyDB// 表为 UserInfo// 表字段为 Name . Pass ...

  8. sql server2016 数据库日志 清空语句

    /*1.查询数据库日志文件名称*/--TC_MES_DEV为数据库名--这里的 数据库日志名,可以用以下注释的语句进行查询(_log那个)USE [TC_MES_DEV]GOSELECT file_i ...

  9. SQL SERVER2008 数据库日志文件的收缩方法

    最近公司的数据库随着业务量的增多,日志文件巨大(超过300G),造成磁盘空间不够用,进而后来的访问数据库请求无法访问. 网上类似的方法也很多,但不可行,如下是我实践过,可行的,将日志文件收缩至任意指定 ...

随机推荐

  1. 【笔记】Kali linux的安装 和 一些使用前的准备工作(原创+转载)

    该博文只记录笔者的蛇皮使用经历,纯新手= =,可能借鉴意义也可能没有(T _ T),侵删. 目录 kali linux 在个人计算机和在VirtualBox下的安装 kali linux 使用前准备工 ...

  2. vue2购物车ch4-(筛选v-for 点击的那个设置样式 设为默认地址其他 联动 非循环的列表选中和非选中 删除当前选中的列表)

    1 address.html <!DOCTYPE html> <html lang="en"> <head> <meta charset= ...

  3. 浅析php curl_multi_*系列函数进行批量http请求

    何起: 一系列 数量很大 数据不热 还希望被蜘蛛大量抓取的页面,在蜘蛛抓取高峰时,响应时间会被拉得很高. 前人做了这样一个事儿:页面分3块,用3个内部接口提供,入口文件用curl_multi_*系列函 ...

  4. ajax和jsonp使用总结

    前言:ajax和jsonp可以与后台通信,获取数据和信息,但是又不用刷新整个页面,实现页面的局部刷新. 一.ajax 定义:一种发送http请求与后台进行异步通讯的技术. 原理:实例化xmlhttp对 ...

  5. opencv-python:win7下,搭建python2.7.5环境,配置opencv3.1.0准备开工-OpenCV步步精深

    我的个人博客:点这里 搭建python2.7.5环境 下载python2.7.5 64位:https://www.python.org/ftp/python/2.7.5/python-2.7.5.am ...

  6. Nhibernate/Hibernate 使用多参数存儲過程 出現could not execute query,Could not locate named parameter等錯誤解決

    <?xml version="1.0" encoding="utf-8" ?> <hibernate-mapping xmlns=" ...

  7. C#枚举中使用Flags特性

    如果对一个值可以包含多个,那么可以使用枚举,加上Flags 本文告诉大家如何写一个 Flags. 在写前,需要知道一些基础知识,取反.或.与,如果不知道的话,请去看看基础. 当然,这些太复杂了,我也不 ...

  8. ajax上传图片的本质

    1.图片上传到服务器. 2.后台将图片地址传到html页面,以图片形式展现. 3.后天将图片地址加入到input表单中,表单处于隐藏状态. 4.前端删除图片,通过js操作,移除图片与表单数据. 5.图 ...

  9. 初识.Net IL

    1.IL基本资料 1.IL概述 IL是.NET框架中中间语言(Intermediate Language)的缩写.使用.NET框架提供的编译器可以直接将源程序编译为.exe或.dll文件,但此时编译出 ...

  10. d3根据数据绘制不同的形状

    绘制力导向图的时候通常节点都是圆形,但也会遇到公司节点绘制成圆型,人绘制成方形的情况,那我们怎么依据数据绘制不同的形状. 你可能首先会想到,这很简单啊,是公司的时候append circle,是人的时 ...