事务处理

    
一、概念

1、含义:数据库中的事务是一种机制,每个事务时一个独立的工作单元,包含一组数据库操作命令。是一个不可分割的工作逻辑单元

2、属性

  原子性:各个元素不可分割
  一致性:数据保持一致的状态
  隔离性:各个事务之间相互隔离,互不干扰
  持久性:其操作结果对系统的影响是永久的

3、分类:

显示事务:
  开始:begin    transaction
  提交:commit   transaction
  回滚:rollback transaction

隐式事务
  开始:set implicit_transaction on(开启)/off(关闭)

自动提交事务 :每条单独的语句都是一个事务。


二、事务的使用

1、创建

2、创建原则

  尽可能简短
  事务中访问的数据量尽量最少
  浏览数据时尽量不要打开事务
  事务处理期间尽量不要请求用户输入

3、使用事务的注意事项
 
  每个操作之后都要检查@@error 或@rowcount的值
  当事务结束后,紧跟的T_sql语句会被执行 但出错后就不能回滚事务
  提交完毕的事务将被写入数据库中
  事务执行过程中若发生非人为因素(如 断电)导致事务执行失败,下次重启系统时 事务会自动回滚
  无法回滚的语句不能写在事务中


三、事务的隔离级别

1、read uncommitted:不隔离数据(该事务正在使用数据同时,其他事务也可以使用) 隔离级别最低

2、read committed: 不允许读取没有提交的数据  Sql server默认级别

3、repeatable read:事务中锁定所读取的数据不让别人修改、删除 可保持数据一致性

4、snapshot:快照隔离

5、serializable:将事务所用到的数据表全部锁定 部允许凄然事务增、删、改数据,并发性最低 安全性最高

6、更改事务隔离级别的语法:
  set transaction isolation level read uncommitted/read committed/repeatable read
/snapshot/serializable  --隔离级别
   --T_sql语句

 

 

四、相关习题

1、use master
if DB_ID('studentDB') is not null
 drop database studentDB
 go
create database studentDB
go
use studentDB
go


if OBJECT_ID('classInfo','table') is not null
 drop table classInfo
 go
create table classInfo
(
 classId int primary key identity,
 className varchar(30) unique
)
--插入测试数据
insert into classInfo values('高三八班')
insert into classInfo values('高三二班')
insert into classInfo values('高三三班')
insert into classInfo values('高三四班')
insert into classInfo values('高三五班')
insert into classInfo values('高三六班')
insert into classInfo values('高三七班')

select * from classInfo


if OBJECT_ID('student','table') is not null
 drop table student
 go
create table student
(
 stuId int primary key identity,
 stuName varchar(30),
 stuAge int,
 stuPhone varchar(20) check(stuPhone like  '139%' or stuPhone like '133%'),
 classId int references classInfo(classId),
 stuState int check(stuState=0 or stuState=1 or stuState=2)  --0为在读 1为休学 2为转学
)
insert into student values('张三',18,'13997805814',1,0)
insert into student values('张三',17,'13397805814',1,0)
insert into student values('张三',19,'13977805814',5,0)
insert into student values('张死',20,'13987805814',1,0)
insert into student values('李四',21,'13997805914',2,0)
insert into student values('王五',28,'13997805234',3,0)
insert into student values('周六',38,'13997805845',2,0)
insert into student values('abc',15,'13378923147',1,0)

select * from student

go
--创建存储过程,传入两个个学生ID1,ID2,把学生的电话号码分别改为abc和13945611234
--   如果修改成功,给出修改成功提示!
--   如果修改失败,撤销回修改前的状态,并给出修改失败错误提示!
--   提示:考虑使用事务!
 if OBJECT_ID('proc_update','procedure') is not null
 drop procedure proc_update
 go
create procedure proc_update
 @stuId1 int,
 @stuId2 int
as
 declare @myerror int =0, @mycount int =0
