SQL Server 添加Delete操作回滚日志方式

我们在操作表的时候难免会遇到误删除,或者删掉的数据还想恢复的情况。

也许细心的朋友会用begin tran rollback/commit 这种事务来避免出现失误,但这并不是最保险的。

如果提交了事物发现删错了或者忘记提交从而导致表被锁,这些问题总是不可避免的。

废话不多说了,下面直接进入正题,通过触发器记录删除日志,避免误删除带来的尴尬。

下面这段sql粘过去直接运行,建立一个存储过程:

create procedure [dbo].[sp_delete_log]
 @tablename varchar(50)
as
begin
	set nocount on;
 if not exists(select * from sys.tables where name = @tablename and type = 'u' )
	begin
		print'error:not exist table '+@tablename
		return
	end
	if (@tablename like'backup_%' or @tablename='update_log' )
	begin
		--print'error:not exist table '+@tablename
		return
	end
	--================================判断是否存在 update_log 表============================
	if not exists(select * from sys.tables where name = 'update_log' and type = 'u')
		create table update_log
		(
			updateguid varchar(36),
			updatetime datetime,
			tablename varchar(20),
			updatetype varchar(6),
			rollbacksql varchar(1000)
		)
	--=================================判断是否存在 backup_ 表================================
	if not exists(select * from sys.tables where name = 'backup_'+@tablename and type = 'u')
	begin
		--declare @sql varchar(500)
		--set @sql='select top 1 newid() as [updateguid],* into backup_'+@tablename+' from '+ @tablename+'
		--		 delete from backup_'+@tablename
		--select @sql
		--exec(@sql)
		declare test_cursor cursor for
		select column_name,data_type,character_maximum_length from information_schema.columns 
		where table_name=@tablename
		open test_cursor
		declare @sqltb nvarchar(max)=''
		declare @column_name nvarchar(50),@data_type varchar(20),@character_maximum_length int
		fetch next from test_cursor into @column_name,@data_type,@character_maximum_length
		while @@fetch_status=0
		begin
			set @sqltb=@sqltb+'['+@column_name+'] '+@data_type+case isnull(@character_maximum_length,0) when 0 then '' when -1 then '(max)' else'('+cast(@character_maximum_length as varchar(10))+')' end+','
			fetch next from test_cursor into @column_name,@data_type,@character_maximum_length
		end
		set @sqltb='create table backup_'+@tablename+' (updateguid varchar(36),'+substring(@sqltb,1,len(@sqltb)-1)+')'
		exec (@sqltb)
		close test_cursor 
		deallocate test_cursor
	end
	--======================================判断是否存在 delete 触发器=========================
	if not exists(select * from sys.objects where name = 'tg_'+@tablename+'_delete' and type = 'tr')
	begin
		declare @sqltr nvarchar(max)
		set @sqltr='
			create trigger tg_'+@tablename+'_delete
				on '+@tablename+'
				after delete
			as 
			begin	
				set nocount on;
				--==============================获取guid==========================================
				declare @newid varchar(36)=newid()
				--==============================将删掉的数据插入备份表============================
				insert into [dbo].[backup_'+@tablename+']
				select @newid,* from deleted
				--==============================记录日志和回滚操作的sql===========================
				--*********************生成列名**********************
				declare @column nvarchar(max)=''''
				select @column+='',[''+column_name+'']'' from information_schema.columns
				where table_name='''+@tablename+''' 
				and columnproperty(object_id('''+@tablename+'''),column_name,''isidentity'')<>1 --非自增字段
				set @column=substring(@column,2,len(@column))
				insert into [dbo].[update_log]
				select @newid,getdate(),'''+@tablename+''',''delete'',''insert into '+@tablename+' select ''+@column+'' from backup_'+@tablename+' where updateguid=''''''+@newid+''''''''
			end
			'
		exec(@sqltr)
	end
end

接着我们新建一张测试表,并且随便往表中插入两组数据:

 create table test 
 (
 id int,
 name varchar(10),
 msg varchar(10)
 )
 insert into test
 select 1,'aa','hahah'
 union all 
 select 2,'bb','heihei'

下面执行这个sp,在给test表添加回滚日志:

exec sp_delete_log 'test'

细心的你不难发现,这时候数据库里面应该会多出两张表:

然后我们删掉一条数据:

delete from test where id=1

再查看那两张表:

没错,这时候日志表里有数据了,然后我们把 update_log 表中的 rollbacksq l这一列对应的值copy出来执行一下:

insert into test select [id],[name],[msg] from backup_test where updateguid='b0cbbc4f-3432-4d4f-9e17-f17209bf6745'

别copy我上面这段sql,因为guid肯定是不一样的!

然而,数据恢复了:

最后,delete日志的介绍就结束了,唯一的不满足的是只能作用在delete 操作,其实update 操作也同样需要这样的回滚日志。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持www.887551.com。如有错误或未考虑完全的地方,望不吝赐教。

(0)
上一篇 2022年3月21日
下一篇 2022年3月21日

相关推荐