作为一名数据库管理员,在进行代码迁移之前,总是尽力给提交于开发环境的代码一个完整的面貌。但是,不得不承认,我不能保证不发生任何可能破坏开发系统的事情。当这种情况发生时,可能的补救措施是恢复到目标代码的前一版本,目标代码可能是存储过程、函数等等。

如果可能的话,你不想做但又不得不做的事情是从备份的数据库中恢复代码,但是如果备份的数据库存储在磁带上,这种方法可能因花费太长的时间而不能使用。如果数据库庞大的话,要花费相当长的时间来恢复,更不用说你还要找一台足够大的服务器来存储备份的文件。不过,还有更好的方法。

很久前我找到的一种解决方法是备份数据库代码到一个独立的数据表中,这样如果在我们开发的代码发生错误时,就可以从数据表恢复出错的过程或函数。这种方法确实节省了大量的时间。

在SQL Server 2000中,这种方法可以这样实现:对特别的数据库做一个完整的syscomments数据表备份,然后将备份的数据表放入档案表中。我通常保存最近两周的重要过程代码。利用这种技术唯一的麻烦是:如果代码对象十分大,那么可能要对代码进行重构。因为如果代码过大将会被存储到syscomments表中不同的行中,有时这可能是件令人感到头痛的事。

SQL Server 2005 新增加的众多功能之一是可以利用一个系统函数返回某个对象的完整代码,这个系统函数将使得存档你的过程代码变得十分简单。

OBJECT_DEFINITION

SQL Server 2005新增的系统函数OBJECT_DEFINITION根据提供给该函数的对象ID返回对象的TSQL代码。为了更好的理解这个函数的工作过程,让我举个例子。首先我们创建一个用户自定义函数,该函数的脚本如下:

CREATE FUNCTION udf_Multiply

 

(@Val1 INT,

 

@Val2 INT

 

)

 

RETURNS INT

 

AS

 

BEGIN

 

DECLARE @RetVal INT

 

SET @RetVal = (@Val1 * @Val2)

 

RETURN(@RetVal)

 

END

 

这是一个很简单的小函数。因为它仅仅处理两个参数,但是已足够为我们演示OBJECT_DEFINITION函数是如何工作。测试该系统函数的脚本如下:

DECLARE @ObjectID INT

 

SET @ObjectID = OBJECT_ID('udf_Multiply')

 

SELECT OBJECT_DEFINITION(@ObjectID)

 

在这个例子中,我们实际上用了两个系统函数。首先,我们要得到前面创建的udf_Multiply函数的OBJECT_ID,在SQL Server 数据库引擎中,OBJECT_ID是一个对象的系统标识符。然后我们将这个ID传给系统函数OBJECT_DEFINITION,这一系统函数将返回提供给它的ID对象的代码,即返回值是我们以前为udf_Multiply 函数写的TSQL代码。

既然我们对OBJECT_DEFINITION函数的工作原理有了很好的了解,接下来让我们看看如何利用这个函数来存档我们数据库中的过程代码。首先,运行列表A中的脚本程序在测试数据库中创建20个存储过程。

DECLARE @i INT

SET @i = 1

 

WHILE @i <= 20

BEGIN  EXECUTE     