begin

   begin transaction
   
   update student set stuPhone='abc' where stuId=@stuId1
   select @myerror+=@@ERROR ,@mycount+=@@ROWCOUNT
   update student set stuPhone='13945611234' where stuId=@stuId2
   select @myerror+=@@ERROR ,@mycount+=@@ROWCOUNT
  
   if(@mycount<2 or @myerror!=0)
  begin
   print '修改失败'
   rollback transaction
  end
   else
  begin
   print '修改成功'
    commit transaction
  end
  select * from student where stuId=@stuId1
  select * from student where stuId=@stuId2
end;
go
execute proc_update 1,2
go

2、use master
go
--创建数据库
if DB_ID('bankDB') is not null
 drop database bankDB
go
create database bankDB
on
(
 name='bankDB',
 filename='e:\bankDB.mdf',
 filegrowth=15%
)
log on
(
 name='bankDB_log',
 filename='e:\bankDB_log.ldf'
)
go

--使用数据库
use bankDB
go

--创建表
if exists(select * from sysobjects where name='userInfo')
 drop table userInfo
go
create table userInfo
(
 customerID int identity(1,1) not null,
 customerName varchar(20) not null,
 PID varchar(20) not null,
 telephone varchar(20) not null,
 address varchar(50)
)
go

if exists(select * from sysobjects where name='cardInfo')
 drop table cardInfo
go
create table cardInfo
(
 cardID varchar(20) not null,
 curType varchar(20) not null,
 savingType varchar(20) not null,
 openDate datetime not null,
 openMoney money not null,
 balance money not null,
 pass varchar(6) not null,
 IsReportLoss bit not null,
 customerID int not null
)
go

if exists(select * from sysobjects where name='transInfo')
 drop table transInfo
go
create table transInfo
(
 transDate datetime not null,
 cardID varchar(20) not null,
 transType varchar(10) not null,
 transMoney money not null,
 remark varchar(100)
)
go

--添加约束
alter table userInfo
 add constraint ck_PID check(len(PID)=18 or len(PID)=15)
alter table userInfo
 add constraint uq_PID unique(PID)
alter table userInfo
 add constraint ck_telephone check(len(telephone)=11 or
 telephone like '[0-9][0-9][0-9][0-9]-[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]' or
 telephone like '[0-9][0-9][0-9]-[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]')
alter table cardInfo
 add constraint ck_cardID check(cardID like '1010 3576 [0-9][0-9][0-9][0-9] [0-9][0-9][0-9][0-9]')
alter table cardInfo
 add constraint df_curTpye default('RMB') for curType
alter table cardInfo
 add constraint ck_savingType check(savingType in('活期','定活两便','定期'))
alter table cardInfo
 add constraint df_openDate default(getdate()) for openDate
alter table cardInfo
 add constraint ck_openMoney check(openMoney>=1)
alter table cardInfo
 add constraint ck_balance check(balance>=1)
alter table cardInfo
 add constraint ck_pass check(len(pass)=6)
alter table cardInfo
 add constraint df_pass default('888888') for pass
alter table cardInfo
 add constraint ck_IsReportLoss check(IsReportLoss='0' or IsReportLoss='1')
alter table cardInfo
 add constraint df_IsReportLoss default('0') for IsReportLoss
alter table transInfo
 add constraint df_transDate default(getdate()) for transDate
alter table transInfo
 add constraint ck_transType check(transType='存入' or transType='支取')
alter table transInfo
 add constraint ck_transMoney check(transMoney>0)

--添加关系
alter table userInfo
 add constraint pk_UcustomerID primary key(customerID)
alter table cardInfo
 add constraint pk_CcardID primary key(cardID)
alter table cardInfo
 add constraint fk_CcustomerID foreign key(customerID) references userInfo(customerID)
alter table transInfo
 add constraint fk_TcardID foreign key(cardID) references cardInfo(cardID)

--插入测试数据
insert into userInfo values('张三','123456789012345','010-67898978','北京海淀')
insert into cardInfo values('1010 3576 1234 5678',default,'活期',default,1000,1000,default,default,1)
insert into userInfo(customerName,PID,telephone) values('李四','321245678912345678','0478-44443333')
insert into cardInfo values('1010 3576 1212 1134',default,'定期',default,1,1,default,default,2)
insert into transInfo(transDate,cardID,transType,transMoney) values(default,'1010 3576 1234 5678','支取',900)
update cardInfo set balance=balance-900 where cardID='1010 3576 1234 5678'
insert into transInfo(transDate,cardID,transType,transMoney) values(default,'1010 3576 1212 1134','存入',5000)
update cardInfo set balance=balance+5000 where cardID='1010 3576 1212 1134'

