随笔-62  评论-361  文章-0  trackbacks-6
 

一、        简介

使用环境:SQL Server

    在项目开发过程中,项目管理者通常都很希望对项目的开发进展有一个日志的记录。代码的记录和管理可以通过TFS或者VSS等工具去管理。但是数据库却没有记录开发日志这一功能。这在实际开发中很不方便,特别是大量的存储过程改动。

       那么针对这一个需求,在数据库中定时执行一个Job,让其自动记录存储过程的改动,以完成对数据库存储过程改动的一个记录。

二、        实际效果

Sp_id

change_date

action_type

sp_name

755585830

2007-11-13

Added

Sp_a

451584747

2007-11-13

Update

Sp_b

2119014630

2007-11-13

Update

Sp_c

2119014630

2007-11-13

Update

Sp_d

771585887

2007-11-13

Deleted

Sp_e

三、        实现原理

由于数据库中所有的存储过程代码都记录在系统表Sys_comments中,所以我们可以通过比较不同时间点代码的方式去实现记录一定时间范围内的存储过程变化。

比如:在今天早上0100我们把所有存储过程代码从系统表中取出,并记录。然后到明天早上再重复这一过程,将两次取出的不同结果进行比较,取出有变化的存储过程并记录,认为这些存储过程在这一时间范围内存在更新。

四、        实现代码

其实原理很简单,就是一个循环比较的方式,所以也不需要大费周章的去介绍了,那么下面就把实现相关的代码和流程贴出来。

1建立数据表

 

在数据库建立三张表,sps_old, sps_new, sps_log

Sps_old:记录前一次系统中所有存储过程代码,以备比较

Sps_new:当前所有存储过程的代码,与sps_log_old中的数据比较

Sps_log:记录在两个时间点范围内变化的存储过程名字和变化时间

表结构:

/****** Sps_log ******/

CREATE TABLE [dbo].[sps_log](

       [sp_id] [int] NULL,

       [change_date] [datetime] NULL,

       [action_type] [char](10) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,

       [sp_name] [varchar](150) COLLATE SQL_Latin1_General_CP1_CI_AS NULL

) ON [PRIMARY]

/****** Sps_new ******/----------------------------------------------------------------

CREATE TABLE [dbo].[sps_new](

       [sp_id] [int] NULL,

       [colid] [smallint] NULL,

       [sp_name] [varchar](150) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,

       [sp_content] [varchar](4000) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,

       [record_date] [datetime] NULL

) ON [PRIMARY]

/******Sps_old******/-----------------------------------------------------------------------------------

CREATE TABLE [dbo].[sps_old](

       [sp_id] [int] NULL,

       [colid] [smallint] NULL,

       [sp_name] [varchar](150) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,

       [sp_content] [varchar](4000) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,

       [record_date] [datetime] NULL

) ON [PRIMARY]

----------------------------------------------------------------------------------------------------------------

2建立进行比较用的存储过程,并记录结果集

 

/*------------------------------------------------------------------------------------------------------

 -- Function   :      sps_log_add

 -- Description       :      record all sps change log

 --1 get all new sps (find sps which in new table not in old table)

 --2 get all deleted sps (find sps which in old table not in new table)

 --3 get all updated sps (find sps which in old talbe are not same in new table)

 -- any change will record into sps_log table

------------------------------------------------------------------------------------------------------*/

CREATE procedure [dbo].[sps_log_add]

as

-- clear out sps_new

truncate table sps_new

-- fill into sps_new

insert into       sps_new

(sp_id,colid,sp_name,sp_content,record_date)

select

       a.id,

       a.colid,

       b.name,

       a.[text],

       getdate()

from

       syscomments a

left join

       sysobjects b

 on a.id = b.id

where b.type='P' and b.name not like 'dt_%'

-- Find new sp

insert into

       sps_log

select distinct

       sp_id,

       getdate(),

       'Added',

       sp_name

from

       sps_new

where

       sp_id not in (select distinct sp_id from sps_old)

-- Find deleted sp

insert into

       sps_log

select distinct

       sp_id,

       getdate(),

       'Removed',

       sp_name

from

       sps_old

where

       sp_id not in (select distinct sp_id from sps_new)

-- compare existing sp

