数据库中事物、存储过程、触发器、索引、临时表 的简单应用

本文介绍了数据库中的关键概念,包括事务的ACID特性,例如原子性、一致性、隔离性和持久性。详细讲解了如何在转账问题中应用事务。此外,还阐述了存储过程的创建和调用,以及聚集和非聚集索引的作用,强调了索引对查询速度的影响。最后,提供了创建不同类型的索引的示例。
摘要由CSDN通过智能技术生成

1. 事物的基本操作

转账问题:

    假定钱从A转到B,至少需要两步:

    • A 的资金减少
    • 然后 B 的资金相应增加   
create table bank
(
	cId char(4) primary key,
	balance money,			--余额
)
alter table bank
add constraint CH_balance check(balance >=10)
go
--delete from bank
insert into bank values('0001',1000)
insert into bank values('0002',10)
go

update bank set balance=balance-1000 where cid='0001'
update bank set balance=balance + 1000 where cid='0002'

--查看结果,注意是否会出现问题!

    SELECT * FROM bank

   注意约束:金额不能小于10


事务的ACID特性:

事务是作为单个逻辑工作单元执行的一系列操作。一个逻辑工作单元必须有四个属性,称为原子性、一致性、隔离性和持久性(ACID)属性,只有这样才能成为一个事务。

原子性:事务必须是原子工作单元;对于其数据修改,要么全都执行,要么全都不执行。

一致性:事务在完成时,必须使所有的数据都保持一致状态。在相关数据库中,所有规则都必须应用于事务的修改,以保持所有数据的完整性。事务结束时,所有的内部数据结构(如B树索引或双向链表)都必须是正确的。

隔离性:由并发事务所作的修改必须与任何其他并发事务所作的修改隔离。事务识别数据时数据所处的状态,要么是另一并发事务修改它之前的状态,要么是第二个事务修改它之后的状态,事务不会识别中间状态的数据。这称为可串行性,因为它能够重新装载起始数据,并且重播一系列事务,以使数据结束时的状态与原始事务执行的状态相同。

持久性:事务完成之后,它对于系统的影响是永久性的。该修改即使出现系统故障也将一直保持。


语法步骤:
开始事务: BEGIN TRANSACTION        开启事务
事务提交: COMMIT TRANSACTION    --提交操作
事务回滚: ROLLBACK TRANSACTION --取消操作
l 判断某条语句执行是否出错:
全局变量 @@ERROR
@@ERROR 只能判断当前一条 T-SQL 语句执行是否有错,为了判断事务中所有 T-SQL 语句是否有错,我们需要对错误进行累计;

         例:SET @errorSum=@errorSum+@@error


SET IMPLICIT_TRANSACTIONS { ON | OFF } 
如果设置为 ON,SET IMPLICIT_TRANSACTIONS 将连接设置为隐式事务模式。如果设置为 OFF,则使连接恢复为自动提交事务模式。

select * from bank

--使用事务
begin transaction
declare @error int
set @error = 0
update bank set balance=balance-1000 where cid='0001'
set @error = @error + @@error
update bank set balance=balance + 1000 where cid='0002'
set @error = @error + @@error
if @error != 0
	rollback transaction
else
	commit transaction
go
select * from bank


2. 存储过程的简单操作

     存储过程 --- 就像数据库中运行方法 ( 函数 )。 存储过程可以使得对数据库的管理、以及显示关于数据库及其用户信息的工作容易得多。存储过程是 SQL 语句和可选控制流语句的预编译集合,以一个名称存储并作为一个单元处理。存储过程存储在数据库内,可由应用程序通过一个调用执行,而且允许用户声明变量、有条件执行以及其它强大的编程功能。
优点:
      执行速度更快 – 在数据库中保存的存储过程SQL语句都是编译过的
      允许模块化程序设计 – 类似方法的复用
     提高系统安全性 – 防止SQL注入
     减少网络流通量 – 只要传输 存储过程的名称
系统存储过程:
    由系统定义,存放在master数据库中
    名称以“sp_”开头或”xp_”开头,自定义的存储过程可以以usp_开头
创建自定义存储过程

    CREATE PROC[EDURE] 存储过程名

    @参数数据类型=默认值,

    @参数数据类型=默认值OUTPUT

    AS

      SQL语句

参数说明:
  • 参数可选(有默认值)
  • 参数分为输入参数、输出参数
  • 输入参数允许有默认值
EXEC   过程名  [ 参数 ]
调用带参数的存储过程

   无参数的存储过程调用:

        l Exec usp_upGrade

   有参数的存储过程两种调用法:

        l EXECusp_upGrade2 60,55 --- 按次序
        l EXECusp_upGrade2 @ english =55,@math=60-- 参数名

   参数有默认值时:

        l EXEC usp_upGrade2 -- 都用默认值
        l EXEC usp_upGrade2 -- 第一个用默认值
       l EXEC usp_upGrade2 1,5  -- 不用默认值
实现分页的存储过程
create proc usp_GetAreaPage
@PageIndex int =3,  --当前页码
@PageSize int = 10  --页容量
as
begin
select * from (select row_number() over (order by BID) as rownum, * from [BOOK].[dbo].[book]) as t
where t.rownum between @pageSize*(@PageIndex-1) and @pageSize*@pageIndex
end

exec usp_GetAreaPage 1,2


