gadget59.ru лекция
Node.js · Лекция 36 · 28 слайдов

Лекция №36: Node.js и MS SQL Server: от установки до первого SELECT

Node.js и MS SQL Server

В прошлых лекциях мы научили Java разговаривать с базой данных «Библиотека» через JDBC. Теперь мы переходим на сторону JavaScript.

До этого момента JavaScript жил только в браузере — он делал кнопки красивыми, открывал модальные окна и проверял, правильно ли вы ввели пароль. Node.js — это технология, которая позволяет запускать JavaScript прямо на сервере, без всякого браузера.

☕ Java (было) 🟨 Node.js (стало) 🪟 MS SQL Server 📦 npm 🔌 mssql 🚀 Express
В этой лекции мы установим Node.js, разберем, чем серверный JavaScript отличается от браузерного, и напишем первую программу, которая выводит текст в консоль сервера.
Формат: лекция, 2 академических часа. Понадобится компьютер с Windows, macOS или Linux.

План лекции

Сегодня мы заложим фундамент для всего блока серверной разработки.

  • 1 Что такое Node.js и зачем он нужен
  • 2 Установка Node.js и проверка npm
  • 3">Первая программа: console.log() на сервере
  • 4 Переменные: let, const и var
  • 5 Функции и стрелочные функции
  • 6 Массивы и объекты
  • 7 Что такое npm и package.json
  • 8 Асинхронность: почему сервер не ждет
  • 9 Promise: «обещание» результата
  • 10 async/await: пишем код как синхронный
  • 11 Обработка ошибок: try...catch
  • 12 Практика и домашнее задание
Если вы уже писали сайты на HTML и JS — вам будет проще. Но мы разжуем каждый термин с нуля.

Что такое Node.js?

Node.js — это среда выполнения JavaScript. Простыми словами: это программа, которая берет ваш файл с кодом (например, server.js) и исполняет его прямо на компьютере, без участия Chrome или Firefox.

JavaScript-код
→
Node.js (движок V8)
→
Операционная система
  • JavaScript в браузере: может менять текст на сайте, слушать клики мыши, но не может лазить в файлы на вашем диске или открывать базы данных.
  • Node.js на сервере: может читать любые файлы, работать с базой данных MS SQL Server, создавать свои сайты (API) и отправлять письма.
Node.js использует движок V8 — это тот самый супер-быстрый мотор, который стоит внутри браузера Google Chrome. Только теперь он работает на сервере.

Установка Node.js

Установка занимает 2 минуты.

  1. Откройте сайт nodejs.org (официальный сайт, ресурс разрешен в РФ).
  2. Вы увидите две зеленые кнопки: LTS (Long Term Support — версия с длительной поддержкой) и Current (самая новая). Всегда скачивайте LTS. Она стабильнее.
  3. Запустите скачанный файл (MSI для Windows).
  4. Нажимайте «Далее» (Next), оставляя все галочки по умолчанию. Node.js сам пропишет себя в системные пути.
Важно: В Windows после установки обязательно перезагрузите компьютер или откройте новую командную строку (cmd), иначе система не увидит команды node.

Проверка установки

Давайте убедимся, что всё работает. Откройте терминал:

  • Windows: Нажмите Win+R, введите cmd и нажмите Enter.
  • macOS: Откройте программу «Терминал».
  • Linux: Нажмите Ctrl+Alt+T.

Введите команды по очереди:

node -v

Вы увидите версию, например: v20.11.1.

npm -v

Вы увидите версию менеджера пакетов, например: 10.2.4.

Если в ответ на обе команды вы увидели цифры версий — Node.js установлен правильно.

Первая программа

Создайте на рабочем столе папку node-lesson. Внутри неё создайте файл index.js.

Откройте этот файл в любом редакторе (VS Code, Notepad++) и напишите:

console.log("Привет, Node.js!");

Сохраните файл. Теперь в терминале зайдите в эту папку (команда cd) и выполните:

node index.js
В терминале появится надпись «Привет, Node.js!». Поздравляю, вы только что запустили свой первый серверный JavaScript!

Переменные: let, const и var

