В этом руководстве вы узнаете, как выполнить транзакцию SQL Server с помощью приложения Node.js.
Это руководство начинается с того места, где закончилось руководство по удалению данных из таблицы с помощью Node.js.
Настройка выборочных данных
Шаг 1. Запустите SQL Server Management Studio(SSMS) для подключения к базе данных BookStore.
Шаг 2. Выполните следующие операторы для вставки данных в таблицы Books, BookAuthors, Customers и Inventories:
-- Insert books into the Books table INSERT INTO Books(Title, Publisher, ISBN, PublishedDate) VALUES('The Adventures of Tom Sawyer', 'American Publishing Company', '978-0-123456-47-2', '1876-01-01'), ('The Adventures of Huckleberry Finn', 'Chatto & Windus', '978-0-123456-48-9', '1884-12-10'), ('A Connecticut Yankee in King Arthur''s Court', 'Charles L. Webster And Company', '978-0-123456-49-6', '1889-04-10'), ('The Prince and the Pauper', 'James R. Osgood & Co.', '978-0-123456-50-2', '1881-12-01'), ('Life on the Mississippi', 'James R. Osgood & Co.', '978-0-123456-51-9', '1883-02-01'); -- Get the generated BookID values for the inserted books DECLARE @BookID1 INT, @BookID2 INT, @BookID3 INT, @BookID4 INT, @BookID5 INT; SELECT @BookID1 = BookID FROM Books WHERE ISBN = '978-0-123456-47-2'; SELECT @BookID2 = BookID FROM Books WHERE ISBN = '978-0-123456-48-9'; SELECT @BookID3 = BookID FROM Books WHERE ISBN = '978-0-123456-49-6'; SELECT @BookID4 = BookID FROM Books WHERE ISBN = '978-0-123456-50-2'; SELECT @BookID5 = BookID FROM Books WHERE ISBN = '978-0-123456-51-9'; -- Insert records into the BookAuthors table INSERT INTO BookAuthors(BookID, AuthorID) VALUES(@BookID1, 6), (@BookID2, 6), (@BookID3, 6), (@BookID4, 6), (@BookID5, 6); -- Insert inventories INSERT INTO Inventories(BookID, Qty) SELECT BookID, ABS(CHECKSUM(NEWID()) % 101) + 100 FROM Books;
Выполнить транзакцию
Шаг 1. Создайте новый файл с именем transaction.js в каталоге проекта.
Шаг 2. Определите функцию createOrder в модуле transaction.js, которая выполняет следующие шаги:
- Сравните инвентарь с объемом заказа в таблице «Запасы».
- Создайте заказ, вставив данные в таблицу Orders и OrderDetails.
- Уменьшите инвентарь книги в таблице «Инвентарь».
import sql from 'mssql'; import { config } from './config.js'; async function createOrder(customerId, bookId, quantity, price, orderDate) { try { // Connect to the database const pool = await sql.connect(config); // Begin transaction const transaction = new sql.Transaction(pool); await transaction.begin(); try { // Check inventory const inventoryResult = await transaction .request() .input('BookID', sql.Int, bookId).query(` SELECT Qty FROM Inventories WHERE BookID = @BookID `); const currentQty = inventoryResult.recordset[0]?.Qty; if(!currentQty || currentQty < quantity) { throw new Error('Not enough inventory to fulfill the order'); } // Insert into Orders table const orderResult = await transaction .request() .input('CustomerID', sql.Int, customerId) .input('OrderDate', sql.DateTime, orderDate) .input('TotalAmount', sql.Decimal(10, 2), price * quantity).query(` INSERT INTO Orders(CustomerID, OrderDate, TotalAmount) OUTPUT INSERTED.OrderID VALUES(@CustomerID, @OrderDate, @TotalAmount) `); const orderId = orderResult.recordset[0].OrderID; // Insert into OrderDetails table await transaction .request() .input('OrderID', sql.Int, orderId) .input('BookID', sql.Int, bookId) .input('Quantity', sql.Int, quantity) .input('Price', sql.Decimal(10, 2), price).query(` INSERT INTO OrderDetails(OrderID, BookID, Quantity, Price) VALUES(@OrderID, @BookID, @Quantity, @Price) `); // Update Inventories table await transaction .request() .input('BookID', sql.Int, bookId) .input('Quantity', sql.Int, quantity).query(` UPDATE Inventories SET Qty = Qty - @Quantity WHERE BookID = @BookID `); // Commit transaction await transaction.commit(); console.log('Order created successfully'); } catch(err) { // Rollback transaction on error await transaction.rollback(); throw err; } } catch(err) { console.error('Error creating order:', err); } } export { createOrder };
Как это работает.
Сначала импортируйте объект SQL из пакета mssql и объект конфигурации из модуля config.js:
import sql from 'mssql'; import { config } from './config.js';
Во-вторых, определите функцию createOrder(), которая создает заказ для клиента на основе заказанной книги, указанной по идентификатору книги, количеству книг, цене и дате заказа.
async function createOrder(customerId, bookId, quantity, price, orderDate) { //... };
В-третьих, подключитесь к базе данных, используя предоставленный объект конфигурации:
const pool = await sql.connect(config);
В-четвертых, начните транзакцию, создав новый объект Transaction и вызвав метод begin().
const transaction = new sql.Transaction(pool); await transaction.begin();
В-пятых, проверьте инвентарь по идентификатору книги и верните количество книг в инвентаре:
const inventoryResult = await transaction .request() .input('BookID', sql.Int, bookId).query(` SELECT Qty FROM Inventories WHERE BookID = @BookID `);
В-шестых, если количество запасов меньше количества заказа, то выдается ошибка:
const currentQty = inventoryResult.recordset[0]?.Qty; if(!currentQty || currentQty < quantity) { throw new Error('Not enough inventory to fulfill the order'); }
В-седьмых, вставьте новую строку в таблицу «Заказы»:
const orderResult = await transaction .request() .input('CustomerID', sql.Int, customerId) .input('OrderDate', sql.DateTime, orderDate) .input('TotalAmount', sql.Decimal(10, 2), price * quantity).query(` INSERT INTO Orders(CustomerID, OrderDate, TotalAmount) OUTPUT INSERTED.OrderID VALUES(@CustomerID, @OrderDate, @TotalAmount) `);
Восьмое, получите вставленный идентификатор заказа:
const orderId = orderResult.recordset[0].OrderID;
Девятое, вставьте новую строку в таблицу OrderDetails:
await transaction .request() .input('OrderID', sql.Int, orderId) .input('BookID', sql.Int, bookId) .input('Quantity', sql.Int, quantity) .input('Price', sql.Decimal(10, 2), price).query(` INSERT INTO OrderDetails(OrderID, BookID, Quantity, Price) VALUES(@OrderID, @BookID, @Quantity, @Price) `);
В-десятых, обновите таблицу «Запасы», уменьшив количество запасов на величину заказа:
await transaction .request() .input('BookID', sql.Int, bookId) .input('Quantity', sql.Int, quantity).query(` UPDATE Inventories SET Qty = Qty - @Quantity WHERE BookID = @BookID `);
В-одиннадцатых, зафиксируйте транзакцию, вызвав метод commit() объекта транзакции:
await transaction.commit();
Двенадцатое, если во время транзакции произошла какая-либо ошибка, откатите ее, вызвав метод rollback() объекта Transaction:
await transaction.rollback();
Дополнительно выдается ошибка:
throw err;
Шаг 3. Измените файл index.js, чтобы использовать функцию createOrder:
import { createOrder } from './transaction.js'; try { await createOrder(1, 1, 5, 9.99, new Date(2024, 6, 16)); } catch(err) { console.log(err); }
Как это работает.
Сначала импортируйте функцию createOrder из модуля transaction.js:
import { createOrder } from './transaction.js';
Во-вторых, создайте новый заказ, вызвав функцию createOrder:
try { await createOrder(1, 1, 500, 9.99, new Date(2024, 6, 16)); } catch(err) { console.log(err); }
Шаг 4. Откройте терминал и выполните следующую команду для выполнения файла index.js:
npm start
Загрузите исходный код проекта
Загрузите исходный код проекта
Краткое содержание
- Вызовите метод transaction.begin(), чтобы начать транзакцию.
- Зафиксируйте транзакцию, вызвав метод transaction.commit().
- Откатите транзакцию, вызвав метод transaction.rollback().