【发布时间】:2014-04-25 14:32:44
【问题描述】:
我尝试将 COMMIT TRAN 置于 if else 循环中,但仍然出现此错误。
我必须为一个学生注册一个班级。如果报名后座位数为负数,我只好反转并打印一条消息说不能报名。我放了其他错误消息只是为了看看事务是如何工作的。
CREATE PROCEDURE dbo.EnrollStudent ( @CourseID AS INTEGER,
@StudentID AS VARCHAR(20) ) AS
BEGIN
DECLARE @StatusID INTEGER
DECLARE @Status VARCHAR(50)
DECLARE @CurrentSeats INTEGER
DECLARE @ErrorCode INTEGER
SET @StatusID=0
IF EXISTS (SELECT 1
FROM dbo.CourseEnrollment
WHERE dbo.CourseEnrollment.CourseId=@CourseID AND dbo.CourseEnrollment.StudentId=@StudentID )
BEGIN
BEGIN TRAN Tr1
SET @StatusID = 1
SELECT @ErrorCode=@@ERROR
IF (@ErrorCode<>0) GOTO OTHERPROBLEM
ELSE
COMMIT TRAN Tr1
END
IF EXISTS ( SELECT 1
FROM dbo.CourseEnrollment
FULL OUTER JOIN dbo.Courses
ON dbo.Courses.CourseId=@CourseID
WHERE dbo.CourseEnrollment.StudentId<>@StudentID AND dbo.Courses.Faculty IS NULL )
BEGIN
BEGIN TRAN Tr2
SET @StatusID=2
SELECT @ErrorCode=@@ERROR
IF (@ErrorCode<>0) GOTO OTHERPROBLEM2
ELSE
COMMIT TRAN Tr2
END
IF @StatusID=0
BEGIN
IF EXISTS ( SELECT 1
FROM dbo.Courses
WHERE dbo.Courses.CourseId=@CourseID AND dbo.Courses.Faculty IS NOT NULL )
BEGIN
BEGIN TRAN Tr3
SET @StatusID=3
BEGIN TRAN InsertingValues
INSERT INTO dbo.CourseEnrollment (dbo.CourseEnrollment.StudentId,dbo.CourseEnrollment.CourseId)
VALUES (@StudentID,@CourseID);
SELECT @ErrorCode=@@ERROR
IF (@ErrorCode<>0) GOTO InsertProblem
ELSE
COMMIT TRAN InsertingValues
BEGIN TRAN UpdateCourses
UPDATE dbo.Courses
SET OpenSeats = OpenSeats-1
WHERE dbo.Courses.CourseId = @CourseID
SELECT @ErrorCode=@@ERROR
IF (@ErrorCode<>0) GOTO UpdateProblem
ELSE
COMMIT TRAN UpdateCourses
SELECT @CurrentSeats=OpenSeats
FROM dbo.Courses
WHERE dbo.Courses.CourseId = @CourseID
IF (@CurrentSeats<0) GOTO PROBLEM
ELSE
COMMIT TRAN Tr3
END
END
OTHERPROBLEM:
BEGIN
PRINT 'Unable to set status'
ROLLBACK TRAN
END
OTHERPROBLEM2:
BEGIN
PRINT 'Unable to set status'
ROLLBACK TRAN
END
UpdateProblem:
BEGIN
PRINT 'Not able to update values'
ROLLBACK TRAN InsertingValues
END
InsertProblem:
BEGIN
PRINT 'Not able to insert'
ROLLBACK TRAN InsertingValues
END
PROBLEM:
BEGIN
PRINT 'Seats Full!'
ROLLBACK TRAN
END
IF @StatusID = 1
BEGIN
SET @Status = 'The Student is already enrolled'
END;
ELSE IF @StatusID = 2
BEGIN
SET @Status = 'Cannot enroll until faculty is selected'
END
ELSE IF @StatusID = 3
BEGIN
SET @Status = 'Student Enrolled'
END
SELECT @Status
END;
这正确更新了表格,但出现以下错误:
(1 row(s) affected)
(1 row(s) affected)
Unable to set status
Msg 3903, Level 16, State 1, Procedure EnrollStudent, Line 101
The ROLLBACK TRANSACTION request has no corresponding BEGIN TRANSACTION.
Unable to set status
Msg 3903, Level 16, State 1, Procedure EnrollStudent, Line 108
The ROLLBACK TRANSACTION request has no corresponding BEGIN TRANSACTION.
Not able to update values
Msg 3903, Level 16, State 1, Procedure EnrollStudent, Line 115
The ROLLBACK TRANSACTION request has no corresponding BEGIN TRANSACTION.
Not able to insert
Msg 3903, Level 16, State 1, Procedure EnrollStudent, Line 123
The ROLLBACK TRANSACTION request has no corresponding BEGIN TRANSACTION.
Seats Full!
Msg 3903, Level 16, State 1, Procedure EnrollStudent, Line 131
The ROLLBACK TRANSACTION request has no corresponding BEGIN TRANSACTION.
(1 row(s) affected)
【问题讨论】:
-
我很确定您的第二个查询(带有
FULL OUTER JOIN的查询)没有告诉您有用的信息。我至少无法理解您期望它会告诉您什么,或者为什么这会相关。此外,除非您将 整个 事物包装在单个序列化事务中,否则您不能相信您的结果;可能会添加太多学生,获得否定席位,根本不报告(未来)否定席位......这对于并发系统实际上并不安全。就我个人而言,我可能会先INSERTing 进入一个具有高分辨率时间戳且没有事务的表。
标签: sql sql-server-2008 transactions