Переменная — это «коробка», в которую мы кладем данные. В современном JavaScript три типа коробок:

let
let
Коробку можно менять.
const
const
Коробку нельзя менять.
var
var
Старый способ. Не используйте.
let age = 20; age = 21; // ОК, поменяли значение const name = "Иван"; name = "Петр"; // ОШИБКА! Нельзя менять const
Правило: всегда используйте const. Если точно знаете, что значение изменится — используйте let. Про var забудьте.

Функции

Функция — это кусочек кода, у которого есть имя. Мы можем вызвать его много раз.

Обычная функция:

function greet(name) { return "Привет, " + name + "!"; } console.log(greet("Алексей"));

Стрелочная функция (современный стандарт):

const greet = (name) => { return "Привет, " + name + "!"; };
Если функция возвращает что-то сразу, можно писать короче: const greet = name => "Привет, " + name;

Массивы и объекты

Массив — это список вещей.

const books = ["Война и мир", "Мастер и Маргарита", "Преступление и наказание"]; console.log(books[0]); // "Война и мир"

Объект — это вещь с характеристиками (ключ-значение).

const reader = { name: "Мария", age: 17, email: "maria@mail.ru" }; console.log(reader.name); // "Мария"
В Node.js мы постоянно передаем данные в базу именно в виде объектов. Ключ — это название столбца в SQL, значение — то, что ввел пользователь.

Что такое npm?

npm (Node Package Manager) — это «магазин приложений» для программистов. В нем миллионы готовых кусочков кода.

Ваш проект
→
npm install express
→
Папка node_modules
  • package.json: «Паспорт» вашего проекта. В нем записано: «Для работы мне нужны вот эти библиотеки».
  • node_modules: Папка, куда npm скачивает эти библиотеки.
npm init -y // создаем паспорт (package.json) npm install express // скачиваем библиотеку Express

Асинхронность

Это самое сложное и важное понятие в Node.js.

Синхронный код (как Java): Программа встает в очередь. Пока база данных ищет книгу, весь сервер «замерзает» и ждет. Другие пользователи не могут зайти на сайт.

Асинхронный код (как Node.js): Программа говорит базе: «Ищи книгу, а я пока пойду обслужу других 100 человек. Как найдешь — свистни».

Запрос 1 (БД)
⏳
Node.js
⚡
Запрос 2 (HTML)
⚡
Запрос 3 (API)
Node.js может держать тысячи соединений одновременно, потому что он не тратит время на ожидание. Он работает как официант в очень быстром кафе.

Promise (Обещание)

Promise (от англ. «обещание») — это объект, который говорит: «Я не знаю результат сейчас, но я ОБЕЩАЮ отдать его позже».

