一次SQLSERVER触发器编写感悟
背景:BOSS须要我写一个工厂採集端到server端的数据同步触发器,数据库採用的是sqlserver2008
需求:将多台採集机的数据同步到server中,假设採集端数据库与server数据库连接失败则将数据保存到记录表中
前期思路:从採集端创建server端的数据库链接,通过採集端的insert,update触发,同一时候往远程表写入
问题:因为初始接触sqlserver。对sqlserver触发器了解不深,查阅一些资料后写出了满足正常情况下(连接server数据库正常)的触发器。
create trigger
trig_sensor_shengyang
on dbo.sensor_test
for insert,update
as
begin
--假设原表没有该记录则插入该记录
IF NOT
EXISTS(SELECT
* FROM deleted)
begin
set NOCOUNT
ON;
begin tran
--insertopenrowset('sqloledb','XXX.XXX.XXX.XXX';'DBUSER';'DBPWD',bwdb.dbo.test)
--向server表插入该条数据
insert into
shengyang.bwdb.dbo.test
select *
from inserted
--同一时候向记录表中插入数据
insert into
dbo.test_bak
values((select
unid from
inserted),(select
sensor_id from
inserted),'create')
commit tran
end
else
--假设原表存在该记录则更新该记录
begin
set NOCOUNT
ON;
begin tran
--update openrowset('sqloledb','XXX.XXX.XXX.XXX';'DBUSER';'DBPWD',bwdb.dbo.test)
--更新server表记录
update shengyang.bwdb.dbo.test
set unid
= inserted.unid
from inserted
--推断假设记录表中存在对该条数据的记录,则更新记录表中的记录
--(针对记录表中同一时候存在对同一条数据的create,update,仅仅须要记录终于unid。
--假设有create终于仍然向server表create,假设是多次更新仅仅需记录最后一次更新)
if exists(select
* from
dbo.test_bak
where sensor_id=(select
sensor_id from
inserted))
begin
update dbo.test_bak
set unid=i.unid
from inserted
i
end
--假设记录表中不存在对该条数据的改动记录。则在记录标中插入该数据的update记录
else
begin
insert into
dbo.test_bak
values ((select
unid from
inserted),(select
sensor_id from
inserted),'update')
end
commit tran
end
end
可是因为须要考虑两方网络不通的情况。因此须要做异常处理。開始没查找到推断远程数据库连接的方法,因此想着直接通过try catch来实现(try块里面运行可能出现异常的——往远程server端写入的代码,catch块里写往採集端本地记录表中的代码)
create trigger trig_sensor_shengyang
on dbo.sensor_test after insert,update as
declare @unid varchar(20)
declare @sensor_id varchar(8)
declare @boolean varchar(1)
begin
set @unid = (select unid from inserted)
set @sensor_id = (select sensor_id from inserted)
--假设採集端原表没有该记录则插入该记录
IF NOT EXISTS(SELECT * FROM deleted)
begin
set NOCOUNT ON;
begin try
-- BEGIN TRAN
--推断server表中是否存在该记录
--假设不存在向server表插入该条数据
print '1111111111'
if not EXISTS(SELECT * FROM shengyang.bwdb.dbo.test where sensor_id=@sensor_id)
begin
--insert openrowset('sqloledb','XXX.XXX.XXX.XXX';'DBUSER';'DBPWD',bwdb.dbo.test)
insert into shengyang.bwdb.dbo.test select * from inserted
end
--否则更新server表数据
else
begin
update shengyang.bwdb.dbo.test set unid = inserted.unid from inserted where test.sensor_id = @sensor_id
end
--COMMIT TRAN
end try
--假设出错则向採集端记录表中插入数据
begin catch
print 'fail to insert this data to server'
rollback
-- print @@TRANCOUNT
-- IF @@TRANCOUNT > 0---------------推断有没有事务
-- BEGIN
-- ROLLBACK TRANSACTION ts----------回滚事务
-- END
insert into dbo.test_bak values (@unid,@sensor_id,'insert')
set @boolean = '1'
--EXEC insert_sensor_shengyang @unid,@sensor_id
end catch
-- if @boolean='1'
-- begin
-- print 'boolean'+@boolean
-- insert into dbo.test_bak values (@unid,@sensor_id,'insert')
-- end
end
else
--假设採集端原表存在该记录则更新该记录
begin
set NOCOUNT ON;
begin try
--update openrowset('sqloledb','XXX.XXX.XXX.XXX';'DBUSER';'DBPWD',bwdb.dbo.test)
--更新server表记录
update shengyang.bwdb.dbo.test set unid = inserted.unid from inserted where test.sensor_id = @sensor_id
end try
--假设出错,推断假设记录表中存在对该条数据的记录。则更新记录表中的记录
--(针对记录表中同一时候存在对同一条数据的create,update,仅仅须要记录终于unid,
--假设有create终于仍然向server表create,假设是多次更新仅仅需记录最后一次更新)
begin catch
if exists(select * from dbo.test_bak where sensor_id=@sensor_id)
begin
update dbo.test_bak set unid=i.unid from inserted i
end
--假设记录表中不存在对该条数据的改动记录,则在记录标中插入该数据的update记录
else
begin
insert into dbo.test_bak values (@unid,@sensor_id,'update')
end
end catch
end
end
可是不管如何,仅仅要出现异常。就会强制回滚。
此时假设在catch块之前提交,触发的仍然时候就会报错,而且无法将错误的记录插入异常记录表(运行不到),触发的原表记录能够写入。假设在catch块中rollback,然后将该记录插入异常记录表能够,可是同一时候回滚后触发的原记录也回滚丢失了。
假设在catch块中commit,也不行(catch块中默认回滚了全部事务),包含尝试了使用记录回滚点进行分段事务提交回滚还是无法解决。既不能commit,又不能rollback,这如何是好。。。。
。
。
随后BOSS提了个建议,通过存储过程中先做异常处理。推断server数据库是否连接成功。随即写了个存储过程,在存储过程中訪问远程数据库,定义一个变量初始值。catch块中改动这个值,然后把这个值作为存储过程返回值进行推断。
触发器:
create trigger trig_sensor_shengyang
on dbo.sensor_test after insert,update as
declare @unid varchar(20)
declare @sensor_id varchar(8)
declare @boolean varchar(1)
declare @ifconnected varchar(2)
begin
set @unid = (select unid from inserted)
set @sensor_id = (select sensor_id from inserted)
--调用存储过程推断远程连接server以及同步事务开启是否成功,返回1则表示失败
--sp_testlinkedserver [ @servername ] = servername
EXEC @ifconnected = [boolean_if_connected]
print @ifconnected
--假设远程连接成功
IF @ifconnected != 1
--假设採集端原表没有该记录则插入该记录
IF NOT EXISTS(SELECT * FROM deleted)
begin
set NOCOUNT ON;
begin try
--推断server表中是否存在该记录
--假设不存在向server表插入该条数据
if not EXISTS(SELECT * FROM shengyang.bwdb.dbo.test where sensor_id=@sensor_id)
begin
insert into shengyang.bwdb.dbo.test select * from inserted
end
--否则更新server表数据
else
begin
update shengyang.bwdb.dbo.test set unid = inserted.unid from inserted where test.sensor_id = @sensor_id
end
end try
begin catch
print 'failed to insert this data to server'
rollback
end catch
end
else
--假设採集端原表存在该记录则更新该记录
begin
set NOCOUNT ON;
begin try
--更新server表记录
update shengyang.bwdb.dbo.test set unid = inserted.unid from inserted where test.sensor_id = @sensor_id
end try
begin catch
print 'failed to update this date to server'
rollback
end catch
end
else
if exists(select * from dbo.test_bak where sensor_id=@sensor_id)
begin
begin tran
update dbo.test_bak set unid=i.unid from inserted i
commit tran
end
--假设记录表中不存在对该条数据的改动记录,则在记录标中插入该数据的update记录
else
begin
begin tran
insert into dbo.test_bak values (@unid,@sensor_id,'....')
commit tran
end
end
触发器:(非常easy。測试就是通过一个远程查询语句推断)
CREATE PROCEDURE boolean_if_connected
AS
BEGIN
declare @flag varchar(1)
begin try
set @flag='0'
select * from shengyang.bwdb.dbo.test;
end try
begin catch
set @flag='1'
print @flag
end catch
return @flag
end
这样的方法作为推断是可行的,可是。。。。。。
在触发器中调用的时候,假设远程server数据库连接不上了(測试关闭数据库服务),触发的时候直接就报错了,
其它的代码根本就没有运行。
终于。。
。
找到了推断远程链接的方法(此时的心情是激动的。
)
sp_testlinkedserver (Transact-SQL)
create trigger
trig_sensor_shengyang
on dbo.sensor_test
after insert,update
as
declare
@unid varchar(20)
declare
@sensor_id varchar(8)
declare
@boolean varchar(1)
declare
@ifconnected varchar(2)
begin
set @unid
=(select
unid from
inserted)
set @sensor_id
=(select
sensor_id from
inserted)
--调用存储过程推断远程连接server以及同步事务开启是否成功。返回则表示失败
--sp_testlinkedserver[ @servername ] = servername
EXEC @ifconnected
= [sp_testlinkedserver]shengyang
print @ifconnected
--假设远程连接成功
IF @ifconnected
!= 1
--假设採集端原表没有该记录则插入该记录
IF NOTEXISTS(SELECT
* FROM
deleted)
begin
set
NOCOUNT ON;
begin
try
--推断server表中是否存在该记录
--假设不存在向server表插入该条数据
if
not EXISTS(SELECT
* FROM
shengyang.bwdb.dbo.test
where sensor_id=@sensor_id)
begin
insert
into shengyang.bwdb.dbo.test
select *
from inserted
end
--否则更新server表数据
else
begin
update
shengyang.bwdb.dbo.test
set unid
= inserted.unid
from inserted
where test.sensor_id
= @sensor_id
end
end
try
begin
catch
print
'failed to insert to server'
rollback
end
catch
end
else
--假设採集端原表存在该记录则更新该记录
begin
set
NOCOUNT ON;
begin
try
--更新server表记录
update
shengyang.bwdb.dbo.test
set unid
= inserted.unid
from inserted
where test.sensor_id
= @sensor_id
end
try
begin
catch
print
'failed to update to server'
rollback
end
catch
end
else
if exists(select
* from
dbo.test_bak
where sensor_id=@sensor_id)
begin
begin
tran
update
dbo.test_bak
set unid=i.unid
from inserted
i
commit
tran
end
--假设记录表中不存在对该条数据的改动记录,则在记录标中插入该数据的update记录
else
begin
begin
tran
insert
into dbo.test_bak
values (@unid,@sensor_id,'....')
commit
tran
end
end
总结(用BOSS的语录):问题总是能找到解决方式的,仅仅要你摸清楚设计者的思路。所以一定要多想为什么,人家为啥要这么设计 !
一次SQLSERVER触发器编写感悟的更多相关文章
- SqlServer触发器的理解
SqlServer触发器是与表事件相关的特殊存储过程,它的执行不是由程序调用,也不是手工启动,而是由事件来触发.比如当对一个表进行操作( insert,delete, update)时就会激活它执行. ...
- SQLServer触发器调用JavaWeb接口
这几天接到一个需求需要吧不同系统的数据库进行同步,需要我做一个中间平台进行连接,瞬间就想到了触发器调用接口然后通过API进行传递再写入另一个数据库. sqlServer触发器调用JavaWeb接口 1 ...
- SqlServer触发器的创建与使用
前言 上期我们介绍了SqlServer的视图和存储过程创建与使用,这期我们介绍一下触发器. 有需要回顾的可以电梯直达看一下: SqlServer视图的创建与使用 SqlServer存储过程的创建与使用 ...
- SQLServer触发器的使用
创建: create trigger trigger_name on {table_name view_name} {for After Instead of } [ insert, update,d ...
- SQLServer存储过程编写规则
SQLServer编写规则 1. 存储过程 a) 在程序应用中,对于数据库“写”操作的功能通过存储过程来实现. b) 存储过程命名: SP_+表名(+功能名) 对于一个 ...
- SqlServer——触发器
一:触发器基本知识 1.首先必须明确以下几点: 触发器是一种特殊的存储过程,但没有接口(输入输出参数),在用户执行Inserted.Update.Deleted 等操作时被自动触发: 当触发的SQL ...
- SQLServer 触发器入门
阅读目录 一:触发器的优点 二:触发器的作用 三:触发器的分类 四:触发器的工作原理 五:创建触发器 六:管理触发器 概念: 触发器(trigger)是SQL server 提供给程序员和数据分析 ...
- sqlserver 触发器实例代码
定义: 何为触发器?在SQL Server里面也就是对某一个表的一定的操作,触发某种条件,从而执行的一段程序.触发器是一个特殊的存储过程. 常见的触发器有三种:分别应用于Insert , Update ...
- SqlServer触发器的基础知识
触发器的基础知识:create trigger tr_name on table/view{for | after | instead of } [update][,][insert][,][dele ...
随机推荐
- ccf 201803-4 棋局评估 (对抗搜索)
棋局评估 问题描述 Alice和Bob正在玩井字棋游戏. 井字棋游戏的规则很简单:两人轮流往3*3的棋盘中放棋子,Alice放的是“X”,Bob放的是“O”,Alice执先.当同一种棋子占据一行.一列 ...
- Redis(六)-数据类型
Redis支持五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合). String(字符串) string是redis最 ...
- python 7:del 列表指定元素、list.pop(索引)、list.remove(元素值)(删除列表指定元素,且不可再使用;默认索引-1,弹出指定列表元素,可再使用;移除列表指定第一个元素)
bicycles = ['trek', 'cannondale', 'redline', 'specialized'] print(bicycles) del bicycles[0] #删除指定列表元 ...
- PHP 二维数组排序 可以按指定 键值排序
<?php header("Content-Type:utf-8"); $arr = array( 0 => array( 'name' => '国际原油价格', ...
- CSS元素水平垂直居中的方法
1. 元素水平居中 1.1 设置父元素的属性 text-align: center; 说明:此属性只针对父元素的子元素为内联元素时有效,比如:img,input,select,button等(行内 ...
- jQuery 滑动及点击切换效果
效果图如下: 初始化 hover效果:滑动menuitem,‘首页’不变,字体颜色改变,有下划线展示. 即在动态添加boder-bottom,改变字体颜色颜色 .menuItem:hover{ bor ...
- Hadoop学习笔记(一)Hadoop的单节点安装
要想深入学习Hadoop分布式文件系统,首先需要搭建Hadoop的实验环境,Hadoop有两种安装模式,即单节点集群模式安装(也称为伪分布式)和完全分布式模式安装,本节只介绍单节点模式的安装,参考官方 ...
- AI:IPPR的模式生成-学习/训练方式(基本结构)
前言: 一个完备的模式识别系统,必然包含一个模式识别模型,此外还要附加一个评价模型,以及为了构建识别模型而构建的学习模型,并选择在学习模型中使用的学习方法. 否则 w=w 这样,)那样 ...
- DNN:逻辑回归与 SoftMax 回归方法
UFLDL Tutorial 翻译系列:http://deeplearning.stanford.edu/wiki/index.php/UFLDL_Tutorial 第四章:SoftMax回归 简介: ...
- 【sqli-labs】 less40 GET -Blind based -String -Stacked(GET型基于盲注的堆叠查询字符型注入)
提交,页面正常,说明是')闭合的 http://192.168.136.128/sqli-labs-master/Less-40/?id=1')%23 http://192.168.136.128/s ...