目录
Setp1:基础背景了解
1.1-什么是存储过程(What)?
1.2-存储过程的优缺点(Why)
优点
缺点
Setp2:基本语法学习
2.1-变量(看代码和注释)
2.2-流程控制
2.2.1-IF判断
2.2.2-While的使用(计算1-100的和)
2.2.3-Case 多重选择的使用
Setp3-自定义存储过程(HOW)
3.1-创建存储过程(带参数)
3.2-使用存储过程
3.3-重命名存储过程
3.4-删除存储过程
Setp4-事务篇
4.1-事务的概述
4.2-事务的特征
4.3-事务的语法
4.4-存储过程中使用事务
4.4.1-测试表SQL代码
4.4.2-没有事务的情况下
4.4.3-使用事务的案例
工作了一段时间都还是很少用到存储过程,之前的项目根本没有去写存储过程,最近就用到了这个存储过程,最近的这个项目多数都是写的存储过程,这几天在学习,就写下了这篇文章!
存储过程(Stored Procedure)是在大型数据库系统中,一组为了完成特定功能的SQL 语句集,它存储在数据库中,一次编译后永久有效,用户通过指定存储过程的名字并给出参数(如果该存储过程带有参数)来执行它。存储过程是数据库中的一个重要对象。在数据量特别庞大的情况下利用存储过程能达到倍数的效率提升。
提示: 其中系统会自带有一些存储过程,存储过程用户也是可以自定义的,比如下面这句就是系统自带的存储过程
exec sp_tables; --查看表
1.效率高:存储过程编译一次后,就会存到数据库,每次调用时都直接执行。一般的SQL语句每执行一次就需要编译一次,所以使用存储过程提高了效率。
2.降低网络流量:存储过程编译好会放在数据库,我们在远程调用时,不会传输大量的字符串类型的SQL语句。
3.复用性高:存储过程往往是针对一个特定的功能编写的,当再需要完成这个特定的功能时,可以再次调用该存储过程。
4.可维护性高:当功能要求发生小的变化时,修改之前的存储过程比较容易,花费精力少。
1.存储过程难以调试:虽然有些DB提供了调试功能,但是一般的账号根本就没有那种权限,更何况线上的数据库不可能会给你调试权限的,再进一步就算能调试效果也比程序的调试效果要差很多。
2.可移植性差:当碰到切换数据种类的时候,存储过程基本就会出现白写。
3.灵活性差:业务数据模型变动,存储过程必须跟着业务代码一起更改,如果是大型项目,这种改动是空前的,是要命的。
DECLARE @age int = 16; --Declare @Local_Var data_type,这里初始设置了age为16;
PRINT @age; -- 打印16
SET @age = 18; -- 为age变量设置值为18
PRINT @age; -- 打印18
> 16
> 18
> OK
> 查询时间: 0s
注意事项1:(SET只能为单个赋值,SELECT可以为多个赋值)
DECLARE @age int,@name VARCHAR(20);
SELECT @age= 18,@name = 'Jack';
PRINT N'年龄:' + CAST(@age AS VARCHAR) + ' 姓名:' + @name;
> 年龄:18 姓名:Jack
> OK
> 查询时间: 0s
注意事项2:(看SQL后面的注释)
DECLARE @name1 VARCHAR(20) = 'TOM';
SET @name1 = (SELECT Name FROM dbo.student WHERE ID = 2);
PRINT '-------------'
PRINT 'SET:'+ @name1; --SET查询为空的时候,不会取上次的值,直接赋值为NULL
DECLARE @name VARCHAR(20) = 'TOM';
SELECT @name = Name FROM dbo.student WHERE ID = 2;
PRINT 'SELECT:'+@name; --SELECT查询为空的时候,赋值也为上次的给的值
> -------------
>
> SELECT:TOM
> OK
> 查询时间: 0.001s
提示:当SELECT 和SET都有初始值的时候,但是赋值的时候SET为空就会为空,然而SELECT不会,它会取上一次的值
DECLARE @age INT = 18;
IF @age < 18
BEGIN
PRINT '你未成年!';
END
ELSE IF @age = 18
BEGIN
PRINT '刚好成年,适当上网哟!';
END
ELSE
BEGIN
PRINT '你已经成年,可以进入!';
END
> 刚好成年,适当上网哟!
> OK
> 查询时间: 0s
DECLARE @i INT = 0,@NumSun INT = 0;
WHILE @i<=100 --开始循环
BEGIN
SET @NumSun=@NumSun+@i;
SET @i=@i+1; --自增一
END
print '结果是:' +CAST(@NumSun AS VARCHAR);
> 结果是:5050
> OK
> 查询时间: 0s
DECLARE @sex INT,@RSex VARCHAR(10)
SET @sex= 1;
SELECT @RSex=
CASE
WHEN @sex=1 THEN '男'
ELSE '女'
END
PRINT '性别:' + @RSex;
> 性别:男
> OK
> 查询时间: 0s
定义存储过程的语法
CREATE PROC[EDURE] 存储过程名
@参数1 数据类型 = 默认值,
…… ,
@参数n 数据类型 OUTPUT
AS
SQL语句 -- 多个SQL用BEGIN END
BEGIN
SQL语句 --就是这样用BEGIN END包裹起来
END
综合例子:(这里是为了演示运算和IF的使用所以我没有设置Id自增)
ALTER PROC up_addOrEditUser(
@Id INT, --定义变量为数字
@Name VARCHAR(20), --定义变量为字符串
@ResultId INT OUTPUT, --定义返回值在变量后面加上OUTPUT
@ResultMsg VARCHAR(20) OUTPUT --定义返回值
)
AS
IF @Id < 0 OR @Id = 0 --判断
BEGIN
SET @Id = (SELECT MAX(ID) FROM dbo.student); -- 赋值
IF(@Id IS NULL OR @Id = 0)
BEGIN
SET @Id = 1;
END
ELSE
BEGIN
SET @Id = @Id + 1;
END
INSERT INTO dbo.student(ID,Name) VALUES(@Id,@Name); -- SQL语句
SELECT * FROM dbo.student WITH(nolock);
SET @ResultMsg = '该操作是插入'; --赋值
END
ELSE
BEGIN
UPDATE dbo.student SET Name = @Name WHERE ID = @Id;
SET @ResultId = @@rowcount; --更新操作返回影响行数
SET @ResultMsg = '该操作是更新';
END
提示:其中的OUTPUT代表返回值 ,也可用retrun来返回,但是只能返回数字类型
DECLARE @RId INT;
DECLARE @Rmsg VARCHAR(20);
EXEC up_addOrEditUser 1,'BertXie',@RId OUTPUT,@Rmsg OUTPUT;
PRINT '返回ID:' + CAST(@RId AS VARCHAR) + '操作是:' + @Rmsg;
> 返回ID:1
> OK
> 查询时间: 0.002s
sp_rename oldName,newName;
DROP PROCEDURE xxx;
事务把所有的命令作为一个整体一起向系统提交或撤销操作请求,即这一组数据库命令要么同时成功要么同时失败。
通俗小讲解:简单来说明我们现在下单买一个手机,假如钱已经付了,但是商品模块出现了问题,没有订单详情和已支付详情,但是我们没有用事务机制,导致我们的钱被扣了,但是没有证明我们买到商品的条件,这个就是没有用事务造成的。
1.原子性(Atomicity):事务是数据库的逻辑工作单位,事务中包括的诸操作要么都做,要么都不做。
2.一致性(Consistency):事物完成时,数据必须是一致的,也就是说,和事物开始之前,数据存储中的数据处于一致状态。保证数据的无损
3.隔离性(Isolation):一个事务的执行不能被其他事务干扰。并发执行的各个事务之间不能互相干扰。
4.持续性(Durability):指一个事务一旦提交,它对数据库中数据的改变时永久性的。
-- 开启事务
start transaction; -- 或者 begin;
-- 提交事务
commit;
-- 回滚事务
rollback;
语法解释:事务以begin transaction开始的,以commit或rollback 结束,commit表示提交,既提交事务的所有操作。具体的说就是将事务中所有对数据库的更新写到磁盘上的物理数据中去,事务正常结束。Rollback表示回滚,在事务运行的过程中发生了异常操作,事务不能继续执行,系统将事务中对数据库的所有已完成的操作全部取消,回滚到事务开始时的状态。
CREATE TABLE [dbo].[Student] (
[Id] bigint IDENTITY(1,1) NOT NULL,
[StudentName] varchar(16) COLLATE Chinese_PRC_CI_AS NOT NULL,
[Score] decimal(18,1) NULL,
[Subject] varchar(16) COLLATE Chinese_PRC_CI_AS NULL
)
GO
INSERT INTO Student VALUES('BertXie',99.5,'数学');
提示:这里的StudentName加了一个唯一约束,等会方便测试
ALTER PROC upTransactionCase
AS
BEGIN
INSERT INTO Student VALUES('BertXie',100,'数学');
INSERT INTO Student VALUES('Jack',100,'数学');
END
--Msg 2627, Level 14, State 1, Server DESKTOP-BV542KL, Procedure upTransactionCase, Line 4
违反了 UNIQUE KEY 约束“snameKey”。不能在对象“dbo.Student”中插入重复键。重复键值为 (BertXie)。
语句已终止。
Procedure execution failed
[23000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]违反了 UNIQUE KEY 约束“snameKey”。不能在对象“dbo.Student”中插入重复键。重复键值为 (BertXie)。 (2627)
[01000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]语句已终止。 (3621)
时间: 0.002s
上面已经发生了异常但是并没有取消后面的操作,后面的Jack数据还是插入成功了
ALTER PROC upTransactionCase
AS
BEGIN
Set NOCOUNT ON;
Set XACT_ABORT ON;
BEGIN TRY --开始捕捉异常
BEGIN TRAN --开始事务
INSERT INTO Student VALUES('BertXie',100,'数学');
INSERT INTO Student VALUES('Tom',100,'数学');
COMMIT TRAN --提交事务
END TRY --结束捕捉异常
BEGIN CATCH --有异常被捕获
--在此可以使用xact_state()来判断是否有不可提交的事务,不可提交的事务
--表示在事务内部发生错误了。Xact_state()有三种值:-1.事务不可提交;
--1.事务可提交;0.表示没有事务,此时commit或者rollback会报错。
IF xact_state()= -1
BEGIN
ROLLBACK TRAN; --回滚事务
END
END CATCH --结束异常处理
END