const loading = new Promise((resolve, reject) => { // ...идет долгая работа... if (успех) { resolve("Данные получены!"); } else { reject("Ошибка!"); } });

У Promise есть три состояния:

  1. Pending (Ожидание): работа идет.
  2. Fulfilled (Выполнено): данные готовы (resolve).
  3. Rejected (Ошибка): что-то сломалось (reject).

async и await

Писать код через then() (цепочки промисов) неудобно. Поэтому придумали async/await. Это «сахар», который делает асинхронный код похожим на обычный.

async function getData() { try { const response = await fetch('https://api.github.com'); const data = await response.json(); console.log(data); } catch (e) { console.log("Ошибка:", e); } }
Ключевое слово await говорит: «Подожди здесь, пока Promise не выполнится». Но важно: пока мы ждем здесь, Node.js всё равно может обслуживать другие запросы!

Обработка ошибок

В Node.js ошибки случаются постоянно: база упала, интернет пропал, файл не найден. Если их не ловить, сервер «упадет» целиком.

Используйте конструкцию try...catch:

try { // Код, который может сломаться const data = await db.query('SELECT ...'); } catch (error) { // Сюда попадаем, если что-то пошло не так console.error("База данных не отвечает:", error.message); }
Правило: любой код с await должен быть внутри try...catch. Это спасет ваш сервер от внезапной остановки.

Подключение к MS SQL Server

В Java мы использовали драйвер mssql-jdbc. В Node.js нам нужен пакет mssql. Это «переводчик» с языка Node.js на язык MS SQL Server.

npm install mssql

Также нам понадобится пакет dotenv. Он нужен, чтобы не писать пароль от базы данных прямо в коде (это небезопасно).

npm install dotenv
После этих команд в папке node-lesson появится папка node_modules, а в файле package.json добавятся строчки с зависимостями.

Файл .env

Создайте в папке проекта файл с названием .env (точка в начале обязательна!). В нем мы спрячем настройки базы.

DB_SERVER=localhost\\SQLEXPRESS DB_DATABASE=LibraryDB DB_USER=sa DB_PASSWORD=YourStrong!Passw0rd
Важно: Никогда не отправляйте файл .env в интернет (например, на GitHub). Там лежат ваши пароли! Добавьте .env в файл .gitignore.

Строка подключения

Теперь создадим файл db.js. В нем мы настроим подключение. Node.js будет читать данные из .env.

require('dotenv').config(); const sql = require('mssql'); const config = { server: process.env.DB_SERVER, database: process.env.DB_DATABASE, user: process.env.DB_USER, password: process.env.DB_PASSWORD, options: { encrypt: false // Для локального сервера } };
process.env — это специальная переменная Node.js, которая достает значения из файла .env.

Первое подключение (async/await)

Напишем функцию, которая проверит связь с базой. Обратите внимание на async и try...catch.

async function testConnection() { try { // Пул соединений — это касса в банке. Мы берем свободную кассу. const pool = await sql.connect(config); console.log("✅ Подключение к MS SQL Server успешно!"); } catch (err) { console.error("❌ Ошибка подключения:", err.message); } } testConnection();
Запустите в терминале: node db.js. Если видите зеленую галочку — Node.js увидел вашу базу «Библиотека»!

Первый SELECT

Давайте прочитаем таблицу Books. Мы используем request.query().

async function getBooks() { try { const pool = await sql.connect(config); const result = await pool.request() .query('SELECT Title, Year FROM Books ORDER BY Year'); // result.recordset — это массив найденных книг console.log(result.recordset); } catch (err) { console.error(err); } } getBooks();
В консоли вы увидите массив объектов: [{ Title: 'Война и мир', Year: 1869 }, ...]. Это те же данные, что мы получали в Java через ResultSet, но уже в формате JSON.

INSERT с параметрами (безопасно)

Никогда не склеивайте SQL из строк с пользовательским вводом! Это SQL-инъекция. Используйте параметры (input()).

async function addReader(name, email) { try { const pool = await sql.connect(config); const result = await pool.request() .input('Name', sql.NVarChar, name) .input('Email', sql.NVarChar, email) .query('INSERT INTO Readers (Name, Email) VALUES (@Name, @Email)'); console.log("Читатель добавлен. ID:", result.rowsAffected[0]); } catch (err) { console.error(err); } } addReader('Алексей Смирнов', 'alex@mail.ru');
Параметры @Name и @Email полностью защищают от взлома. Что бы ни ввел пользователь, это будет воспринято как текст.

Пул соединений (Pool)

В примере выше мы каждый раз делали sql.connect(). Это долго. В реальности мы создаем пул один раз при запуске сервера.

// db.js (общий файл) sql.connect(config).then(pool => { global.dbPool = pool; console.log("Пул подключен!"); }).catch(err => { console.error("Пул не создан:", err); });

Теперь в других файлах мы просто берем готовый пул:

const result = await global.dbPool.request()...
Пул сам открывает и закрывает соединения. Нам не нужно об этом думать.

Типичные ошибки Node.js + MSSQL

1. Login failed for user
Неправильный логин или пароль. Проверьте файл .env.
2. TCP/IP connection has failed
SQL Server не принимает подключения. Зайдите в "Диспетчер конфигурации SQL Server" и включите протокол TCP/IP.
3. Conversion failed...
Ошибка типов. Вы пытаетесь вставить текст в числовое поле. Проверьте sql.Int, sql.NVarChar, sql.Date.
4. Callbacks already called
Ошибка в асинхронности. Вы пытаетесь сделать await внутри функции, которая не помечена как async.
5. RequestError: Connection lost
База «уснула» или перезагрузилась. Пул должен пересоздать соединение автоматически.

Структура проекта (рефакторинг)

Чтобы код не превратился в кашу, разделим его на части. Хороший проект выглядит так:

node-lesson/ ├── node_modules/ // скачанные библиотеки ├── .env // пароли (НЕ в Git!) ├── package.json // паспорт проекта ├── db.js // настройки подключения к БД ├── queries.js // все SQL-запросы └── index.js // главная точка входа
В queries.js мы вынесем функции getBooks() и addReader(). В index.js будем только вызывать эти функции. Это называется «разделение ответственности».

Итоговая программа (index.js)

Соберем всё вместе. Наш index.js теперь выглядит очень просто и понятно:

require('dotenv').config(); const { getBooks, addReader } = require('./queries'); async function main() { console.log("=== Все книги ==="); await getBooks(); console.log("\n=== Добавляем читателя ==="); await addReader("Борис", "boris@mail.ru"); console.log("\n=== Снова книги (проверка связи) ==="); await getBooks(); } main().then(() => { console.log("Работа завершена."); process.exit(0); // закрываем Node.js }).catch(err => { console.error("Фатальная ошибка:", err); process.exit(1); });
Запустите node index.js. Программа выполнит все действия по очереди и корректно завершит работу.

Правила безопасного кода

Запомните эти правила — они спасут ваш сервер от взлома и падений.

  1. Никаких паролей в коде. Только .env.
  2. Только параметры в SQL. Никаких ' + userInput + '. Только request.input().
  3. Всегда используйте try...catch. Ошибка не должна «ронять» весь сервер.
  4. Закрывайте пул при завершении. Используйте sql.close() в конце работы скрипта.
  5. Не используйте SELECT *. Выбирайте только нужные столбцы (например, SELECT Id, Name).
  6. Ограничивайте пул. В config можно указать pool: { max: 10 }, чтобы не перегрузить базу.
SQL-инъекция в Node.js блокируется только методом input(). Обычные кавычки в строке запроса не спасут.

Самостоятельные задания

Попробуйте расширить наш проект самостоятельно.

  1. Метод getReaders(): Выведите всех читателей из таблицы Readers.
  2. Метод getLoans(): Сделайте INNER JOIN между Loans, Books и Readers, чтобы показать, кто какую книгу взял.
  3. Метод returnBook(loanId): Напишите UPDATE, который ставит дату возврата в таблицу Loans.
  4. Валидация: Проверьте в addReader(), что email содержит символ @. Если нет — киньте ошибку throw new Error('Неверный email').
  5. Центральная ошибка: Сделайте функцию withDB(func), которая сама подключается, вызывает вашу функцию и закрывает соединение, чтобы не писать sql.connect() в каждом файле.
Для UPDATE используйте метод request.execute('ИмяХранимойПроцедуры') или обычный request.query('UPDATE ...').

Домашнее задание

Задания для сдачи практической работы.

  1. Реализуйте все 5 пунктов из «Самостоятельных заданий».
  2. Создайте файл books-by-author.js. Он должен принимать имя автора из аргументов командной строки (process.argv[2]) и выводить его книги через PreparedStatement (параметры).
  3. Добавьте в package.json скрипт "start": "node index.js", чтобы запускать программу командой npm start.
  4. Напишите в отчете: чем async/await удобнее, чем обычные функции с then() (приведите пример кода).
  5. Проверьте: если в .env написать неправильный пароль, программа должна выдать понятную ошибку в консоль, а не «упасть» с белым экраном.
Аргументы командной строки: node books-by-author.js "Лев Толстой". Внутри кода: const author = process.argv[2];

Спасибо за работу!

🟨

JavaScript теперь умеет работать с базой данных!

Вы прошли путь от установки Node.js до написания безопасного кода, который читает и пишет данные в MS SQL Server. Это фундамент для создания современных сайтов (REST API).

🟨 Node.js 📦 npm 🪟 MS SQL Server 🛡️ mssql 🚀 async/await