有过第一版的机房收费系统,大家都很清楚知道有些调用数据库表的操作真的是很麻烦,就用机房收费系统中的注册,既要更新学生表,卡表,还需要更新充值记录表,三张表的操作,除了它在代码的编写过程很麻烦,耦合性很高,还有一点就是在这个过程很有可能更新其中的一张表后,就报错了,这样的结果就是数据库中的数据不再统一。同样的问题,如果应用到银行存款,后果不堪设想啊。。。
问题
首先分析上面的问题,一是多张表的同时操作,比较麻烦;二是如果数据过程中出错,会造成整个系统中的数据不一致。遇到问题一个个的解决。
存储过程
不知道大家在学习数据库的时候是否注意到存储过程这个东西,学习是一个不断进步的过程。因为数据库用的比较少,所以这一次果断使用存储过程完成这个更新过程。先让我们温故一下:
存储过程的定义:一组为了完成特定功能的SQL语句集,存储在数据库中,经过第一次编译后再次调用不需要再次编译,用户通过指定存储过程的名字并给出参数(如果该存储过程带有参数)来执行它。存储过程是数据库中的一个重要对象,任何一个设计良好的数据库应用程序都应该用到存储过程。
由此可见存储过程还是一个比较重要的部分吧。那么如何使用呢?首先存储过程位于什么位置?
我第一次用存储过程是在学生的注册部分,这种东西其实看看就很能搞懂的。
ALTER PROCEDURE [dbo].[PROC_RegisterCard]
@cardno varchar(50),
@studentno varchar(50),
@studentName varchar(50),
@Cash varchar(50),
@sex varchar(50),
@department varchar(50),
@grade varchar(50),
@class varchar(50),
@explain varchar(500),
@UserID varchar(10),
@style varchar(10),
@RegisterDate varchar(50),
@RegisterTime varchar(50),
@CheckCash varchar(50)
AS
begin
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
--SET NOCOUNT ON;
--SET XACT_ABORT ON;
-- Insert statements for procedure here
--在表card_Info 中添加卡号
insert into Card_Info values(@cardno ,@studentno ,@RegisterDate ,@RegisterTime ,@UserID ,@Cash ,@style )
insert into Student_Info values(@studentno ,@studentName ,@sex,@department ,@grade ,@class ,@explain )
insert into ReCharge_Info (cardno,AddMoney ,Date ,Time ,UserID ,CheckCash )values (@cardno ,@cash,@RegisterDate ,@RegisterTime ,@UserID ,@CheckCash )
END
这样就能帮助我们提高编写的效率,更是能提高系统的性能。但是第二个问题依旧存在,如何让它们要不同时执行,要不都不执行呢?是否还记的数据库中的事务?
事务
事务的四个特性,成为我们钟爱的原因。
1、原子性(atomicity)。一个事务是一个不可分割的工作单位,事务中包括的诸操作要么都做,要么都不做。
2、一致性(consistency)。事务必须是使数据库从一个一致性状态变到另一个一致性状态。一致性与原子性是密切相关的。
3、隔离性(isolation)。一个事务的执行不能被其他事务干扰。即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
4、持久性(durability)。持久性也称永久性(permanence),指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。接下来的其他操作或故障不应该对其有任何影响。
这一次我们主要使用它的原子性,下面是具体的代码,主要是在原来代码的基础上添加事务回滚。
ALTER PROCEDURE [dbo].[PROC_RegisterCard]
@cardno varchar(50),
@studentno varchar(50),
@studentName varchar(50),
@Cash varchar(50),
@sex varchar(50),
@department varchar(50),
@grade varchar(50),
@class varchar(50),
@explain varchar(500),
@UserID varchar(10),
@style varchar(10),
@RegisterDate varchar(50),
@RegisterTime varchar(50),
@CheckCash varchar(50)
AS
begin
declare @error int
set @error=0
BEGIN transaction
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
--SET NOCOUNT ON;
--SET XACT_ABORT ON;
-- Insert statements for procedure here
--在表card_Info 中添加卡号
insert into Card_Info values(@cardno ,@studentno ,@RegisterDate ,@RegisterTime ,@UserID ,@Cash ,@style )
set @error=@error+@@error
--save tran bcd --保存一个事务点
--在表student_Info 中添加学生信息
insert into Student_Info values(@studentno ,@studentName ,@sex,@department ,@grade ,@class ,@explain )
set @error =@error +@@error
--增添表ReCharge_Info表中的充值记录
insert into ReCharge_Info (cardno,AddMoney ,Date ,Time ,UserID ,CheckCash )values (@cardno ,@cash,@RegisterDate ,@RegisterTime ,@UserID ,@CheckCash )
set @error=@error+@@error
if @error<>0
rollback transaction --如果不等于0,则回滚事务,不能执行
else
commit transaction --等于0,则执行该事务
END
所以机房中的注册过程,通过存储过程+事务完美解决。虽然这些东西很好,但是过分的依赖同样要有大麻烦。
缺点
1:移植问题,数据库端代码当然是与数据库相关的。但是如果是做工程型项目,基本不存在移植问题。
2:重新编译问题,因为后端代码是运行前编译的,如果带有引用关系的对象发生改变时,受影响的存储过程、包将需要重新编译(不过也可以设置成运行时刻自动编译)。
3: 如果在一个程序系统中大量的使用存储过程,到程序交付使用的时候随着用户需求的增加会导致数据结构的变化,接着就是系统的相关问题了,最后如果用户想维护该系统可以说是很难很难、而且代价是空前的,维护起来更麻烦。
【总结】
存储过程和事务,尽管在数据库学习的时候了解过,但是相对于之前的自己确实是很陌生的东西,所以尝试使用是我们面对陌生的最好办法。在使用的过程中渐渐熟悉,这对我们自己更是一种挑战,然而这些挑战都将帮助我们变得越来越好,所以既然花费的大量的时间和尽力来做这件事,就尽可能的让自己多多成长些!