DECLARE @ProcID int

declare @count_new int

declare @count_old int

declare @text_new varchar(4000)

declare @text_old varchar(4000)

declare @name varchar(150)

declare @i int

DECLARE SearchProc CURSOR FOR

select distinct

       sp_id

from

       sps_new

where

       sp_id in (select distinct sp_id from sps_old)

order by

       sp_id

open SearchProc

FETCH NEXT FROM SearchProc

INTO @ProcID

WHILE @@FETCH_STATUS >=0

BEGIN

       -- colid quantity

       select @count_new=count(colid) from sps_new where sp_id = @ProcID

      select @count_old=count(colid) from sps_old where sp_id = @ProcID

-- if count of colid is unequal, sp was updated.

       if @count_new <> @count_old

              begin

                     -- Record change

                     insert into       sps_log(sp_id,change_date,action_type) values(@ProcID,getdate(),'Update')

              end

       else -- @count_new = @count_old, if count of colid is equal

              begin

                     set @i=1 -- Reset Counter

                     while @i<=@count_new -- colid

                     begin

                                   -- sp content

select @text_new = sp_content from sps_new

where sp_id = @ProcID and colid = @i

                                   select @text_old = sp_content from sps_old

where sp_id = @ProcID and colid = @i

-- if content is different, sp was updated.

                                   if @text_new <> @text_old        

                                          begin      

                                                 -- Record change

                                                 select @name = [name] from sysobjects where id=@ProcID

                                                 insert into sps_log(sp_id,change_date,action_type,sp_name)

values(@ProcID,getdate(),'Update',@name)

                                          end

                                   set @i= @i+1 -- Counter + 1

                     end

              end

       FETCH NEXT FROM SearchProc

    INTO @ProcID

END

CLOSE SearchProc

DEALLOCATE SearchProc

-- clear out sps_new

truncate table sps_old

-- fill into sps_old with sps_new

insert into sps_old select * from sps_new

----------------------------------------------------------------------------------------------------------------------

3创建一个存储过程从sps_log中获取指定时间内的数据

 

/*

 -- Function   : sps_log_get

 -- Description       : Show sps change in a period of time

*/

CREATE PROCEDURE [dbo].[sps_log_get]

@from_date datetime,

@to_date datetime

as

       select

              sp_name,

              action_type,

              CONVERT(varchar(10),change_date,102) as change_date

       from

              sps_log

       where

              change_date between @from_date and @to_date

       group by

              sp_name,action_type,CONVERT(varchar(10),change_date,102)

       order by

              CONVERT(varchar(10),change_date,102) asc

五、        实际应用和配置

在数据库中新建一个Job,代码为exec sps_log_add,一般运行可以设置为每天的零晨,一天一次比较合理,这样便能把每天做的改动记录下来。

六、        查看日志

直接运行存储过程exec sps_log_get ‘2007-11-01’,’2007-11-30’。便能查看所有在这一段时间内的存储过程变化。


    如果您有更好的办法,还请务必留言。谢谢!

posted on 2007-11-19 14:42 Carlwave-陆飞(Fei.Lu) 阅读(1455) 评论(12)  编辑 收藏 网摘 所属分类: SQL 数据库相关

评论:
#1楼 2007-11-19 21:38 | 搜索人生      
跟版本管理软件关联就行了,不必这么麻烦吧
  回复  引用  查看    
#2楼[楼主] 2007-11-19 23:26 | Carlwave-陆飞(Fei.Lu)      
@搜索人生
首先,感谢你参与讨论。但是我希望做事严谨不是随便说说。
请务必提出切实可行的方案,版本管理软件具体是什么软件?我在网上也有查过,并没有找到相关的软件。只有记录数据库日志的收费软件,而且易用性不强。

  回复  引用  查看    
#3楼 2007-11-20 09:02 | arcticfox[未注册用户]
采用 VSS 和 VSTS 都可以做到 版本控制的
  回复  引用    
