В этом руководстве вы узнаете, как выполнить транзакцию 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().