3. 触发器
触发器的作用:自动化操作,减少了手动操作以及出错的几率。
触发器是一种特殊类型的 存储过程 ,它不同于前面介绍过的一般的存储过程。 SQL 内部把触发器看做是存储过程但是 不能传递参数
一般的存储过程通过存储过程名称被直接调用,而触发器主要是 通过事件进行触发而被执行
触发器是一个功能强大的工具, 在表中数据发生变化时自动强制执行 。触发器可以用于 SQLServer 约束、默认值和规则的完整性检查,还可以完成难以用普通约束实现的复杂功能
那究竟何为触发器?在 SQLServer 里面也就是对某一个表的一定的操作,触发某种条件,从而执行的一段程序。触发器是一个特殊的存储过程。
DML 触发器:
  • Insert delete update (不支持 select
  • after 触发器 (for) instead of 触发器(不支持 before 触发器)
After 触发器:
  • 在语句执行完毕之后触发
  • 按语句触发,而不是所影响的行数,无论所影响为多少行,只触发一次。
  • 只能建立在常规表上,不能建立在视图和临时表上。 (*)
  • 可以递归触发,最高可达 32 级。
   • update( ) ,在 update 语句触发时,判断某列是否被更新,返回布尔值。
l instead of 触发器
   • 用来替换原本的操作
   • 不会递归触发
   • 可以在约束被检查之前触发
   • 可以建在临时表和视图上(*)
触发器常用语法:
CREATETRIGGERtriggerNameON表名

after(for)(for与after都表示after触发器)  |  instead of

 UPDATE|INSERT|DELETE(insert,update,delete)

AS

begin

…

end

例如: 触发器 - 插入
CREATE TRIGGER tr_updateStudent ON score  --相当于外键检查约束
after INSERT -- 后置的新增触发器
AS
Begin
	declare @sid int,@scoreid int--定义两个变量
	select @sid = sId,@ scoreid=id from inserted--获得新增行的数据
	if exists(select * from student where sid=@sid)--判断分数学员是否存在
		print ‘插入成功’
	else --如果不存在,则把更新增成功的分数记录给删除掉
		delete from score where sid = @scoreId
End

Insert into score (studentId,english) values(100,100)

插入和删除 触发器:
drop table Records
create table Records
(
	rId int identity(1,1) primary key,
	rType int ,  -- 1存钱  -1 取钱
	rMoney money,
	userId char(4)
)

select * from bank
--创建触发器
create trigger tr_Records
on Records
for insert
as 
	declare @type int,@money money,@id char(4)
	select @type = rType,@money=rMoney,@id=userId from inserted
	
	update bank set balance = balance + @money*@type
	where  cId = @id

--当插入数据的时候就会引发触发器
insert into Records values(-1,10,'0002')

select * from Records
create trigger tr_del
on student
for delete
as
	delete from score where studentId in (select sid from deleted)

触发器使用建议:
   a.  尽量避免在触发器中执行耗时操作,因为触发器会与 SQL 语句认为在同一个事务中。(事务不结束,就无法释放锁。)
   b.  避免在触发器中做复杂操作,影响触发器性能的因素比较多(如:产品版本、所使用架构等等),要想编写高效的触发器考虑因素比较多(编写触发器容易,编写复杂的高性能触发器难!)。


4.索引Index

索引:

   相当于字典中的目录

   加快查询速度

    在执行增删改的时候降低了速度

聚集索引:

   相当于字典中拼音目录

   拼音目录的顺序和数据的顺序是一致的

   一个表中只能有一个聚集索引。

   索引的排序顺序与表中数据的物理存储位置是一致的,一般新建主键列后回自动生成一个聚集索引。

非聚集索引(逻辑上的排序):

   一个表中可以有多个非聚集索引。

   相当于字典中笔画目录

   笔画目录的顺序和数据是无关的

//建索引的目的是为了加快查询速度。

//索引之所以能加快查询速度是因为索引对数据进行了排序。

//建索引应该建在某个列上,就是说要对某个列排序,

//这是,如果用用户执行一条查询语句,where条件中包含了建索引的那列,那么这时,采用用到索引,否则,不会使用索引。Name=数据(用索引),namelike ‘%aa%’(不用索引)

创建索引的方式,在表设计器中点击右键,选择“索引/ 键”→添加→在列中选择索引包含的列。

使用索引能提高查询效率,但是索引也是占据空间的,而且添加、更新、删除数据的时候也需要同步更新索引,因此会降低 Insert Update Delete 的速度。只在经常检索的字段上 (Where) 创建索引。

(*)即使创建了索引,仍然有可能全表扫描,比如like 、函数、类型转换等。

删除索引:drop index T8 . IX_T8_tage

=======非聚集索引=============

CREATENONCLUSTERED INDEX IX_SalesPerson_SalesQuota_SalesYTD ONSales.SalesPerson (SalesQuota,SalesYTD); GO

====创建唯一非聚集索引=============

CREATEUNIQUE INDEX AK_UnitMeasure_Name ONProduction.UnitMeasure(Name);GO

=======创建聚集索引=================

CREATETABLE t1 (a int, bint, cAS a/b); CREATE UNIQUE CLUSTERED INDEX Idx1 ON t1(c); INSERT INTO t1 VALUES (1,0);


5. 临时表
局部临时表
    • create table # tbName ( 列信息 );
    • 表名前缀 #
   • 只在当前会话中有效,不能跨连接访问
   • 作用域范围类似 C#
    • 如果直接在连接会话中创建的,则当前连接断开后删除,如果是在存储过程中创建的则当前存储过程执行完毕后删除
全局临时表
   • create table ## tbName ( 列信息 );
   • 表名前缀 ##
   • 多个会话可共享全局临时表
   • 当创建全局临时表的会话断开,并且没有用户正在访问全局临时表时删除
(*)表变量: declare @varT1 table (col1int,col2 char(2));// 存储更小量的数据,比临时表有更多的限制。
l 临时数据都存储在 tempdb , 当服务重新启动的时候,会重建 tempdb .


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值