#4楼[楼主] 2007-11-20 09:14 | Carlwave-陆飞(Fei.Lu)      
@arcticfox
可以讨论下,
首先,你提出的VSS和VSTS根本就是两个概念,一个是源码管理,一个是开发框架。要比也应该是VSS和TFS才对。
其次,据我所知(而且本人的开发环境也就是VSTS+TFS),TFS源码管理并不能针对SQL的存储过程改变进行记录。
我也在网上搜索了一下,并没有发现TFS据有该功能,当然也可能是我没有搜索完全,同样希望你提出具体的做法,或者给出范例的连接,以便更好的方法能让更多的人看到。
暂时,本人认为你的方案不可行。

  回复  引用  查看    
#5楼 2007-11-20 09:18 | carl.chang[未注册用户]
SQL 2005 支持 VSS 管理
  回复  引用    
#6楼[楼主] 2007-11-20 09:38 | Carlwave-陆飞(Fei.Lu)      
@carl.chang
查到你说的方法了,确实在VSS中有这么一回事情,可以用VSS进行存储过程版本控制,但是其具体实现相当繁琐,一般是这样,按人或者系统建立存储过程文件管理,在用vss进行版本控制,一般可以用winsql在进行存储过程编辑、编译过程,完成一个新版本纳入vss管理。
也就是说存储过程脱离SQL SERVER的管理,也和代码一样要check in , check out。还得将数据库也纳入VSS中,这大大降低了数据库代码本身的易用性和灵活性。
我不喜欢这种方法,如果你说的方法和我说的不一致,还是希望你贴出具体的内容或者链接。

  回复  引用  查看    
#7楼 2007-11-20 09:49 | Clark Zheng      
不错的方法,一天之内的几次变化怎么办呢,感觉这种方法唯一的缺陷就是没有在每次变更时强制性的check in/out。
不知道sql2005支不支插件开发,楼主可以考虑做个插件连上TFS呢

  回复  引用  查看    
#8楼[楼主] 2007-11-20 09:57 | Carlwave-陆飞(Fei.Lu)      
@Clark Zheng
恩,谢谢你的建议。
通过对job的周期执行时间进行调整,可以完成任何时间间隔内的数据库记录。只是觉得没那个必要,太消耗资源了,这个JOB也只是对存储过程改变得记录,并没有把之前的版本记录,也就是说无法通过这个记录来恢复。
当然,如果你想做到把改变得代码也记录下来,那是完全可行的。只是我在开发过程中用到这个日志的时候主要是在每次重要更新的时候。
并且我强烈要求自己及项目组员在写存储过程时加上修改日期与修改人的注释,所以我这里的需求就变成只要知道哪些被改变过就可以了。

  回复  引用  查看    
#9楼 2007-11-20 14:16 | Enzo      
我感觉还可以添加个check in/out的功能,当然不是每次都check in/out;
而是当修改者觉得这次修改有必要做个记录时,就使用check in/out,做个手动的日志记录,然后再结合你说的一天一次或一天两次。

这样做的目的是为了记录较大的改动或删除重写一个存储过程,方便以后查询。

  回复  引用  查看    
#10楼[楼主] 2007-11-20 15:04 | Carlwave-陆飞(Fei.Lu)      
@Enzo
同意你的看法,包括我现在也是改完后有一个人工的记录。

  回复  引用  查看    
#11楼 2007-12-01 10:38 | 热电厂[未注册用户]
哇,这篇文章太适合我了,我正好需要,楼主我要大力赞扬一下你,我看了那些评论,觉得各有个的道理,但是我不是用来开发用的,我是用来运行的时候记录一些非法删除记录的活动,监控用的,所以我不用什么版本控制软件. 我就是要楼主说的这个东西,但是我有些地方看不明白,所以请教楼主: "在数据库中新建一个Job,代码为exec sps_log_add"这段话我看不懂,是不是新建一个作业? 那么"代码为exec sps_log_add" 又是什么意思?怎样操作呢?
  回复  引用    
#12楼[楼主] 2007-12-01 15:50 | Carlwave-陆飞(Fei.Lu)      
@热电厂
对的,就是新建一个作业。这个存储过程sps_log_add运行一次就能对比数据库存储过程的变化。所以新建一个作业去定时运行这个存储过程即可。

  回复  引用  查看    



发表评论

昵称: [登录] [注册]

主页:

邮箱:(仅博主可见)

评论内容:

  登录  注册

[使用Ctrl+Enter键快速提交评论]

0 964216




相关文章:

相关链接: