数据库工程开发秘籍之TSQL 存储过程user stored procedure的概念与案例实战
TSQL存儲過程概念與案例實戰
存儲過程
存儲過程由一個或多個 T-SQL 語句或對.NET公共語言運行時 (CLR) 方法的引用所構成的一組程序塊。這里的T-SQL語句包括執行DDL、DML語句、應用臨時表、動態SQL、定義異常處理等。但是相比于函數,它不能嵌套在查詢里,但它可以調用其它的存儲過程,即存儲過程可以相互調用。
存儲過程和常見的程序語言類似,可以指定輸入和輸出參數。SQL Server通過緩存存儲過程的執行計劃進而達到節約時間、降低CPU、內存的目的。
存儲過程相對于在應用端實現業務邏輯有以下好處:
1 通過封裝實現重用性和邏輯復雜性的隱藏。僅需要通過存儲過程的修改(alter procedure)就能應用新的邏輯。
2 減少網絡的傳輸,這是因為存儲過程即存儲在數據庫里,而如果是應用程序方式訪問數據庫識別有網絡傳輸的成本。
3 存儲過程可以提供對數據庫進行安全的訪問,即賦予了執行存儲過程的用戶不能直接訪問底層的數據庫對象,這種隔離對數據庫提供了保障。
補注:盡管存儲過程有這些優點,但實際應用程序封裝在Service(服務層),其對應的是某些單獨的SQL邏輯,而如果都放在存儲過程則會出現靈活性差、代碼難維護的情況。
普通存儲過程
假設我們有一張tb_user表,有兩個字段id,name,如果我想通過傳參數的形式給這張表插入數據,那么我們可以通過存儲過程來實現。這里id需要沿著tb_user的最大的值往下自增,自增間隔是1。
SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO ALTER PROCEDURE [dbo].[usp_useradd_MS] (@username VARCHAR(100)) AS DECLARE @max_id int=0 DECLARE @has int=0 BEGIN SELECT @max_id=max(id) FROM tb_user ; SELECT @has=1 FROM tb_user WHERE name = @username;IF @has =0BEGININSERT INTO tb_user VALUES(@max_id+1,@username);END;END; GO--調用,可選用下列任一方式執行 exec usp_useradd_MS 'Mike' exec usp_useradd_MS @username='John' --驗證結果 SELECT * FROM tb_user;存儲過程與動態SQL
所謂動態SQL即SQL的內容是靈活的,是通過字符串拼接出來的,可以理解是不固定的。比如有一個需求,我們想通過查詢指定表的字段名并以列的形式展示出來,這里就可以通過存儲過程結合動態SQL來實現。因為每次傳過來的參數即表名是不固定的,所以需要一個字符串變量拿到參數里的值再拼接成最終的sql(相對于翻譯一下),再去數據庫里執行。
CREATE PROCEDURE [dbo].[usp_getColumnsBycolumn]( @tabname VARCHAR(100)) AS DECLARE @sql VARCHAR(8000) DECLARE @STRING VARCHAR(500) BEGIN SELECT @sql= ISNULL(@sql+',','')+'['+CAST(COLID AS VARCHAR(12))+']' FROM SYSCOLUMNS WHERE ID = OBJECT_ID(@tabname) GROUP BY COLID SET @STRING='SELECT * FROM (SELECT NAME,COLID FROM SYSCOLUMNS WHERE ID=OBJECT_ID('''+@tabname+'''))A pivot (MAX(NAME) for COLID in('+@sql+'))t' EXEC(@STRING) END GO --調用及結果 exec usp_getColumnsBycolumn 'tb_user'存儲過程內調用存儲過程
存儲過程里是可以調用其它存儲過程的,有時一些復雜的邏輯需要多個存儲過程結合一起才能實現最終效果。
CREATE PROCEDURE [dbo].[usp_getColumnsByonecolumn]( @tabname VARCHAR(100)) AS DECLARE @tab Table (colid varchar(100),colname varchar(20)) BEGIN INSERT INTO @tab exec usp_getColumnsBycolumn @tabname SELECT colid FROM @tab END --調用 exec usp_getColumnsByonecolumn 'tb_user' -- 結果注意:我們不可以把存儲過程包裹在子查詢里,即如下方式查詢存儲過程的結果是不支持的。
SELECT?*?FROM(exec?usp_getColumnsBycolumn?'tb_user')A
系統函數查看存儲過程的定義
可以通過內置的系統函數sp_helptext查看存儲過程的文本定義。
sp_helptext @objname = N'usp_getColumnsByonecolumn' #結果,存儲過程的文本定義見下: CREATE PROCEDURE [dbo].[usp_getColumnsByonecolumn]( @tabname VARCHAR(100)) AS DECLARE @tab Table(colid varchar(100), colname varchar(20)) BEGIN INSERT INTO @tab exec usp_getColumnsBycolumn @tabname SELECT colid FROM @tab END存儲過程的安全性
存儲過程跟表、視圖一樣首先用戶和角色,賦予EXECUTE權限后才能執行。特別的,如果過程里用到非dbo的schema(架構)那么在賦予存儲過程權限后也要將該架構下表的訪問權限賦予用戶,否則存儲可以執行但是會報底層表訪問權限的錯誤。
CREATE LOGIN db_loginuser WITH PASSWORD = 'D#2$3)5b'; GO CREATE USER db_user FOR LOGIN db_loginuser; GO EXECUTE AS LOGIN = 'db_loginuser'; SELECT SUSER_NAME() AS [login], USER_NAME() AS [user]; exec usp_useradd_MS 'Alice'?
REVERT; SELECT SUSER_NAME() AS [login], USER_NAME() AS [user]; GRANT EXEC ON dbo.usp_useradd_MS TO db_user; EXECUTE AS LOGIN = 'db_loginuser'; SELECT SUSER_NAME() AS [login], USER_NAME() AS [user]; exec usp_useradd_MS 'Alice'?
REVERT; SELECT * FROM tb_user注:針對sa、dbo無法執行,即無法通過下列的語句切換到sa用戶
EXECUTE?AS?LOGIN?=?'sa';
EXECUTE?AS?LOGIN?=?'dbo';
可通過REVERT;語句切換到上一次的用戶執行環境。
存儲過程與事務
事務是一個工作整體,它包含一個或多個操作數據(可能還包括數據結構)的活動。比如我們建表的DDL語句就是一個事務,要么建表成功要么失敗,不存在中間狀態。事務具有ACID性,其中A(atomicity)即原子性、C(consistency)即一致性、I(isolation)隔離性、D(durability)持久性。
SQL Server事務分為隱性事務和顯性事務的,如果是隱性的可通過SET IMPLICIT_TRANSACTIONS ON;開關打開該選項,在該模式下只需要在要操作的事務的尾部編寫commit或者rollback即可提交或者回滾事務,而不用在事務開頭寫begin tran。相對的顯式事務需要在事務前后定義諸如BEGIN TRAN … COMMIT TRAN(ROLLBACK TRAN)
隱式事務的例子:
SET IMPLICIT_TRANSACTIONS ON select @@TRANCOUNT INSERT INTO tb_user VALUES(110,'Philips') select @@TRANCOUNT -- 注:以上代碼需要一起執行。 -- 查看插入的數據 SELECT * FROM tb_user A WHERE A.name = 'Philips' --這里如果回滾則數據不存在。 ROLLBACK以回滾為例演示在存儲過程里如何使用事務。如果傳入的參數(用戶名)是'Lily'則回滾,其它則插入并提交事務。
CREATE PROCEDURE [dbo].[usp_useradd_MS_trans](@username VARCHAR(100)) AS BEGIN print @username; if @username='Lily' BEGIN BEGIN TRAN exec usp_useradd_MS @username ROLLBACK TRAN END ELSE BEGIN exec usp_useradd_MS @username END END GO -- 執行與結果 EXEC usp_useradd_MS_trans 'Lily' EXEC usp_useradd_MS_trans 'Tim' SELECT?*?FROM?tb_user?A?WHERE?A.name?=?'Lily' SELECT?*?FROM?tb_user?A?WHERE?A.name?=?'Tim'總結
以上是生活随笔為你收集整理的数据库工程开发秘籍之TSQL 存储过程user stored procedure的概念与案例实战的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: FRM考试哪些人适合报名?有哪些用处?
- 下一篇: 10派7元是什么意思