]]>触发器简?/title>http://www.aygfsteel.com/gcw633/archive/2010/05/18/321303.html淡E的回?/dc:creator>淡E的回?/author>Tue, 18 May 2010 09:49:00 GMThttp://www.aygfsteel.com/gcw633/archive/2010/05/18/321303.htmlhttp://www.aygfsteel.com/gcw633/comments/321303.htmlhttp://www.aygfsteel.com/gcw633/archive/2010/05/18/321303.html#Feedback0http://www.aygfsteel.com/gcw633/comments/commentRss/321303.htmlhttp://www.aygfsteel.com/gcw633/services/trackbacks/321303.htmlINSTEAD OF 触发?br />
AFTER 触发器(也叫“FOR”触发器)会在触发 insert、update 或是delect 动作之后执行。例如,一?nbsp;Employees 表上?nbsp;AFTER 触发器会在在 Employee 表上执行一?nbsp;update 语句后激zR因此,AFTER 触发器只有在已插入一行或是多行和所有约束已被处理且通过后才触发。INSTEAD OF 触发器和 AFTER 触发器有本质上的不同Q因?nbsp;INSTEAD OF 触发器代替触发动作进行激发。就拿同L例子来说Q如果在 Emplyees 表上有一?nbsp;INSTEAD OF UPDATE 触发器和在这个表上执行一?nbsp;UPDATE 语句Q结果是q条 UPDATE 语句q不会改?nbsp;Employee 表中的Q何一行。相?q条 UPDATE 语句只有是ؓ了踢?nbsp;INSTEAD OF UPDATE 触发器,q个触发器可能会Q也可能不会改变 Employees 表中的数据?br />
因此Q怎么军_在合适的旉和位|放|?nbsp;INSTEAD OF 触发器呢Q有几个关键的因素在做决定是值得考虑的。AFTER 触发器多用在动作必须在表中数据发生改变之后才执行后情情况。比如,AFTER 触发器可以用于将Ҏ据作M变动的日志记录在一个相对独立的审计表中。INTEAD OF 触发器也能做同样的工作。但?nbsp;INSTEAD OF 触发器在q个情况下的效率比较低,因ؓ更新动作只能在将它发生的动作准确地记录在审计表之后才允许执行?br />
一般来_只要不媄响数据的修改QAFTER 触发器比 INSTEAD OF 触发器更有效率。在Ҏ据进行计或是对数据的修改作Z个整体提交或是作Z个整体回退的情况下QAFTER 触发器也是一个很好的选择。例如,存在q样一条规则:对在 Products 表的产品h的变动超q?0Q的必须回退。AFTER 触发器能很漂亮地完成q个工作Q它利用已插入同已删除的表中的品hg比较Q然后在有必要的时回滚事务。这些都?nbsp;AFTER 触发器的理想条gQ但有时 INSTEAD OF会更好些?br />
INSTEAD OF 触发器有一个很大的特点——就是它允许你在某个表或视图上用多个复杂的查询操作来代替单一的查询。跟 AFTER 触发器只能对表v作用不同QINSTEAD OF 触发器可以同时对表和视图起作用。我常常被问到怎么样去解决q种情况Q有一个多表组成的视图Q如何对该视图进行一ơ更新。如果视囑含有关键字段和包含有基本表的某些字段Q这只是单的更新基本表。但是,当有视图中包含有多个基本表示Q逻辑上的更新比单单一?nbsp;UPDATE 语句会更复杂。因此,你是怎么利用什么可以替代的工具来解册个问题的呢?其中一个方法就是将一个INSTEAD OF 触发器放在视图上。INSTEAD OF 触发器可以定义在一个或多个表上.INSTEAD OF 触发器就能{开在多个基本表中修改的范围. 例如Q如果一个视囑ְ Customers、Products、orders ?nbsp;OrderDteils {表合ƈ成一个视图,q利用视N过E序在屏q上来显C所有的数据。更新操作便允许用来代替q个视图Q假如存在一个这个样的视图:它包?nbsp;Northwind 数据库中的四个表Qƈ且被命名为vwCustomersOrdersOrderDetailsProductsQ它看v来像q样(Figure 1)Q?nbsp; Figure 1 q接 Customers 及其 Order Details 的视?nbsp; CREATE VIEW vwCustomersOrdersOrderDetailsProducts AS SELECT c.CustomerID, c.CompanyName, o.OrderID, o.OrderDate, od.UnitPrice, od.Quantity, od.Discount, p.ProductID, p.ProductName FROM Customers c INNER JOIN Orders o ON c.CustomerID = o.CustomerID INNER JOIN [Order Details] od ON o.OrderID = od.OrderID INNER JOIN Products p ON od.ProductID = p.ProductID GO vwCustomersOrdersOrderDetailsProducts 视图q接着四个表,q且每个表都暴露一个取样字Dc必记住的一ҎQ当你设计一个含?nbsp;INSTEAD OF UPDATE 的触发器Ӟ每个表的主关键字段包含在SELECT语句中是很有益的做法。即使这些字D在应用E序不会用到Q它们也以在 INSTEAD OF 触发器中用来定位要被修改的行,然后对基表作相应的修攏V假设你打算允许更新该视图以便按非关键字qo。更C码应该写?nbsp;INSTEAD OF UPDATE 触发器中Q让触发器去更新 Customers 表中?nbsp;CompnayName 列,Orders 表中?nbsp;OrderDate 列,Order Details 表的 UnitPrice ?nbsp;Quantity 列以及在 Products 表中?nbsp;ProductName 列。在q种情况下,使用 AFTER 触发器就不适合了,?nbsp;INSTEAD OF 触发器则是一个很好的选择Q参?nbsp;Figure 2Q?nbsp;Figure 2 ?nbsp;INSTEAD OF 触发器更新视?br />
CREATE TRIGGER tr_vwCustomersOrdersOrderDetailsProducts_IO_U ON vwCustomersOrdersOrderDetailsProducts INSTEAD OF UPDATE AS ?nbsp;更新 Customers UPDATE Customers SET CompanyName = i.CompanyName FROM inserted i INNER JOIN Customers c ON i.CustomerID = c.CustomerID ?nbsp;更新 Orders UPDATE Orders SET OrderDate = i.OrderDate FROM inserted i INNER JOIN Orders o ON i.OrderID = o.OrderID ?nbsp;更新 Order Details UPDATE [Order Details] SET UnitPrice = i.UnitPrice, Quantity = i.Quantity FROM inserted i INNER JOIN [Order Details] od ON i.OrderID = od.OrderID AND i.ProductID = od.ProductID ?nbsp;更新 Products UPDATE Products SET ProductName = i.ProductName FROM inserted i INNER JOIN Products p ON i.ProductID = p.ProductID GO 注意?nbsp;Figure 2 中的 INSTEAD OF UPDATE 触发器包含了四个 UPDATE 语句。每?nbsp;UPDATE语句目的都是Z对其中一个基表中的非关键字段q行修改。在 UPDATE 语句中包含了每个表中的关键字D对应于视图中的字段。这样就允许 UPDATE 语句在相应的表中定位对应的列q只对这些列作修攏V下面的 UPDATE 语句对 INSTEAD OF 触发器进行测试: UPDATE vwCustomersOrdersOrderDetailsProducts SET Quantity =100, UnitPrice =20, CompanyName =''''Fake Name'''', OrderDate =''''11/23/2001'''', ProductName =''''Widget'''' WHERE OrderID =10265 AND ProductID =17 如果你(通过视图或是表自w)查相应表中的|很明显,q些值已被更C。当Ӟ对INSTEAD OF 触发器作一些改变会使其有不同的l果。例如,不存在写一个触发器L变四个基表的需求,因此Q可以将触发器中的一个或是多?nbsp;UPDATE 语句删去。假?nbsp;INSTEAD OF 触发器仅仅是Z更新 Order Details 表的|q就会仅仅更新在 Order Details 表中的字D,而忽视Q何在其他上的修改。在q种情况下,?nbsp;Customers,Products 或是 Orders 表中不会产生M错误同时也不会发生Q何改变。当Ӟ如果q三个表中的某些字段发生改变的话Q会发生报错。如我呆会在q篇文章会讨论的一PUPDATE ?nbsp;COLUMNSQUPDATED 函数是个哪些字D发生改变的理想的方法?br />
Figure 2 也演CZ怎么写一个触发器修改多行记录。注意到 UPDATE 语句如何按关键字q接被插入的表和各个。这׃证更新是Ҏ有的行,q些行在视图中被原有?nbsp;UPDATE 语句修改。通过循环被插入表的记录行也能完成该操作。不怎么P通常避免使用游标是个好主意,其是在使用触发器时更应如此。SQL SERVER 被设计成以数据集的方式来处理数据Q而游标是Zơ处理一个数据行而设计的。在触发器中使用游标会降低程序的性能Q因此,最好能使用?nbsp;Figure 2 中那h有效代替Ҏ或用一个子查询?br />
另一个改?nbsp;INSERT OF UPDATE 触发器的Ҏ是使其在视囄 INSERT ?nbsp;DELETE 语句中激发。这也就意味着在适当的地方,触发器会实现 INSERT 或是 DELETE 的功能。但是必记隹的?nbsp;DELETE 可能会删除多个记录,q关键在于触发器是怎样写的。因此,查触发器的需求,在实C前进行测试,q些做法十分重要。INSERT OF UPDATE 触发器可写在视图中,因此它可插入一个新的顾客、订单、详l的订单和品。这个触发器也可以用来在插入一个新֮之前查这个顾客是否是新的(对其它记录的操作也是一?。当采用的是 INSTEAD OF 触发器时存在有许多机会,但是Q当Ӟ触发器是决相应的需求这才是它的本质?br />
通常Q当引用一张表?nbsp;UPDATE 语句试图去赋g个计型的,恒等型的或是旉戛_的列Ӟ会生一个错误,因ؓq些列的值必L由SQL SERVER来决定的。这些列必须被包含在UPDATE 语句中以便能满列不能ؓI的要求。但是,如果 UPDATE 语句?nbsp;INSTEAD OF 触发器引用一个视图,定义在触发器中的逻辑可以旁\掉这些列来避免错误的发生。ؓ了达到这个目的,触发器决不能试L新基表中相应列的?让它们远?nbsp;UPDATE 语句?nbsp;SET 从句)。当某一条被处理的记录来自被插入的表Ӟ计算型的Q恒{型的或是时间戳型的列可以用一个虚假g满不ؓI值的要求Q这ӞINSTEAD OF 触发器将忽略q些|正确的值由 SQL SERVER 讄?br />
更新分开的列 INSTEAD OF 触发器也很普遍地用于更新中计型的列。例如,假设存在有如下这样一个叫 vwOrdersOrderDetailsProducts 的视图: CREATE VIEW vwOrdersOrderDetailsProducts AS SELECT o.OrderID, o.OrderDate, od.UnitPrice * od.Quantity AS ExtendedPrice, p.ProductID, p.ProductName FROM Orders o INNER JOIN [Order Details] od ON o.OrderID = od.OrderID INNER JOIN Products p ON od.ProductID = p.ProductID GO q个视图揭示了一个计型的列叫ExtendedPriceQ这个列不能被直接被更新Q因为它不能其自己变ؓ表中独立的一列。虽然你可实现这样一个生意规则,在这个规则中ExtendedPrice通过q个视图来修改,Quantity列不应修改,但是UnitPrice可被修改(我知道这条规则有点奇怪,但我可以忍受q点)。可以写一个INSTEAD OF UPDATE触发器来增强q条生意规则Q其代码如下所C: CREATE TRIGGER tr_vwOrdersOrderDetailsProducts_IO_U ON vwOrdersOrderDetailsProducts INSTEAD OF UPDATE AS UPDATE [Order Details] SET UnitPrice = i.ExtendedPrice / Quantity FROM inserted i INNER JOIN [Order Details] od ON i.OrderID = od.OrderID AND i.ProductID = od.ProductID GO q些代码揭示了怎样用一个在INSTEAD OF 触发器中的逻辑来代替对一个计型列的更新。假设一个品在一张特定的定单表中Quantity?00而ExtendedPrice要更Cؓ200Q这时新的UnitPrice值就变ؓ2。在q种情况下,在执行一个对ExtendedPrice列进行修改的UPDATE语句Ӟ最l的l果是UnitPrice被赋为ExtendedPrice除以Quantity的商。下面的代码可以用来试q种情况Q?nbsp;UPDATE vwOrdersOrderDetailsProducts SET ExtendedPrice =200 WHERE OrderID =10265 AND ProductID =17 查改?br />
在INSTEAD OF和AFTER触发器中都有UPDATE和COLUMNSQUPDATE功能Q这二种功能允许p发器军_哪些字段p发器的语句来改变。例如,下面的触发器LM对Employees表中的lastname字段q行修改。在q里QUPDATE功能用来军_对哪些对字段的修改可以执行。如果超出发生了改变Q而又是不允许修改的)׃产生一个错误。PAISERR OR功能和事务就会回退Q回退会撤消所做的M修改。UPDATE功能都可以在AGTER触发器和INSTEAD OF触发器中工作Q而不是在外部工作?nbsp;CREATE TRIGGER tr_Employees_U on Employees AFTER UPDATE AS IF UPDATE(lastname) BEGIN RAISERROR (''''cannot change lastname'''', 16, 1) ROLLBACK TRAN RETURN END GO UPDATE功能是ؓ了判断单一列是否被INSERT或是UPDATE语句修改q。UPDATE(?是一个用来检更新的标准的方法。但是当需要用来他多列是否受到INSERT或UPDATE语句的媄响时变得更低效率。而这恰恰是COLUM_UPDATE功能的一个亮炏VCOLUMN_UPDATE功能q回一个位掩码来判断特定的列是否被修改q。位掩码是包含在被表中被修改的列中的一个比特,目的是ؓ了在表模式中定义q些列。如果一行修改,q比特位的值就?Q否则ؓ0。不像从叛_左地d节的常规ҎQ位掩码是从左往双。例如,下面的代码提CZ一个在Order Details表中的触发器Q这个触发器是ؓ了检Quantity和UnitPrice二个字段是否被修改过?nbsp;CREATE TRIGGER tr_OrderDetails ON [Order Details] AFTER UPDATE AS IF (COLUMNS_UPDATED() =12) BEGIN RAISERROR (''''Cannot change both UnitPrice and Quantity at the same time'''', 16, 1) ROLLBACK TRAN END GO 如果q个字段都被修改了,׃产生一个错误,同时事务也将回滚。就拿Order Details表来_COLUMN_UPDATED功能q回代表Order Details表中字段的五个字节。只要第三和W四个字D被修改Q上面这U情况就会发生,它检这些位是不是已赋gؓ1.当第三和W四位都打开的庆Q它如Q?/span>00110。L因这个位掩码代表2ơ幂Q第一位表C?Q第二位表示2Q第三位表示4Q第四位表示8Q第五位表示16Q是的,q是和正怺q制数相反的序Q;因此只表CUnitPrice和Quantity字段被修改位掩码的gؓ00110Q这个gؓ12Q?/span>4+8Q。请注意Q这个触发器只有在UnitPrice和Quantity字段被修Ҏ会将事务回滚。如果其他字D修改的话,位掩码就会不一P因此׃{于整数12了。如果触发器被修改ؓ止对这二个字段修改即对其他字D也止Q它可重新~写为如? ALTER TRIGGER tr_OrderDetails ON [Order Details] AFTER UPDATE AS IF (COLUMNS_UPDATED() >=12) BEGIN RAISERROR (''''Cannot change both UnitPrice and Quantity at the same time'''', 16, 1) ROLLBACK TRAN END GO h意 COLUMN_UPDATED 功能现在是怎么L位掩码的但是否于{于12.如果你修改联pUnitPrice,Quantity和Discount列的话,位掩码就变ؓ00111Q代表整?8Q?/span>4+8+16Q。当在一个表中不止有8个列Ӟq个函数׃先返回包含了前八列的五个字节Q而第从第九到W十六就会在W二个字节中Q以此类推。这个功能在军_允许哪些列可以被更新比只对第列进行更新的UPDATE功能更有用?br />
如前期所描述的一P在Ş特定条件规则条件下Q触发器可以回滚事务Q当一个含有回滚的触发器在SQL脚本中执行时Q整个处理将被取消。因此,被触发动作修改的的所有数据将由ROLLBACK TRANSACION语句回滚。虽然一个回滚ƈ不阻止触发执行SQL语句所有在ROLLBACK TRANSACION语句后面的语句都会被执行 。特别是当一个触发器l箋执行回滚语句后面的语句时Q在回滚以后所作的M修改都不会回滚。发生这U情冉|因ؓ当在触发器中执行了一个ROLLBACK TRANSACTIONӞ所以有的事务都被取消。因此当一个新的查询语句被执行Ӟ一个新的不同与以前事务的事务就重新开始。因此,一般情况下Q徏议不要在ROLLBACK TRANSACTION语句后放|Q何语句?br />
像回滚不会自动退发器一P它也不会自动产生错误。如果必d滚且必会产生错误QPAISERR OR语句应该攑֜退发器代码前,紧跟在回滚后. l束?nbsp; 在对同一个表的数据所作的修改会激发同LINSTEAD OF触发器,q种触发器不会递归调用。因?如果在Emplyee表中有一个INSTEAD OF触发?Pq个触发器是用来更新Employee表的Q这q不会发生调用同一个INSTEAD OF触发器。如果允许这U递旭的话Q更新应该被止。INSTEAD OF触发器和AFTER触发器的另一个不同在于Text,Ntext和Image列可以出现在被更新和删除的表的触发器中。这些二q制列会以如VARCAHAR数值出现在更新和删除表的触发器中,q种是可行的Q但qƈ不是他们原始的数据类型?br />
q有一个有用的存储q程-sp_helptrigger pȝ存储q程-来检触发器。他q回定义在表上的触发器类型,q个表是传递给存储q程的。用q种ҎQ你可以看到哪些触发器和某个表有兌Q什么操作动触发q些触发器和判断触发器是AFTER触发器还是INSTEAD OF触发器?nbsp; 在最后二栏中Q我已经讨论了AFTER触发器和INSTEAD OF触发器的多个斚w。当Ӟq有许多情Ş下他们很有用Q还有许多用时Z没有提出来。当一个触发器必须查询其他表的情况下,触发器就会没有什么效率了。在q些情况下,触发器的性能和触发动作会受到很大损害。当使用得好Ӟ触发器是一个很的工具Q但是必M证在使用他们之前必须对你的程序作一个全面的试?nbsp;
]]>ssh调用存储q程http://www.aygfsteel.com/gcw633/archive/2010/05/18/321284.html淡E的回?/dc:creator>淡E的回?/author>Tue, 18 May 2010 07:48:00 GMThttp://www.aygfsteel.com/gcw633/archive/2010/05/18/321284.htmlhttp://www.aygfsteel.com/gcw633/comments/321284.htmlhttp://www.aygfsteel.com/gcw633/archive/2010/05/18/321284.html#Feedback0http://www.aygfsteel.com/gcw633/comments/commentRss/321284.htmlhttp://www.aygfsteel.com/gcw633/services/trackbacks/321284.html
create PROCEDURE [dbo].[GetUserS] ( @empno nvarchar(32),--输入参数 @pwd nvarchar(32)--输入参数 ) AS BEGIN select * from [user] where empno=@empno and pwd=@pwd END GO --q个存储q程输出的结果是名字和密码相W合的整一条记?/span>
数据讉K层中的代?br />
publicint getUser(String name, String pass) { // TODO Auto-generated method stub Session session=this.getSession(); String sql1="{call GetUserS(?,?)}"; Query query=session.createSQLQuery(sql1); query.setString(0, name); query.setString(1, pass); List list =query.list(); if(list.size()>0){ return1; } return0; }