select * from userInfo
select * from transInfo
select * from cardInfo

--(1)写存储过程完成存款的业务,使用事务
if OBJECT_ID('proc_get','procedure') is not null
 drop procedure proc_get
 go
create procedure proc_get
 @cardId varchar(20),
 @money money
as
 declare @mycount int =0,@myerror int =0
begin
 if not exists(select * from cardInfo where cardID=@cardId)
  begin
   print '该用户不存在 请检查卡号是否输入正确'
   return
  end
 begin transaction
  update cardInfo set balance=balance+@money where cardId=@cardId
  select @mycount+=@@ROWCOUNT,@myerror+=@@ERROR
  insert into transInfo values(GETDATE(),@cardId,'存入',@money,null)
  select @mycount+=@@ROWCOUNT,@myerror+=@@ERROR
 if(@mycount<2 or @myerror!=0)
  begin
   print '存款失败'
   rollback transaction
  end
 else
  begin
   commit transaction
   select * from cardInfo where cardId=@cardId
  end
end;
go
execute proc_get '1010 3576 1212 1134',10000
select * from userInfo
select * from transInfo
select * from cardInfo

--(2)写存储过程完成取款的业务,使用事务
if OBJECT_ID('proc_save','procedure') is not null
 drop procedure proc_save
 go
create procedure proc_save
 @customerId int,
 @money money
as
 declare @mycount int =0,@myerror int =0
begin
 begin transaction
  update cardInfo set balance=balance-@money where customerID=@customerId
 select @mycount+=@@ROWCOUNT,@myerror+=@@ERROR
  insert into transInfo values(GETDATE(),(select cardID from cardInfo where customerID=@customerId),'支取',@money,null)
 select @mycount+=@@ROWCOUNT,@myerror+=@@ERROR
 if(@mycount<2 or @myerror!=0)
  begin
   print '支取失败'
   rollback transaction
  end
 else
  begin
   commit transaction
   select * from cardInfo where customerID=@customerId
  end
end;
go
execute proc_save 1,10000
go

--(3)写存储过程完成转账的业务,使用事务
--
if OBJECT_ID('proc_give','procedure') is not null
 drop procedure proc_give
 go
create procedure proc_give
 @customerIdG int,
 @customerIdR int,
 @money money
as
declare @mycount int =0,@myerror int =0
begin
 if(((select balance from cardInfo where customerID=@customerIdG)-@money)!>0)
  begin
   print '该用户不可以进行转账业务  卡内余额不足'
   return
  end
 begin transaction
  update cardInfo set balance=balance-@money where customerID=@customerIdG
  select @mycount+=@@ROWCOUNT,@myerror+=@@ERROR
  update cardInfo set balance=balance+@money where customerID=@customerIdR
  select @mycount+=@@ROWCOUNT,@myerror+=@@ERROR
  insert into transInfo values(GETDATE(),(select cardID from cardInfo where customerID=@customerIdG),'支取',@money,null)
  select @mycount+=@@ROWCOUNT,@myerror+=@@ERROR
  insert into transInfo values(GETDATE(),(select cardID from cardInfo where customerID=@customerIdR),'存入',@money,null)
  select @mycount+=@@ROWCOUNT,@myerror+=@@ERROR
  if(@mycount<4 or @myerror!=0)
   begin
    print '转账失败'
    rollback transaction
   end
  else
   begin
    commit transaction
    select * from cardInfo
    select * from transInfo
   end
end;
go
execute proc_give 2,1,15000
go
select * from cardInfo
select * from transInfo
select* from userInfo
print'服务器为:'+@@servicename

posted on 2013-05-03 09:06  DBtwoer  阅读(356)  评论(0)    收藏  举报