Проблема с логикой транзакций c и обработкой ошибок - PullRequest
1 голос
/ 29 января 2020

Я слежу за онлайн-уроками по транзакциям в соответствии с концепцией ACID. У меня есть две таблицы:

-- Create Product table
CREATE TABLE Product
(
  ProductId INT PRIMARY KEY,
  Name VARCHAR(50),
  Price INT,
  Quantity INT
)
GO

-- Populate the Product Table with some test data
INSERT INTO Product VALUES(101, 'Laptop', 1234, 100)
INSERT INTO Product VALUES(102, 'Desktop', 3456, 150)
INSERT INTO Product VALUES(103, 'Tablet', 5678, 200)
INSERT INTO Product VALUES(104, 'Mobile', 7890, 250)
GO

-- Create ProductSales table
CREATE TABLE ProductSales
(
  ProductSalesId INT PRIMARY KEY,
  ProductId INT,
  QuantitySold INT
) 
GO

Я создал хранимую процедуру с транзакцией, в которой я предоставляю productId и количество для продажи.

Это моя хранимая процедура:

CREATE PROCEDURE spSellProduct
@ProductID INT,
@QuantityToSell INT
AS
BEGIN
  -- First we need to Check the stock available for the product we want to sell
  DECLARE @StockAvailable INT

  SELECT @StockAvailable = Quantity 
  FROM Product 
  WHERE ProductId = @ProductId

  -- We need to throw an error to the calling application 
  -- if the stock is less than the quantity we want to sell
  IF(@StockAvailable< @QuantityToSell)
  BEGIN
    Raiserror('Enough Stock is not available',16,1)
  END
  -- If enough stock is available
  ELSE
  BEGIN
    BEGIN TRY
      -- We need to start the transaction
      BEGIN TRANSACTION

      -- First we need to reduce the quantity available
      UPDATE    Product SET 
          Quantity = (Quantity - @QuantityToSell)
      WHERE ProductID = @ProductID

      -- Calculate MAX ProductSalesId
      DECLARE @MaxProductSalesId INT
      SELECT    @MaxProductSalesId = CASE 
          WHEN  MAX(ProductSalesId) IS NULL THEN 0 
          ELSE MAX(ProductSalesId) 
          END 
      FROM  ProductSales

      -- Increment @MaxProductSalesId by 1, so we don't get a primary key violation
      Set @MaxProductSalesId = @MaxProductSalesId + 1

      -- We need to insert the quantity sold into the ProductSales table
      INSERT INTO ProductSales(ProductSalesId, ProductId, QuantitySold)
      VALUES(@MaxProductSalesId, @ProductId, @QuantityToSell)

      COMMIT TRANSACTION
    END TRY
    BEGIN CATCH
      ROLLBACK TRANSACTION
      SELECT    ERROR_NUMBER() as ErrorNumber,
          ERROR_MESSAGE() as ErrorMessage,
          ERROR_PROCEDURE() as ErrorProcedure,
          ERROR_STATE() as ErrorState,
          ERROR_SEVERITY() as ErrorSeverity,
          ERROR_LINE() as ErrorLine
    END CATCH
  End
END

go

spSellProduct @ProductId=103, @QuantityToSell=300

Я проверяю, если количество меньше количества для продажи, тогда я выдаю ошибку. Если ошибок не обнаружено, я начинаю транзакцию.

Затем вычитаю количество из таблицы продуктов. После этого я увеличиваю ProductSalesId в таблице productSales и вставляю новую строку с ProductId и QuantitySold.

Если возникли какие-либо ошибки, я пытаюсь обработать их в моем пакете перехвата и откатить транзакцию.

Итак в моей таблице Product для ProductId 103, в котором имеется 200 штук, и я выполняю хранимую процедуру c следующим образом:

spSellProduct @ ProductId = 103, @ QuantityToSell = 300

Нет генерируются ошибки, и транзакция не откатывается, если @QuantityToSell больше количества. В этом случае количество для ProductId равно 200, а количество, которое я пытаюсь продать, составляет 300.

Что я здесь не так делаю?

спасибо

1 Ответ

0 голосов
/ 29 января 2020

Вы должны поместить весь код вашей процедуры в ловушку try, а внутри нее - транзакцию. Попробуйте использовать следующий код.

CREATE PROCEDURE [dbo].[spSellProduct]
@ProductID INT,
@QuantityToSell INT
AS
BEGIN
  BEGIN TRY
     BEGIN TRANSACTION 
          -- First we need to Check the stock available for the product we want to sell
          DECLARE @StockAvailable INT

          SELECT @StockAvailable = Quantity 
          FROM Product 
          WHERE ProductId = @ProductId

          -- We need to throw an error to the calling application 
          -- if the stock is less than the quantity we want to sell
          IF(@StockAvailable< @QuantityToSell)
          BEGIN
            Raiserror('Enough Stock is not available',16,1)
          END
          -- If enough stock is available
          ELSE
          BEGIN
               -- First we need to reduce the quantity available
              UPDATE    Product SET 
                  Quantity = (Quantity - @QuantityToSell)
              WHERE ProductID = @ProductID

              -- Calculate MAX ProductSalesId
              DECLARE @MaxProductSalesId INT
              SELECT    @MaxProductSalesId = CASE 
                  WHEN  MAX(ProductSalesId) IS NULL THEN 0 
                  ELSE MAX(ProductSalesId) 
                  END 
              FROM  ProductSales

              -- Increment @MaxProductSalesId by 1, so we don't get a primary key violation
              Set @MaxProductSalesId = @MaxProductSalesId + 1

              -- We need to insert the quantity sold into the ProductSales table
              INSERT INTO ProductSales(ProductSalesId, ProductId, QuantitySold)
              VALUES(@MaxProductSalesId, @ProductId, @QuantityToSell)
            END
        COMMIT TRANSACTION CHECKTR
    END TRY
    BEGIN CATCH
      ROLLBACK TRANSACTION 
      SELECT    ERROR_NUMBER() as ErrorNumber,
          ERROR_MESSAGE() as ErrorMessage,
          ERROR_PROCEDURE() as ErrorProcedure,
          ERROR_STATE() as ErrorState,
          ERROR_SEVERITY() as ErrorSeverity,
          ERROR_LINE() as ErrorLine
    END CATCH
END
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...