( 'IF OBJECT_ID(''usp_TestProcedure'+@i + ''')>0           

DROP PROCEDURE usp_TestProcedure'+@i+'      '      )     

EXECUTE ( 'CREATE PROCEDURE usp_TestProcedure' + @i + '    

AS BEGIN PRINT ''The name of this procedure is '' +

CAST(OBJECT_NAME(@@PROCID) AS VARCHAR(20))  END' )     

SET @i = @i + 1

END

 

你将看到在上面的脚本中,我们使用了动态SQL语句。当创建动态SQl语句时,我习惯用系统存储过程sp_executesql,因为该过程能够很好地在系统中缓存SQL语句。但是,在我们这一例子中,EXECUTE命令就能很好地完成任务

现在我们的数据库中已经有了一些对象,我们可以创建用来存档数据库中存储过程需要的对象和代码。在列表B中的脚本可以为我们完成这项工作。

IF OBJECT_ID('CodeArchive','U')>0     

DROP TABLE CodeArchive

 

CREATE TABLE CodeArchive

(      ArchiveID INT IDENTITY(1,1) PRIMARY KEY,     

ObjectName SYSNAME,     

ObjectDescription VARCHAR(60),     

ObjectType CHAR(2),     

ObjectDefinition VARCHAR(MAX),     

ObjectID INT,     

CreationDate DATETIME,     

ModifiedDate DATETIME,     

EntryDate DATETIME DEFAULT(GETDATE())

)

 

INSERT INTO CodeArchive

( ObjectName, ObjectDescription,

ObjectType, ObjectDefinition,

ObjectID, CreationDate, ModifiedDate

)

SELECT so.name, so.type_desc, so.type,

OBJECT_DEFINITION(object_id),      

so.object_id, so.create_date, so.modify_date   

FROM      sys.objects so

WHERE      so.[type]

IN('C', 'D', 'P', 'FN', 'R', 'RF', 'TR', 'IF', 'TF', 'V')

 

存档方案首先要求有一个用来存储我们定义代码的表格,和在上面的表格脚本中看到的一样,我们将对象定义代码存入表格的ObjectDefinition域,这是一个VARCHAR(MAX)数据类型的域。VARCHAR(MAX)是SQL Server 2005新增的一种数据类型,它可以存储高达2GB的有效数据。这样我们就不在局限于文本数据类型或者将我们的数据保存在一个单个数据页上。这种数据类型存储我们的对象毫无问题。

在上面的脚本中关于插入CodeArchive表有几点值得注意的地方。首先是在查询中包含的数据类型,这些用于OBJECT_DEFINITION函数的对象类型将返回一个值。A列表中包含的。

对象类型列在下面供参考。其次是脚本调用的方法,我通常是利用SQL Server的预定任务调度法执行类似的脚本(你可以按照工作要求反复的运行脚本)。无论用什么调度方法,总之你需要按照一定的规则运行脚本,这样才能在需要时恢复你的过程代码。

OBJECT_DEFINITION函数用到的对象类型列表:

T:检查约束。

D:默认。

P:TSQL存储过程。

FN:TSQL数值用户自定义函数。

R:规则。

RF:复制过滤过程。

TR:TSQL触发器。

IF:TSQL内嵌函数。

TF:TSQL数值函数。

V:视图。

存档需求

希望本文对你有所帮助,如果你还没有使用过OBJECT_DEFINITION这个新函数,你最好亲自试一下。然而,在你的开发环境中设置一些代码备份系统,这样做的重要性在怎么强调也不为过。实际上,我拥有一个类似的备份系统用于我们的开发环境。

如果你能设置一个类似本文提到的恢复系统,就可以进行本地或远程备份你的过程代码,当需要恢复代码时,你将会很方便地进行,而不再用查找备份文件已找到所要恢复的代码。

利用OBJECT_DEFINITION函数来代码存档的更多相关文章

  1. 利用JavaScript函数对字符串进行加密

    加密.解密问题对我来说一直是很神秘的,感到神奇无比. 理论了解 前段时间看到关于利用JavaScript函数unescape()和escape()对字符串进行替换处理.通过查资料得知, escape( ...

  2. 【编程题目】请修改 append 函数,利用这个函数实现两个非降序链表的并集

    42.请修改 append 函数,利用这个函数实现(链表):两个非降序链表的并集,1->2->3 和 2->3->5 并为 1->2->3->5另外只能输出结 ...

  3. PHP获取毫秒时间戳,利用microtime()函数

    PHP获取毫秒时间戳,利用microtime()函数 php本身没有提供返回毫秒数的函数,但提供了一个microtime()函数,借助此函数,可以很容易定义一个返回毫秒数的函数.php的毫秒是没有默认 ...

  4. 20145311利用gdb调试汇编代码

    利用GDB调试汇编代码 首先编写c语言原代码,我使用的是同学分析过的代码 #include<stdio.h>short addend1 = 1;static int addend2 = 2 ...

  5. (转)Java程序利用main函数中args参数实现参数的传递

    Java程序利用main函数中args参数实现参数的传递 1.运行Java程序的同时,可以通过输入参数给main函数中的接收参数数组args[],供程序内部使用!即当你在Java命令行后面带上参数,J ...

  6. 利用freopen()函数和fc命令简化程序调试

    大家在参加ACM比赛或者参加c/c++实验技能竞赛的时候,如果遇到大量的输入和大量的输出时,调试起来很不方便.一来如果结果不正确的话,需要重复输入大量数据:二来如果大量输出的话,得仔细检查输出结果与正 ...

  7. 利用copy函数简单快速输出/保存vector向量容器中的数据

    如果要输出vector中的数据我们可以通过循环语句输出,更加简便的方法是利用copy函数直接输出,例子: #include "stdafx.h" #include <iost ...

  8. 让 Python 的1、数据库查询返回字典记录--- 2、利用zip函数将两个列表(list)组成字典(dict)

    让 Python 的数据库查询返回字典记录: https://yanbin.blog/python-database-query-return-dictionary-result/#more-9179 ...

  9. 利用foo函数的Bof漏洞攻击:构造攻击字符串

    利用foo函数的Bof漏洞攻击:构造攻击字符串 一.基础知识储备 objdump反汇编指令.gdb函数调试运行.Perl语言.|管道符 二.实验步骤 1. 通过反汇编了解程序功能及代码 ①反汇编查看文 ...

随机推荐

  1. sigprocmask, sigpending, sigsuspend的用法

    sigset_t set sigemptyset(&set) :清空阻塞信号集合变量 sigfillset(&set) :添加所有的信号到阻塞集合变量里 sigaddset(& ...

  2. Android Studio升级到0.8.1后怎样设置字体大小?

    升级到0.8.1后.打开设置字体大小页面.你会发现无论是Default还是Darcula,都不同意你改变字体的大小.事实上这个是由于这两个模式是Android Studio自带模式,所以不同意你修改, ...

  3. es8 --- 新特性

    ES8尚未发布(2017年1月),下面是它已经完成起草的一些特性: Object.values() Object.entries() padStart() padEnd() Object.getOwn ...

  4. 关于router-link的传参以及参数的传递

    1.路径:http://localhost:8081/#/test?name=1 <router-link :to="{path:'/test',query: {name: id}}& ...

  5. 简单理解javascript的闭包

    看过网上关于javascript的闭包的概念和分析,看完之后都是一头雾水,完全不懂,零度我本来就对于概念性的东西很烦躁,没办法,硬着头皮翻阅了很多的资料,总算理清了一点头绪,现在分享给大家,错误之处还 ...

  6. 59.C++与正则表达式

    regex_match 整个字符串是否匹配 (通过cmatch存储匹配的结果),match[0]代表整个匹配序列,match[1]代表第1个匹配后的子序列,match[2]代表第2个匹配后的子序列 代 ...

  7. sqlserver 小计合计总计

    SELECT CASE WHEN GROUPING(F1) = 1 THEN '总计'WHEN GROUPING(F1) = 0 AND GROUPING(F2) = 1 THEN  F1+'合计'W ...

  8. Qwt库的一个使用注意事项

    作者:朱金灿 来源:http://blog.csdn.net/clever101 一般debug版本的程序链接release版本的库是没有问题的.今天使用debug版本程序链接release版本的qw ...

  9. 37.Node.js工具模块---处理和转换文件路径的工具 Path模块

    转自:http://www.runoob.com/nodejs/nodejs-module-system.html Node.js path 模块提供了一些用于处理文件路径的小工具,我们可以通过以下方 ...

  10. SQL数值转字符串保留指定小数位

    IF EXISTS ( SELECT * FROM sysobjects WHERE xtype = 'fn' AND name = 'fn_NumberFormat' ) BEGIN DROP FU ...