Webbplatssökning

Hur man använder Sequelize med Node.js och MySQL


Författaren valde Open Internet/Free Speech Fund för att ta emot en donation som en del av Write for Donations-programmet.

Introduktion

Sequelize är en Node.js-baserad objekt-relations-mapper som gör det enkelt att arbeta med MySQL-, MariaDB-, SQLite-, PostgreSQL-databaser och fler. En objekt-relations-mapper utför funktioner som att hantera databasposter genom att representera data som objekt. Sequelize har en kraftfull migrationsmekanism som kan omvandla befintliga databasscheman till nya versioner. Sammantaget erbjuder Sequelize utmärkt stöd för databassynkronisering, eager loading, associationer, transaktioner och databas-migrationer, samtidigt som utvecklingstiden minskar och SQL-injektioner förhindras.

I den här handledningen kommer du att installera och konfigurera Sequelize med MySQL på din lokala utvecklingsmiljö. Därefter kommer du att använda Sequelize för att skapa databaser och modeller samt utföra insert, select och delete-operationer. Sedan kommer du att skapa Sequelize-associationer för one-to-one, one-to-many och many-to-many-relationer. Slutligen kommer du att skapa Sequelize-raw queries för array- och objektersättning. Förutom dessa grundläggande delar täcker handledningen även säker databas-konfiguration med hjälp av miljövariabler, hantering av schemaändringar på ett säkert sätt genom migrationer, samt bästa praxis för felsökning och prestandaoptimering.

Distribuera dina frontend-applikationer från GitHub med Linux-Console.net App Platform. Låt Linux-Console.net ta hand om att skala din app.

Viktiga punkter:

  • Sequelize erbjuder ett enkelt sätt att interagera med MySQL genom att använda modeller istället för rå SQL, vilket gör databasoperationer enklare och mer organiserade.
  • Att lagra databasuppgifter i miljövariabler håller känslig information säker och utanför versionskontroll.
  • Att använda migrationer för schemauppdateringar är säkrare än att förlita sig på sequelize.sync(), särskilt i produktionsmiljöer.
  • Sequelize gör det enkelt att definiera en-till-en, en-till-många och många-till-många relationer mellan modeller.
  • Råa SQL-frågor kan fortfarande användas när du behöver mer kontroll eller bättre prestanda för komplexa databasoperationer.
  • De vanligaste problemen med Sequelize, såsom anslutningsfel eller migrationsfel, kan lösas genom att kontrollera miljövariabler, granska loggar och använda MySQL-verktyg som EXPLAIN och SHOW PROCESSLIST.
  • Prestanda kan förbättras genom att optimera frågor, lägga till lämpliga index, justera anslutningspooler och cachelagra ofta åtkomlig data.
  • Att testa migrationer, lägga till felhantering och övervaka databasens prestanda hjälper till att hålla Sequelize-applikationer pålitliga och redo för produktion.

Förutsättningar

För att slutföra denna handledning behöver du:

  • En utvecklingsmiljö som kör Node.js. För att ställa in detta, följ tutorialen Hur man installerar Node.js och skapar en lokal utvecklingsmiljö för ditt operativsystem.
  • MySQL installerat i din arbetsmiljö. Följ guiden Hur man installerar MySQL för din miljö, inklusive stegen för att skapa en användare.
  • Bekantskap med JavaScript och MySQL-frågor, vilket du kan utveckla med serien Hur man kodar i JavaScript och handledningen En introduktion till frågor i MySQL.
  • En grundläggande förståelse för koncepten för relationsdatabaser, som du kan hitta i handledningen Understanding Relational Databases.

Denna handledning testades på Node.js version v24.11.1 och npm version 11.6.2.

Installera och konfigurera Sequelize

I det här steget kommer du att installera Sequelize och skapa anslutningen till din MySQL-databas. För att göra det kommer du först att skapa en Node.js-applikation. Sedan kommer du att installera Sequelize, konfigurera MySQL-databasen och utveckla en enkel applikation.

Installera Sequelize

Börja med att skapa en projektmapp. I det här exemplet kan du använda hello-world. När mappen är skapad, navigera till mappen med terminalen:

mkdir hello-world

cd hello-world

Skapa sedan en exempelapplikation i Node.js med följande kommando:

npm init

Nästa steg är att du kommer att uppmanas att svara på några installationsfrågor. Använd följande output för din konfiguration. Tryck på ENTER för att använda standardvärdet som visas och se till att ange huvudentrén som server.js. Detta skapar en projektstruktur som är lätt att underhålla.

Utdata kommer att se ut som följer, vilket kommer att fylla package.json-filen:

{
  "name": "hello-world",
  "version": "1.0.0",
  "description": "",
  "main": "server.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}

Skapa sedan en tom server.js-fil i projektmappen:

touch server.js

Efter att ha följt de tidigare stegen kommer din slutliga mappstruktur att se ut så här:

hello-world/
├─ package.json
├─ server.js

Nu kan du installera Sequelize med följande kommando:

npm i sequelize

Efter dessa uppdateringar ser package.json-filen nu ut så här:

{
  "name": "hello-world",
  "version": "1.0.0",
  "description": "",
  "main": "server.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "node server.js"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "sequelize": "^6.37.7"
  }
}

I avsnittet dependencies kommer du nu att se ett Sequelize-beroende.

Du har satt upp projektet och installerat Sequelize. Nästa steg är att skapa en exempel-databas att koppla upp mot.

Skapa en exempel-databas

Som en del av förutsättningarna installerade och konfigurerade du MySQL, vilket inkluderade att skapa en användare. Nu kommer du att skapa en tom databas.

För att göra det måste du först logga in på din MySQL-instans. Om du kör den på distans kan du använda ditt föredragna verktyg. Om du använder en MySQL-instans som körs lokalt kan du använda följande kommando, och ersätta your_username med ditt MySQL-användarnamn:

mysql -u your_username -p

-u är användarnamnet och -p-alternativet används om kontot är skyddat med ett lösenord.

MySQL-servern kommer att be om ditt databaslösenord. Skriv ditt lösenord och tryck på ENTER.

När du har loggat in, skapa en databas som heter hello_world_db med följande kommando:

CREATE DATABASE hello_world_db;

För att kontrollera om du har skapat databasen framgångsrikt kan du använda detta kommando:

SHOW DATABASES;

Din utmatning kommer att likna detta:

+--------------------+
|      Database      |
+--------------------+
| hello_world_db     |
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+

Efter att ha skapat exempel-databasen, koppla från MySQL-servern:

mysql> QUIT

Nu behöver du installera en manuell drivrutin för den databas du väljer. Eftersom Sequelize endast tillhandahåller ORM-funktioner, inkluderar det inte inbyggda databaskontroller. Därför måste du installera drivrutiner enligt din preferens. För att göra det, navigera till projektmappen med terminalen och installera MySQL-drivrutinen till projektet med följande kommando:

npm install --save mysql2

I det här fallet använder du drivrutinen för MySQL.

Observera: Eftersom denna handledning använder MySQL som databas, använder du en drivrutin för det. Beroende på din databas kan du manuellt installera drivrutinen på följande sätt:

  • npm install --save pg pg-hstore # Postgres
  • npm install --save mysql2
  • npm install --save mariadb
  • npm install --save sqlite3
  • npm install --save tedious # Microsoft SQL Server

Nu när du har en exempel-databas kan du skapa din första Sequelize-applikation med databaskoppling.

Ansluter till MySQL-databasen

I det här avsnittet kommer du att ansluta Node.js-applikationen till MySQL-databasen med Sequelize.

För att ansluta till databasen, öppna server.js för redigering med nano eller din föredragna kodredigerare:

nano server.js

Här kommer du att skapa en databaskoppling i din applikation med hjälp av en Sequelize-instans. I new Sequelize()-metoden, ange MySQL-serverparametrarna och databasuppgifterna på följande sätt, och ersätt DATABASE_USERNAME och DATABASE_PASSWORD med uppgifterna för din MySQL-användare:

const Sequelize = require("sequelize");
const sequelize = new Sequelize(
 'hello_world_db',
 'DATABASE_USERNAME',
 'DATABASE_PASSWORD',
  {
    host: 'DATABASE_HOST',
    dialect: 'mysql'
  }
);

host är där MySQL-servern är hostad, så du behöver ange en server-URL eller en IP-adress. Om du använder en lokalt installerad MySQL-server kan du ersätta DATABASE_HOST med localhost eller 127.0.0.1 som värde.

På samma sätt, om du använder en fjärrserver, se till att ersätta databaskopplingsvärden med lämpliga uppgifter för fjärrservern.

Observera: Om du använder någon annan databasserverprogramvara kan du ersätta dialektparametern därefter.

Anropa sedan en promise-baserad authenticate()-metod för att skapa en databaskoppling till applikationen. För att göra det, lägg till följande kodblock i din server.js-fil:

...

sequelize.authenticate().then(() => {
   console.log('Connection has been established successfully.');
}).catch((error) => {
   console.error('Unable to connect to the database: ', error);
});

Metoden authenticate() används för att ansluta till databasen och testar om de angivna uppgifterna är korrekta. Här är databasanslutningen öppen som standard och samma anslutning kan användas för alla frågor. När du behöver stänga anslutningen, anropa sequelize.close()-metoden efter detta authenticate()-anrop. För att lära dig mer om Sequelize, se deras guide för att komma igång.

De flesta metoder som tillhandahålls av Sequelize är asynkrona. Det innebär att du kan köra processer i din applikation medan ett asynkront kodblock körs. Efter att det asynkrona kodblocket har körts framgångsrikt, returnerar det ett promise, vilket är värdet som returneras i slutet av en process. Därför kan du i asynkrona kodblock använda then(), catch() och finally() för att returnera de bearbetade uppgifterna.

Vid denna punkt kommer filen server.js att se ut som följer:

const Sequelize = require("sequelize");

const sequelize = new Sequelize(
   'hello_world_db',
   'DATABASE_USERNAME',
   'DATABASE_PASSWORD',
    {
      host: 'DATABASE_HOST',
      dialect: 'mysql'
    }
  );

sequelize.authenticate().then(() => {
   console.log('Connection has been established successfully.');
}).catch((error) => {
   console.error('Unable to connect to the database: ', error);
});

Spara och stäng din fil.

I projektmappen kör du server.js-applikationen genom att köra följande kommando:

node server.js

Din utmatning kommer att se ut så här:

Connection has been established successfully!

Du har skapat databasanslutningen framgångsrikt.

I det här steget installerade du Sequelize, skapade en exempel-databas och använde Sequelize för att ansluta till databasen. Nästa steg är att arbeta med modeller i Sequelize.

Skapa en databastabell med Sequelize

Nu när du har skapat en exempel MySQL-databas kan du använda Sequelize för att skapa en tabell och fylla den med data. I Sequelize refereras databasens tabeller till som modeller. En modell är en abstraktion som representerar en tabell i databasen. Modeller definierar flera saker för Sequelize, såsom tabellens namn, kolumndetaljer och datatyper. I detta steg kommer du att skapa en Sequelize-modell för bokdata.

För att börja, skapa en ny fil som heter book.model.js i projektmappen:

nano book.model.js

På liknande sätt som i föregående steg, lägg till Sequelize-koden för databasinitiering med en ny import för DataTypes högst upp i filen:

const { Sequelize, DataTypes } = require("sequelize");

Sequelize innehåller många inbyggda datatyper. För att komma åt dessa datatyper lägger du till en import för DataTypes. Denna handledning hänvisar till några ofta använda datatyper, såsom STRING, INTEGER och DATEONLY. För att lära dig mer om andra stödda datatyper kan du hänvisa till den officiella Sequelize-dokumentationen.

Inkludera sedan de rader du tidigare använde för att skapa en anslutning till din MySQL-databas och uppdatera dina MySQL-uppgifter i enlighet därmed:

...

const sequelize = new Sequelize(
   'hello_world_db',
   'DATABASE_USERNAME',
   'DATABASE_PASSWORD',
    {
      host: 'DATABASE_HOST',
      dialect: 'mysql'
    }
  );

sequelize.authenticate().then(() => {
   console.log('Connection has been established successfully.');
}).catch((error) => {
   console.error('Unable to connect to the database: ', error);
});

Nästa steg är att skapa en modell som kallas books, som inkluderar title, author, release_date och subject-ID. För att göra det, använd sequelize.define()-metoden som visas:

...

const Book = sequelize.define("books", {
   title: {
     type: DataTypes.STRING,
     allowNull: false
   },
   author: {
     type: DataTypes.STRING,
     allowNull: false
   },
   release_date: {
     type: DataTypes.DATEONLY,
   },
   subject: {
     type: DataTypes.INTEGER,
   }
});

Metoden sequelize.define() definierar en ny modell, som representerar en tabell i databasen. Den här kodblocket skapar en tabell som heter books och lagrar bokposter enligt title, author, release_date och subject.

I den här koden visar allowNull att modellkolumnens värde inte kan vara null. På samma sätt, om du behöver ange ett sådant värde, kan du använda defaultValue: "value".

Nästa steg är att lägga till book-modellen i din databas. För att göra det använder du sync()-metoden på följande sätt:

...

sequelize.sync().then(() => {
   console.log('Book table created successfully!');
}).catch((error) => {
   console.error('Unable to create table : ', error);
});

I sync()-metoden ber du Sequelize att göra några saker med databasen. Med detta anrop kommer Sequelize automatiskt att utföra en SQL-fråga mot databasen och skapa en tabell, samtidigt som meddelandet Book table created successfully! skrivs ut.

Som nämnts är sync()-metoden en metod baserad på löften, vilket innebär att den också kan hantera fel. I denna kodblock kommer du att kontrollera om tabellen skapades framgångsrikt. Om inte, kommer den att returnera ett fel via catch-metoden och skriva ut det i utdata.

Observera: Du kan hantera modellsynkronisering genom att ange force-parametrar för att tvinga skapandet av en ny tabell om den inte finns, eller använda en befintlig. Här är några exempel som kan vara användbara när du arbetar med Sequelize:

  • model.sync(): Detta skapar tabellen om den inte redan finns.
  • model.sync({ force: true }): Detta skapar tabellen genom att ta bort den om samma tabell redan finns.

Den slutliga koden kommer att se ut så här:

const {Sequelize, DataTypes} = require("sequelize");

const sequelize = new Sequelize(
   'hello_world_db',
   'DATABASE_USERNAME',
   'DATABASE_PASSWORD',
    {
      host: 'DATABASE_HOST',
      dialect: 'mysql'
    }
  );

sequelize.authenticate().then(() => {
   console.log('Connection has been established successfully.');
}).catch((error) => {
   console.error('Unable to connect to the database: ', error);
});

const Book = sequelize.define("books", {
   title: {
     type: DataTypes.STRING,
     allowNull: false
   },
   author: {
     type: DataTypes.STRING,
     allowNull: false
   },
   release_date: {
     type: DataTypes.DATEONLY,
   },
   subject: {
     type: DataTypes.INTEGER,
   }
});

sequelize.sync().then(() => {
   console.log('Book table created successfully!');
}).catch((error) => {
   console.error('Unable to create table : ', error);
});

Spara och stäng din fil.

Kör din applikation med följande kommando:

node book.model.js

Du kommer att få följande utdata i din kommandorad:

Executing (default): SELECT 1+1 AS result
Executing (default): CREATE TABLE IF NOT EXISTS `books` (`id` INTEGER NOT NULL auto_increment , `title` VARCHAR(255) NOT NULL, `author` VARCHAR(255) NOT NULL, `release_date` DATE, `subject` INTEGER, `createdAt` DATETIME NOT NULL, `updatedAt` DATETIME NOT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB;
Connection has been established successfully.
Executing (default): SHOW INDEX FROM `books`
Book table created successfully!

I utskriften kommer du att se att returloggen innehåller meddelandet, Book table created successfully!. Du kan verifiera detta genom att kontrollera din databas för att se den nya books-tabellen som skapats i hello_world_db-databasen.

För att verifiera skapandet av den nya tabellen, logga in på din MySQL-instans:

mysql -u YOUR_USERNAME -p

Efter att du har angett ditt lösenord, byt till exempel-databasen:

USE hello_world_db;

Och kör sedan kommandot för att visa tabeller:

SHOW TABLES;

Din utmatning kommer att likna detta:

+---------------------------+
| Tables_in_hello_world_db |
+---------------------------+
| books                     |
+---------------------------+
1 row in set (0.00 sec)

Slutligen, koppla från MySQL-servern:

mysql> QUIT

Du har verifierat att skapandet av book-modellen lyckades. Genom att använda denna process kan du skapa valfritt antal modeller genom att följa samma procedur.

I det här steget skapade du en modell i en databas och började arbeta med modellen med hjälp av inbyggda metoder. Du använde också Sequelize-stödda datatyper för att definiera din modell. Nästa steg är att arbeta med grundläggande modellfrågor.

Använda Sequelize för databasfrågor

I detta steg kommer du att använda Sequelizes inbyggda frågor för insättning, urval, urval med villkorssatser och radering.

Infoga en ny post

I föregående steg skapade du en book-modell i databasen. I det här avsnittet kommer du att infoga data i den här modellen.

För att komma igång, kopiera innehållet från book.model.js från föregående steg. Skapa en ny fil som heter book.controller.js för att hantera frågelogiken. Lägg till koden från book.model.js i book.controller.js.

I book.controller.js, hitta sync()-metoden. I sync()-metoden, lägg till följande markerade rader:

...

sequelize.sync().then(() => {
   console.log('Book table created successfully!');

   Book.create({
       title: "Clean Code",
       author: "Robert Cecil Martin",
       release_date: "2021-12-14",
       subject: 3
   }).then(res => {
       console.log(res)
   }).catch((error) => {
       console.error('Failed to create a new record : ', error);
   });

}).catch((error) => {
   console.error('Unable to create table : ', error);
});

Här infogar du en ny bokpost i books-modellen som du redan har skapat med hjälp av sync()-metoden, som stöder att lägga till nya poster i tidigare skapade modeller. När sync()-metoden körs framgångsrikt körs then()-metoden. Inuti then()-metoden anropar du create()-metoden för att infoga de nya posterna i modellen.

Du använder create()-metoden för att skicka de data du behöver lägga till i databasen som ett objekt. Den markerade delen av koden kommer att infoga en ny post i din befintliga books-tabell. I det här exemplet lägger du till Clean Code av Robert Cecil Martin, som har kategoriserats med ämnes-ID 3. Du kan använda samma kod, uppdaterad med information om andra böcker, för att lägga till nya poster i din databas.

Spara och stäng filen.

Kör applikationen med följande kommando:

node book.controller.js

Ditt resultat kommer att se ungefär ut så här:

books {
  dataValues:
   { id: 1,
     title: 'Clean Code',
     author: 'Robert Cecil Martin',
     release_date: '2021-12-14',
     subject: 3,
     updatedAt: 2021-12-14T10:12:16.644Z,
   ...
}

Du har lagt till en ny post i modellen du skapade i databasen. Du kan fortsätta att lägga till flera poster med samma process.

Markera alla poster

I det här avsnittet kommer du att välja och hämta alla bokposter från databasen med metoden findAll(). För att göra det, öppna först book.controller.js och ta bort den tidigare metoden Book.create(). I metoden sync(), lägg till metoden Book.findAll() som visas:

...

sequelize.sync().then(() => {

    Book.findAll().then(res => {
        console.log(res)
    }).catch((error) => {
        console.error('Failed to retrieve data : ', error);
    });

}).catch((error) => {
    console.error('Unable to create table : ', error);
});

...

Spara och stäng filen.

Kör sedan programmet igen med följande kommando:

node book.controller.js

Ditt resultat kommer att se ungefär ut så här:

[
  books {
    dataValues: {
      id: 1,
      title: 'Clean Code',
      author: 'Robert Cecil Martin',
      release_date: '2020-01-01',
      subject: 3,
      createdAt: 2021-02-22T09:13:55.000Z,
      updatedAt: 2021-02-22T09:13:55.000Z
    },
    _previousDataValues: {
      id: 1,
      title: 'Clean Code',
      author: 'Robert Cecil Martin',
      release_date: '2020-01-01',
      subject: 3,
      createdAt: 2021-02-22T09:13:55.000Z,
      updatedAt: 2021-02-22T09:13:55.000Z
    },
...
]

Utdata innehåller all bokdata som ett array-objekt. Du använde framgångsrikt Sequelize findAll()-metoden för att hämta all bokdata från databasen.

Välja med where-satsen

I det här avsnittet kommer du att välja värden med villkor med hjälp av where-satsen. where-satsen används för att ange ett villkor när du hämtar data. För den här handledningen kommer du att hämta en bok med ett specifikt post-ID från databasen med hjälp av findOne()-metoden.

För att göra det, öppna book.controller.js för redigering, ta bort findAll()-metoden och lägg till följande rader:

...

sequelize.sync().then(() => {

    Book.findOne({
        where: {
            id: 1
        }
    }).then(res => {
        console.log(res)
    }).catch((error) => {
        console.error('Failed to retrieve data : ', error);
    });

}).catch((error) => {
    console.error('Unable to create table : ', error);
});

Här väljer du en specifik bokpost från databasen med metoden findOne() och alternativet where. I det här exemplet hämtar du bokinformationen där id är lika med 1.

Spara och stäng filen.

Sedan, kör applikationen:

node book.controller.js

Ditt resultat kommer att se ungefär ut så här:

books {
  dataValues: {
    id: 1,
    title: 'Clean Code',
    author: 'Robert Cecil Martin',
    release_date: '2020-01-01',
    subject: 'Science',
    createdAt: 2021-02-22T09:13:55.000Z,
    updatedAt: 2021-02-22T09:13:55.000Z
  },
  ...
}

Du har framgångsrikt använt where-satser för att hämta data från Sequelize-modeller. Du kan använda where-satsen i databasanvändningen för att fånga villkorlig data.

Ta bort en post

För att radera en specifik post från databasmodellen använder du destroy()-metoden med where-alternativet. För att göra det, öppna book.controller.js, ta bort findOne()-metoden och lägg till följande markerade rader:

...
sequelize.sync().then(() => {

  Book.destroy({
      where: {
        id: 2
      }
  }).then(() => {
      console.log("Successfully deleted record.")
  }).catch((error) => {
      console.error('Failed to delete record : ', error);
  });

}).catch((error) => {
    console.error('Unable to create table : ', error);
});

Här tar du bort en bokpost från databasen genom att använda destroy()-metoden med where-alternativet och ange id på boken som ska tas bort. Du kommer att ta bort bokposten vars id är 2.

Spara och stäng filen.

Sedan, kör applikationen:

node book.controller.js

Din utmatning kommer att se ut som följande:

Successfully deleted record.

Posten har raderats.

I det här steget experimenterade du med din databasmodell och modellfrågor. Du startade databasen, skapade modeller, infogade poster, hämtade poster, hämtade poster med villkor med hjälp av where-satser, och tog bort utvalda poster. Med denna kunskap om Sequelize kommer du nu att skapa associationer i Sequelize. Därefter kommer du kunna definiera och arbeta med olika typer av relationer med Sequelize-modeller.

Skapa associationer med Sequelize

I det här steget kommer du att använda de standardtyper av associationer som Sequelize stöder: en-till-en, en-till-många och många-till-många associationer. Du kommer att använda exempeldata om studenter, kurser och betygsnivåer.

Sequelize använder associationstyper baserade på följande databaserelationer:

  • en-till-en relation: En en-till-en-relation innebär att en post i en tabell är kopplad till exakt en post i en annan tabell. När det gäller Sequelize kan du använda belongsTo() och hasOne()-associationer för att skapa denna typ av relation.

  • en-till-många relation: En en-till-många-relation innebär att en post i en tabell är kopplad till flera poster i en annan tabell. Med Sequelize kan du använda hasMany()-associationsmetoder för att skapa denna typ av relation.

  • många-till-många-relation: En många-till-många-relation betyder att flera poster i en tabell är kopplade till flera poster i en annan tabell. Med Sequelize kan du använda belongsToMany()-associationer för att skapa denna typ av relation.

Innan du skapar dessa associationer kommer du först att skapa en ny databas som heter student_db och lägga till nya modeller samt några exempeldata för studenter, kurser och betygsnivå.

För att skapa databasen, följ samma process som i Installing and Configuring Sequelize för att logga in på MySQL och skapa en databas som heter student_db. När den nya databasen har skapats, logga ut från MySQL. Nästa steg är att börja skapa databasassociationer.

Skapa en en-till-en-relation med belongsTo()

I det här avsnittet kommer du att skapa en en-till-en-relation med hjälp av Sequelize-modeller. Föreställ dig att du vill hämta en students detaljer tillsammans med deras betygsnivå. Eftersom en student endast kan ha en betygsnivå är denna typ av association en en-till-en-relation och du kan använda belongsTo()-metoden.

Observera: Det finns en skillnad mellan belongsTo() och hasOne(). belongsTo() kommer att lägga till foreignKey i källtabellen, medan hasOne() kommer att lägga till det i måltabellen. I vilket fall som helst, om båda relationerna används samtidigt, kommer det att fungera som Sequelize bidirektionella en-till-en-relationer.

Metoden belongsTo() låter dig skapa en en-till-en-relation mellan två Sequelize-modeller. I det här exemplet använder du Student och Grade-modellerna.

Skapa en ny fil som heter one_to_one.js. Precis som du gjorde i föregående avsnitt, Ansluta till MySQL-databasen, inkludera raderna för att skapa en anslutning till databasen och autentisera din MySQL-användare högst upp i filen. Se till att uppdatera MySQL-uppgifterna vid behov:

const { Sequelize, DataTypes } = require("sequelize");

const sequelize = new Sequelize(
   'student_db',
   'DATABASE_USERNAME',
   'DATABASE_PASSWORD',
    {
      host: 'DATABASE_HOST',
      dialect: 'mysql'
    }
  );

sequelize.authenticate().then(() => {
   console.log('Connection has been established successfully.');
}).catch((error) => {
   console.error('Unable to connect to the database: ', error);
});

I det här avsnittet kommer du att skapa tre modeller i den nya student_db-databasen: Student, Grade och Course. Du börjar med att skapa Student- och Grade-modellerna. Senare i det här steget kommer du att skapa Courses-modellen.

För Student-modellen, lägg till följande kodblock i one_to_one.js:

...
const Student = sequelize.define("students", {
   student_id: {
       type: DataTypes.UUID,
       defaultValue: DataTypes.UUIDV4,
       primaryKey: true,
   },
   name: {
       type: DataTypes.STRING,
       allowNull: false
   }
});

Denna studentmodell innehåller två kolumner: student_id och name.

Nästa, lägg till ett kodblock för Grade-modellen:

...
const Grade = sequelize.define("grades", {
   grade: {
       type: DataTypes.INTEGER,
       allowNull: false
   }
});

Modellen Grade innehåller kolumnen grade.

För att demonstrera associationerna behöver du lägga till exempeldata i databasen. För det använder du bulk()-metoden. Istället för att infoga data i rader en åt gången, gör bulkCreate()-metoden det möjligt att infoga flera rader i dina databasmodeller på en gång.

Så nu, importera Grade och Student data till deras respektive modeller i databasen som visas:

...
const grade_data = [{grade : 9}, {grade : 10}, {grade : 11}]

const student_data = [
   {name : "John Baker", gradeId: 2},
   {name : "Max Butler", gradeId: 1},
   {name : "Ryan Fisher", gradeId: 3},
   {name : "Robert Gray", gradeId: 2},
   {name : "Sam Lewis", gradeId: 1}
]

sequelize.sync({ force: true }).then(() => {
   Grade.bulkCreate(grade_data, { validate: true }).then(() => {
       Student.bulkCreate(student_data, { validate: true }).then(() => {
           …
       }).catch((err) => { console.log(err); });
   }).catch((err) => { console.log(err); });
}).catch((error) => {
   console.error('Unable to create the table : ', error);
});

Här tillhandahåller du exempeldata och infogar datan i Student- och Grade-modellerna. Med din databas, modeller och exempeldata på plats är du redo att skapa associationer.

I one-to-one.js, lägg till följande rad under student_data-blocket:

...
Student.belongsTo(Grade);

Nästa steg är att kontrollera om associationen fungerar korrekt. För att göra det kan du hämta all studentdata med tillhörande betygsnivåer genom att skicka med include-parametern i findAll()-metoden.

Eftersom du behöver få studentens betygsnivå, skickar du Grade som modellen. I metoden sequelize.sync(), lägg till de markerade raderna som visas:

...
sequelize.sync({ force: true }).then(() => {
   Grade.bulkCreate(grade_data, { validate: true }).then(() => {
       Student.bulkCreate(student_data, { validate: true }).then(() => {
           Student.findAll({
               include: [{
                   model: Grade
               }]
           }).then(result => {
               console.log(result)
           }).catch((error) => {
               console.error('Failed to retrieve data : ', error);
           });
       }).catch((err) => { console.log(err); });
   }).catch((err) => { console.log(err); });
}).catch((error) => {
   console.error('Unable to create the table : ', error);
});

Den kompletta koden ser ut som följer:

const {Sequelize, DataTypes} = require("sequelize");

const sequelize = new Sequelize(
   'student_db',
   'DATABASE_USERNAME',
   'DATABASE_PASSWORD',
    {
      host: 'DATABASE_HOST',
      dialect: 'mysql'
    }
  );
sequelize.authenticate().then(() => {
   console.log('Connection has been established successfully.');
}).catch((error) => {
   console.error('Unable to connect to the database: ', error);
});

const Student = sequelize.define("students", {
   student_id: {
       type: DataTypes.UUID,
       defaultValue: DataTypes.UUIDV4,
       primaryKey: true,
   },
   name: {
       type: DataTypes.STRING,
       allowNull: false
   }
});

const Grade = sequelize.define("grades", {
   grade: {
       type: DataTypes.INTEGER,
       allowNull: false
   }
});

const grade_data = [{grade : 9}, {grade : 10}, {grade : 11}]

const student_data = [
   {name : "John Baker", gradeId: 2},
   {name : "Max Butler", gradeId: 1},
   {name : "Ryan Fisher", gradeId: 3},
   {name : "Robert Gray", gradeId: 2},
   {name : "Sam Lewis", gradeId: 1}
]

// One-To-One association
Student.belongsTo(Grade);

sequelize.sync({ force: true }).then(() => {
   Grade.bulkCreate(grade_data, { validate: true }).then(() => {
       Student.bulkCreate(student_data, { validate: true }).then(() => {
           Student.findAll({
               include: [{
                   model: Grade
               }]
           }).then(result => {
               console.log(result)
           }).catch((error) => {
               console.error('Failed to retrieve data : ', error);
           });
       }).catch((err) => { console.log(err); });
   }).catch((err) => { console.log(err); });
}).catch((error) => {
   console.error('Unable to create the table : ', error);
});

Spara och stäng din fil.

Kör filen med följande kommando:

node one_to_one.js

Utdata kommer att vara lång, och du kommer att se allas elevers data med betygsnivåer. Här är ett utdrag av utdata som visar elevdata:

students {
    dataValues:
   { student_id: '3e786a8f-7f27-4c59-8e9c-a8c606892288',
       name: 'Sam Lewis',
       createdAt: 2021-12-16T08:49:38.000Z,
       updatedAt: 2021-12-16T08:49:38.000Z,
       gradeId: 1,
       grade: [grades] },
    _previousDataValues:
...

Beroende på vilka kommandoradsverktyg du använder kan utskriften visas som en utökad vy eller inte. Om det är en utökad vy skrivs det utökade grade-objektet som output.

I det här avsnittet skapade du en en-till-en-relation med metoden Student.belongsTo(Grade); och fick detaljerna enligt den association du skapade.

Skapa en en-till-många-relation med hasMany()

I det här avsnittet kommer du att skapa en en-till-många-relation med hjälp av Sequelize-modeller. Föreställ dig att du vill hämta alla elever som är kopplade till en vald årskurs. Eftersom en specifik årskurs kan ha flera elever, är detta en en-till-många-relation.

För att komma igång, kopiera innehållet i one_to_one.js till en ny fil som heter one_to_many.js. I one_to_many.js tar du bort raderna efter student_data-blocket. Din one_to_many.js-fil kommer att se ut så här:

const {Sequelize, DataTypes} = require("sequelize");

const sequelize = new Sequelize(
   'student_db',
   'DATABASE_USERNAME',
   'DATABASE_PASSWORD',
    {
      host: 'DATABASE_HOST',
      dialect: 'mysql'
    }
  );

sequelize.authenticate().then(() => {
   console.log('Connection has been established successfully.');
}).catch((error) => {
   console.error('Unable to connect to the database: ', error);
});

const Student = sequelize.define("students", {
   student_id: {
       type: DataTypes.UUID,
       defaultValue: DataTypes.UUIDV4,
       primaryKey: true,
   },
   name: {
       type: DataTypes.STRING,
       allowNull: false
   }
});
const Grade = sequelize.define("grades", {
   grade: {
       type: DataTypes.INTEGER,
       allowNull: false
   }
});

const grade_data = [ {grade : 9}, {grade : 10}, {grade : 11}]

const student_data = [
   {name : "John Baker", gradeId: 2},
   {name : "Max Butler", gradeId: 1},
   {name : "Ryan Fisher", gradeId: 3},
   {name : "Robert Gray", gradeId: 2},
   {name : "Sam Lewis", gradeId: 1}
]

Efter student_data-blocket, använd hasMany()-metoden för att skapa en ny relation:

...
Grade.hasMany(Student)

Metoden hasMany() låter dig skapa en en-till-många-relation mellan två Sequelize-modeller. Här använder du Grade och Student-modellerna.

Nästa steg är att lägga till sequelize.sync()-metoden med findAll()-metoden under raden med hasMany():

...
sequelize.sync({ force: true }).then(() => {
   Grade.bulkCreate(grade_data, { validate: true }).then(() => {
       Student.bulkCreate(student_data, { validate: true }).then(() => {
           Grade.findAll({
               where: {
                   grade: 9
               },
               include: [{
                   model: Student
               }]
           }).then(result => {
               console.dir(result, { depth: 5 });
           }).catch((error) => {
               console.error('Failed to retrieve data : ', error);
           });
       }).catch((err) => { console.log(err); });
   }).catch((err) => { console.log(err); });
}).catch((error) => {
   console.error('Unable to create table : ', error);
});

Här försöker du få åtkomst till alla elever på en viss årskurs—in i det här fallet, alla elever i årskurs 9. Du lade också till Student-modellen i include-alternativet.

Här är den kompletta koden:

const {Sequelize, DataTypes} = require("sequelize");

const sequelize = new Sequelize(
   'student_db',
   'DATABASE_USERNAME',
   'DATABASE_PASSWORD',
    {
      host: 'DATABASE_HOST',
      dialect: 'mysql'
    }
  );

sequelize.authenticate().then(() => {
   console.log('Connection has been established successfully.');
}).catch((error) => {
   console.error('Unable to connect to the database: ', error);
});

const Student = sequelize.define("students", {
   student_id: {
       type: DataTypes.UUID,
       defaultValue: DataTypes.UUIDV4,
       primaryKey: true,
   },
   name: {
       type: DataTypes.STRING,
       allowNull: false
   }
});
const Grade = sequelize.define("grades", {
   grade: {
       type: DataTypes.INTEGER,
       allowNull: false
   }
});

const grade_data = [ {grade : 9}, {grade : 10}, {grade : 11}]

const student_data = [
   {name : "John Baker", gradeId: 2},
   {name : "Max Butler", gradeId: 1},
   {name : "Ryan Fisher", gradeId: 3},
   {name : "Robert Gray", gradeId: 2},
   {name : "Sam Lewis", gradeId: 1}
]

// One-To-Many relationship
Grade.hasMany(Student);

sequelize.sync({ force: true }).then(() => {
   Grade.bulkCreate(grade_data, { validate: true }).then(() => {
       Student.bulkCreate(student_data, { validate: true }).then(() => {
           Grade.findAll({
               where: {
                   grade: 9
               },
               include: [{
                   model: Student
               }]
           }).then(result => {
               console.dir(result, { depth: 5 });
           }).catch((error) => {
               console.error('Failed to retrieve data : ', error);
           });
       }).catch((err) => { console.log(err); });
   }).catch((err) => { console.log(err); });
}).catch((error) => {
   console.error('Unable to create table : ', error);
});

Spara och stäng din fil.

Kör filen med följande kommando:

node one_to_many.js

Utdata kommer att se ut ungefär som följande. Den kommer att vara ganska lång, men alla elever i årskurs 9 kommer att returneras på följande sätt:

[ grades {
    dataValues:
     { id: 1,
       grade: 9,
       createdAt: 2021-12-20T05:12:31.000Z,
       updatedAt: 2021-12-20T05:12:31.000Z,
       students:
        [ students {
            dataValues:
             { student_id: '8a648756-4e22-4bc0-8227-f590335f9965',
               name: 'Sam Lewis',
               createdAt: 2021-12-20T05:12:31.000Z,
               updatedAt: 2021-12-20T05:12:31.000Z,
               gradeId: 1 },
...
          students {
            dataValues:
             { student_id: 'f0304585-91e5-4efc-bdca-501b3dc77ee5',
               name: 'Max Butler',
               createdAt: 2021-12-20T05:12:31.000Z,
               updatedAt: 2021-12-20T05:12:31.000Z,
               gradeId: 1 },
...

I det här avsnittet skapade du en en-till-många-relation med hjälp av Grade.hasMany(Student);-metoden. I resultatet hämtade du uppgifterna enligt den association du skapade.

Skapa många-till-många-relationer med belongsToMany()

I det här avsnittet kommer du att skapa många-till-många-relationer med hjälp av Sequelize-modeller. Som ett exempel, föreställ dig en situation där studenter är inskrivna på kurser. En student kan vara inskriven på många kurser och en kurs kan ha många studenter. Detta är en många-till-många-relation. För att implementera detta med Sequelize kommer du att använda modellerna Student, Course och StudentCourse med metoden belongsToMany().

För att komma igång, skapa en fil som heter many_to_many.js och lägg till kodblocken för databasinitering och autentisering enligt följande. (Du kan återanvända kodblocken från det tidigare one_to_many.js-exemplet.) Se till att uppdatera de markerade värdena för databasanslutningen vid behov.

const {Sequelize, DataTypes} = require("sequelize");

const sequelize = new Sequelize(
   'student_db',
   'DATABASE_USERNAME',
   'DATABASE_PASSWORD',
    {
      host: 'DATABASE_HOST',
      dialect: 'mysql'
    }
);

sequelize.authenticate().then(() => {
    console.log('Connection has been established successfully.');
}).catch((error) => {
    console.error('Unable to connect to the database: ', error);
});

Nästa steg är att skapa databassmodellerna för många-till-många-relationer: Student och Course. Sedan kommer du att lägga till några exempeldata i dessa modeller.

...

const Student = sequelize.define("students", {
    student_id: {
        type: DataTypes.UUID,
        defaultValue: DataTypes.UUIDV4,
    },
    name: {
        type: DataTypes.STRING,
        allowNull: false
    }
});

const Course = sequelize.define("courses", {
    course_name: {
        type: DataTypes.STRING,
        allowNull: false
    }
});

const StudentCourse = sequelize.define('StudentCourse', {
    id: {
      type: DataTypes.INTEGER,
      primaryKey: true,
      autoIncrement: true,
      allowNull: false
    }
  });

const course_data = [
    {course_name : "Science"},
    {course_name : "Maths"},
    {course_name : "History"}
]

const student_data = [
    {name : "John Baker", courseId: 2},
    {name : "Max Butler", courseId: 1},
    {name : "Ryan Fisher", courseId: 3},
    {name : "Robert Gray", courseId: 2},
    {name : "Sam Lewis", courseId: 1}
]

const student_course_data = [
    {studentId : 1, courseId: 1},
    {studentId : 2, courseId: 1},
    {studentId : 2, courseId: 3},
    {studentId : 3, courseId: 2},
    {studentId : 1, courseId: 2},
]

Här skapar du Student- och Course-modellerna och tillhandahåller några exempeldata. Du sätter också ett courseID, som du kommer att använda för att hämta studenter enligt denna relationstyp.

Slutligen definierade du en ny modell som heter StudentCourse, som hanterar relationsdata mellan Student och Course. I detta exempel är studentId 1 inskriven i courseId 1 och courseId 2.

Du har slutfört databasinitieringen och lagt till exempeldata i databasen. Nästa steg är att skapa många-till-många-relationer med hjälp av belongsToMany()-metoden som visas:

...
Course.belongsToMany(Student, { through: 'StudentCourse'})
Student.belongsToMany(Course, { through: 'StudentCourse'})

Inom belongsToMany()-metoden skickar du through-konfigurationen med namnet på modellen som konfigurationsalternativ. I det här fallet är det StudentCourse. Detta är tabellen som hanterar många-till-många-relationerna.

Slutligen kan du kontrollera om associationen fungerar korrekt genom att hämta all kursdata med tillhörande studenter. Du gör det genom att skicka med parametern include i findAll()-metoden. Lägg till följande rader i many_to_many.js:

...
sequelize.sync({ force: true }).then(() => {
    Course.bulkCreate(course_data, { validate: true }).then(() => {
        Student.bulkCreate(student_data, { validate: true }).then(() => {
            StudentCourse.bulkCreate(student_course_data, { validate: true }).then(() => {
                Course.findAll({
                    include: {
                        model: Student,
                    },
                }).then(result => {
                    console.log(result);
                }).catch((error) => {
                    console.error('Failed to retrieve data : ', error);
                });
            }).catch((error) => {
                console.log(error);
            });
        }).catch((error) => {
            console.log(error);
        });
    }).catch((error) => {
        console.log(error);
    });
}).catch((error) => {
    console.error('Unable to create table : ', error);
});

Den kompletta koden ser ut som följer:

const {Sequelize, DataTypes} = require("sequelize");

const sequelize = new Sequelize(
   'student_db',
   'DATABASE_USERNAME',
   'DATABASE_PASSWORD',
    {
      host: 'DATABASE_HOST',
      dialect: 'mysql'
    }
);

sequelize.authenticate().then(() => {
   console.log('Connection has been established successfully.');
}).catch((error) => {
   console.error('Unable to connect to the database: ', error);
});

const Student = sequelize.define("students", {
    student_id: {
       type: DataTypes.UUID,
       defaultValue: DataTypes.UUIDV4,
    },
    name: {
       type: DataTypes.STRING,
       allowNull: false
    }
});

const Course = sequelize.define("courses", {
    course_name: {
        type: DataTypes.STRING,
        allowNull: false
    }
});

const StudentCourse = sequelize.define('StudentCourse', {
    id: {
      type: DataTypes.INTEGER,
      primaryKey: true,
      autoIncrement: true,
      allowNull: false
    }
  });

const course_data = [
    {course_name : "Science"},
    {course_name : "Maths"},
    {course_name : "History"}
]

const student_data = [
    {name : "John Baker", courseId: 2},
    {name : "Max Butler", courseId: 1},
    {name : "Ryan Fisher", courseId: 3},
    {name : "Robert Gray", courseId: 2},
    {name : "Sam Lewis", courseId: 1}
]

const student_course_data = [
    {studentId : 1, courseId: 1},
    {studentId : 2, courseId: 1},
    {studentId : 2, courseId: 3},
    {studentId : 3, courseId: 2},
    {studentId : 1, courseId: 2},
]

Course.belongsToMany(Student, { through: 'StudentCourse'})
Student.belongsToMany(Course, { through: 'StudentCourse'})

sequelize.sync({ force: true }).then(() => {
    Course.bulkCreate(course_data, { validate: true }).then(() => {
        Student.bulkCreate(student_data, { validate: true }).then(() => {
            StudentCourse.bulkCreate(student_course_data, { validate: true }).then(() => {
                Course.findAll({
                    include: {
                        model: Student,
                    },
                }).then(result => {
                    console.log(result);
                }).catch((error) => {
                    console.error('Failed to retrieve data : ', error);
                });
            }).catch((error) => {
                console.log(error);
            });
        }).catch((error) => {
            console.log(error);
        });
    }).catch((error) => {
        console.log(error);
    });
}).catch((error) => {
    console.error('Unable to create table : ', error);
});

Spara och stäng filen.

Kör filen med följande kommando:

node many_to_many.js

Utdata kommer att vara lång, men kommer att se ungefär ut som följande:

[ courses {
    dataValues:
     { id: 1,
       course_name: 'Science',
       createdAt: 2022-05-11T04:27:37.000Z,
       updatedAt: 2022-05-11T04:27:37.000Z,
       students: [Array] },
    _previousDataValues:
     { id: 1,
       course_name: 'Science',
       createdAt: 2022-05-11T04:27:37.000Z,
       updatedAt: 2022-05-11T04:27:37.000Z,
       students: [Array] },
    _changed: Set {},
    _options:
     { isNewRecord: false,
       _schema: null,
       _schemaDelimiter: '',
       include: [Array],
       includeNames: [Array],
       includeMap: [Object],
       includeValidated: true,
       attributes: [Array],
       raw: true },
    isNewRecord: false,
    students: [ [students], [students] ] },
  courses {
    dataValues:
     { id: 2,
       course_name: 'Maths',
       createdAt: 2022-05-11T04:27:37.000Z,
       updatedAt: 2022-05-11T04:27:37.000Z,
       students: [Array] },
    _previousDataValues:
...

Som du kan se i denna utskrift hämtades kurser med tillhörande studenter. Inom courses-blocket kommer du att se separata id-värden som anger varje kurs. Till exempel är id: 1 kopplat till course_name: Science för Science-klassen, medan id: 2 är Maths-klassen, och så vidare.

I databasen kan du se de tre genererade tabellerna med de exempeldata du infogade.

I det här steget använde du Sequelize för att skapa en-till-en-, en-till-många- och många-till-många-relationer. Nästa steg är att arbeta med råa frågor.

Arbeta med råa frågor

I det här steget kommer du att arbeta med råa frågor i Sequelize. I tidigare steg använde du Sequelizes inbyggda metoder, såsom insert() och findAll(), för att hantera datainsättning och urval från databasen. Du har kanske märkt att dessa metoder följer ett specifikt mönster för att skriva en fråga. Med användning av råa frågor behöver du dock inte bekymra dig om Sequelizes inbyggda metoder och mönster. Med din kunskap om SQL-frågor kan du genomföra en rad olika frågor i Sequelize, från enkla till mer avancerade.

Här är ett exempel på råfrågor som utför åtgärden att välja alla värden från en viss tabell, ta bort de valda värdena enligt villkoret och uppdatera tabellen med de angivna värdena.

SELECT * FROM table_name;
DELETE FROM table_name WHERE condition;
UPDATE table_name SET y = 42 WHERE x = 12;

I Sequelize kan råa frågor användas med främst två metoder: arrayersättning och objektersättning. När du skickar värden till SQL-frågan kan du använda antingen en array eller ett objekt för att göra den ersättningen.

Innan du skriver en rå fråga måste du först tillhandahålla studentdata i en exempel-databas. Efter föregående avsnitt, Skapa en exempel-databas, logga in på MySQL, skapa en databas som heter sample_student_db och logga ut från MySQL.

Nästa steg är att lägga till lite rådata för att börja arbeta med råa frågor. Skapa en ny fil som heter add_student_records.js och lägg till följande kodblock, som innehåller de tidigare diskuterade Sequelize-metoderna authenticate(), sync() och bulkCreate().

const {Sequelize, DataTypes} = require("sequelize");

const sequelize = new Sequelize(
   'sample_student_db',
   'DATABASE_USERNAME',
   'DATABASE_PASSWORD',
    {
      host: 'DATABASE_HOST',
      dialect: 'mysql'
    }
   );

sequelize.authenticate().then(() => {
    console.log('Connection has been established successfully.');
}).catch((error) => {
    console.error('Unable to connect to the database: ', error);
});

const Student = sequelize.define("students", {
    student_id: {
        type: DataTypes.UUID,
        defaultValue: DataTypes.UUIDV4,
        primaryKey: true,
    },
    name: {
        type: DataTypes.STRING,
        allowNull: false
    }
});

const student_data = [
    {name : "John Baker"},
    {name : "Max Butler"},
    {name : "Ryan Fisher"},
    {name : "Robert Gray"},
    {name : "Sam Lewis"}
]

sequelize.sync({ force: true }).then(() => {

    Student.bulkCreate(student_data, { validate: true }).then((result) => {
        console.log(result);
    }).catch((error) => {
        console.log(error);
    });

}).catch((error) => {
    console.error('Unable to create table : ', error);
});

Här initierar du databasanslutningen, skapar modellen och lägger in några elevposter i den nya databasen.

Spara och stäng filen.

Kör sedan detta skript med följande kommando:

node add_student_records.js

Utdata kommer att vara något liknande följande. Det kommer att vara ganska långt, men alla elevregister som du infogade kommer att returneras på följande sätt. Observera att eftersom student_id är ett automatiskt genererat UUID (Universally Unique Identifier)-värde, kommer det att vara olika beroende på användaren.

Executing (default): SELECT 1+1 AS result
Executing (default): DROP TABLE IF EXISTS `students`;
Connection has been established successfully.
Executing (default): DROP TABLE IF EXISTS `students`;
Executing (default): CREATE TABLE IF NOT EXISTS `students` (`student_id` CHAR(36) BINARY , `name` VARCHAR(255) NOT NULL, `createdAt` DATETIME NOT NULL, `updatedAt` DATETIME NOT NULL, PRIMARY KEY (`student_id`)) ENGINE=InnoDB;
Executing (default): SHOW INDEX FROM `students`
Executing (default): INSERT INTO `students` (`student_id`,`name`,`createdAt`,`updatedAt`) VALUES ('45d1f26c-ba76-431f-ac5f-f41282351710','John Baker','2022-06-03 07:27:49','2022-06-03 07:27:49'),('1cb4e34d-bfcf-4a97-9624-e400b9a1a5f2','Max Butler','2022-06-03 07:27:49','2022-06-03 07:27:49'),('954c576b-ba1c-4dbc-a5c6-8eaf22bbbb04','Ryan Fisher','2022-06-03 07:27:49','2022-06-03 07:27:49'),('e0f15cd3-0025-4032-bfe8-774e38e14c5f','Robert Gray','2022-06-03 07:27:49','2022-06-03 07:27:49'),('826a0ec9-edd0-443f-bb12-068235806659','Sam Lewis','2022-06-03 07:27:49','2022-06-03 07:27:49');
[
  students {
    dataValues: {
      student_id: '45d1f26c-ba76-431f-ac5f-f41282351710',
      name: 'John Baker',
      createdAt: 2022-06-03T07:27:49.453Z,
      updatedAt: 2022-06-03T07:27:49.453Z
    },
    _previousDataValues: {
      name: 'John Baker',
      student_id: '45d1f26c-ba76-431f-ac5f-f41282351710',
      createdAt: 2022-06-03T07:27:49.453Z,
      updatedAt: 2022-06-03T07:27:49.453Z
    },

…

I nästa avsnitt kommer du att använda råa frågor med ett av student_id-värdena i kodblocket ovan. Kopiera ner det så att du har det till nästa avsnitt, där du kommer att använda query()-metoden för array- och objektutbyten.

Array-erättning

I det här avsnittet kommer du att använda query()-metoden för en arraysubstitution. Med den här metoden kan Sequelize köra råa SQL-frågor eller redan förberedda SQL-frågor.

För att komma igång, kopiera innehållet i filen server.js från Steg 1, eftersom den inkluderar metoden Sequelize() för initiering och databasstart. Klistra in innehållet i en ny fil som heter array_raw_query.js. Uppdatera databasnamnet till sample_student_db:

const {Sequelize, DataTypes} = require("sequelize");

const sequelize = new Sequelize(
   'sample_student_db',
   'DATABASE_USERNAME',
   'DATABASE_PASSWORD',
    {
      host: 'DATABASE_HOST',
      dialect: 'mysql'
    }
   );

sequelize.authenticate().then(() => {
    console.log('Connection has been established successfully.');
}).catch((error) => {
    console.error('Unable to connect to the database: ', error);
});

Längst ner i filen, lägg till följande kodblock för en arrayersättning, och se till att ersätta REPLACE_STUDENT_ID med student_id-värdet som du kopierade i föregående avsnitt.

...
sequelize.query(
    'SELECT * FROM students WHERE student_id = ?',
    {
      replacements: ['REPLACE_STUDENT_ID'],
      type: sequelize.QueryTypes.SELECT
    }
).then(result => {
    console.log(result);
}).catch((error) => {
    console.error('Failed to insert data : ', error);
});

För arrayersättning skickar du query()-metoden med SQL-frågan och konfigurationsobjektet. Det innehåller replacements-värdet och typen. För ersättningar skickar du data som en array och fångar dessa värden med frågeteckensymbolen (?).

Nästa, eftersom du behöver hämta data om en specifik student, skickas student_id som den andra parametern. Efter det skickar du nyckel-värdeparet type: sequelize.QueryTypes.SELECT, som du kan använda för att hämta data från databasen.

Det finns även några andra typer, såsom QueryTypes.UPDATE och QueryTypes.DELETE. Beroende på behovet kan du välja den typ som passar ditt syfte.

Följande visar hela kodblocket. Här ansluter du till databasen och hämtar de valda studentuppgifterna med en direkt fråga.

const {Sequelize, DataTypes} = require("sequelize");

const sequelize = new Sequelize(
   'sample_student_db',
   'DATABASE_USERNAME',
   'DATABASE_PASSWORD',
    {
      host: 'DATABASE_HOST',
      dialect: 'mysql'
    }
   );

sequelize.authenticate().then(() => {
    console.log('Connection has been established successfully.');
}).catch((error) => {
    console.error('Unable to connect to the database: ', error);
});

sequelize.query(
    'SELECT * FROM students WHERE student_id = ?',
    {
      replacements: ['REPLACE_STUDENT_ID'],
      type: sequelize.QueryTypes.SELECT
    }
).then(result => {
    console.log(result);
}).catch((error) => {
    console.error('Failed to insert data : ', error);
});

Spara och stäng din fil.

Nästa steg är att köra detta skript med följande kommando:

node array_raw_query.js

Du kommer att se output som liknar följande:

Connection has been established successfully.
[ { student_id: 'STUDENT_ID_YOU_RETRIEVED',
    name: 'Robert Gray',
    createdAt: 2022-05-06T13:14:50.000Z,
    updatedAt: 2022-05-06T13:14:50.000Z } ]

På grund av det valda student_id kan dina utdatavärden skilja sig.

Objektersättning

På ytan liknar objektutbyte arrayutbyte, men mönstret för att skicka data till den råa frågan är olika. I alternativet för utbyte skickar du data som ett objekt, och i frågealternativet använder du värden som :key.

För att komma igång, skapa en ny fil som heter object_raw_query.js och klistra in de kompletta kodblocken från server.js-filen, och uppdatera databasen till sample_student_db.

const {Sequelize, DataTypes} = require("sequelize");

const sequelize = new Sequelize(
   'sample_student_db',
   'DATABASE_USERNAME',
   'DATABASE_PASSWORD',
    {
      host: 'DATABASE_HOST',
      dialect: 'mysql'
    }
   );

sequelize.authenticate().then(() => {
    console.log('Connection has been established successfully.');
}).catch((error) => {
    console.error('Unable to connect to the database: ', error);
});

Lägg sedan till följande kodblock i slutet av den nya filen object_raw_query.js:

...
sequelize.query(
  'SELECT * FROM students WHERE student_id = :id',
  {
    replacements: { id: 'REPLACE_STUDENT_ID' },
    type: sequelize.QueryTypes.SELECT
  }
 ).then(result => {
    console.log(result);
}).catch((error) => {
    console.error('Failed to insert data : ', error);
});

Här får du vald studentdata med hjälp av objektbyte-metoden. Du skapar ett replacement-objekt och anger id som den studentinformation du vill hämta: { id: '<mark>REPLACE_STUDENT_ID</mark>' }.

I query() anger du: 'SELECT * FROM students WHERE student_id=:id'. Genom att använda query()-metoden skickar du ersättningsvärdet som ett objekt, vilket är anledningen till att denna metod kallas för objektutbyte.

Här är den kompletta koden:

const {Sequelize, DataTypes} = require("sequelize");

const sequelize = new Sequelize(
   'sample_student_db',
   'DATABASE_USERNAME',
   'DATABASE_PASSWORD',
    {
      host: 'DATABASE_HOST',
      dialect: 'mysql'
    }
   );

sequelize.authenticate().then(() => {
    console.log('Connection has been established successfully.');
}).catch((error) => {
    console.error('Unable to connect to the database: ', error);
});

sequelize.query(
  'SELECT * FROM students WHERE student_id = :id',
  {
    replacements: { id: 'REPLACE_STUDENT_ID' },
    type: sequelize.QueryTypes.SELECT
  }
 ).then(result => {
    console.log(result);
}).catch((error) => {
    console.error('Failed to insert data : ', error);
});

Spara och stäng filen.

Kör sedan detta skript med följande kommando:

node object_raw_query.js

Utmatningen kommer att se ungefär ut så här:

Connection has been established successfully.
[ { student_id: 'STUDENT_ID_YOU_RETRIEVED',
    name: 'Robert Gray',
    createdAt: 2022-05-06T13:14:50.000Z,
    updatedAt: 2022-05-06T13:14:50.000Z } ]

På grund av det valda student_id kan dina utdatavärden skilja sig.

I detta steg arbetade du med Sequelize råa frågor med två olika metoder: arrayersättning och objektersättning.

Konfigurera miljövariabler för säkra databaskopplingar

Hittills har du lagrat databaskredentialer direkt i din kod. Även om detta tillvägagångssätt fungerar för lokal experimentering är det inte säkert. Att hårdkoda credentialer utsätter känslig information som databasklösenord och värdnamn, och ökar risken för intrång när koden delas eller driftsätts. I det här avsnittet kommer du att lära dig hur du kan lagra dessa credentialer säkert med hjälp av miljövariabler.

Varför använda miljövariabler?

Miljövariabler fungerar som externa konfigurationsparametrar som din applikation kan läsa vid körning. Istället för att inbädda uppgifter direkt i din kod lagras de i ditt system eller i en separat konfigurationsfil som aldrig läggs till i versionskontrollen. Denna metod ger flera fördelar:

  • Säkerhet: Dina inloggningsuppgifter förblir dolda för offentliga arkiv och versionskontrollsystem.
  • Flexibilitet: Varje miljö (utveckling, test, produktion) kan använda en annan databas-konfiguration utan att ändra källkoden.
  • Underhållbarhet: Centraliserad konfiguration möjliggör enkla uppdateringar; om databaslösenordet ändras behöver du bara ändra en fil eller variabel.
  • Efterlevnad: Denna praxis är i linje med Twelve-Factor App-metodiken, som främjar miljöspecifik konfigurationshantering för skalbara applikationer.

Ställa in miljövariabler

Du kommer att använda paketet dotenv för att hantera dina miljövariabler i Node.js. Detta bibliotek läser variabler från en .env-fil och injicerar dem i Node.js process.env-objektet, vilket gör dem tillgängliga i hela din applikation.

Installera dotenv-paketet genom att köra följande kommando:

npm install dotenv

Efter installationen, skapa en ny fil med namnet .env i projektets rotkatalog. Denna fil kommer att innehålla all känslig data som krävs för databasanslutning.

Här är ett exempel på en .env-filkonfiguration för din Sequelize-inställning:

DB_NAME=hello_world_db
DB_USER=your_username
DB_PASSWORD=your_password
DB_HOST=localhost
DB_DIALECT=mysql

Varje variabel motsvarar en specifik parameter som Sequelize använder för att etablera anslutningen.

Säkra .env-filen

Det är avgörande att din .env-fil aldrig hamnar i versionskontroll. För att förhindra detta, lägg till den i din .gitignore-fil så att Git hoppar över den när förändringar begås:

.env

I produktionsmiljöer konfigureras miljövariabler vanligtvis direkt i din värdplattforms inställningar eller sekretesshanterare istället för en lokal .env-fil.

Uppdatera din Sequelize-konfiguration

Nu när du har definierat miljövariablerna, uppdatera din Sequelize-initialisering för att använda dem. Börja med att importera och konfigurera dotenv högst upp i din huvudserverfil (t.ex. server.js):

require('dotenv').config();
const Sequelize = require('sequelize');

const sequelize = new Sequelize(
  process.env.DB_NAME,
  process.env.DB_USER,
  process.env.DB_PASSWORD,
  {
    host: process.env.DB_HOST,
    dialect: process.env.DB_DIALECT
  }
);

sequelize.authenticate().then(() => {
   console.log('Connection has been established successfully.');
}).catch((error) => {
   console.error('Unable to connect to the database:', error);
});
  1. Raden require('dotenv').config() laddar alla variabler som definieras i .env-filen till process.env.
  2. Sequelize läser miljövariablerna när en ny instans initialiseras.
  3. Detta säkerställer att ingen känslig information som användarnamn eller lösenord visas i din kod.

Detta tillvägagångssätt förbättrar säkerheten och gör det möjligt för olika miljöer att använda unika konfigurationer helt enkelt genom att ändra värdena på miljövariabler.

Verifierar konfigurationen

När du har uppdaterat din konfiguration kan du verifiera anslutningen genom att köra din Node.js-applikation:

node server.js

Om din .env-fil är korrekt inställd och MySQL-servern körs, kommer du att se följande output:

Connection has been established successfully.

Om ett fel visas, kontrollera noggrant att:

  • Uppgifterna i din .env-fil matchar de i din MySQL-instans.
  • MySQL-servern körs och är tillgänglig från din värd.
  • Filen .env finns i rotmappen för ditt projekt och är korrekt formaterad.

Bästa praxis för säker konfiguration

Att använda miljövariabler är ett starkt första steg mot säker konfigurationshantering. För att säkerställa fortsatt säkerhet och pålitlighet, överväg följande ytterligare bästa praxis:

  • Använd separata konfigurationer för varje miljö: Behåll olika .env-filer för development, staging och production. Du kan namnge dem .env.development, .env.staging och .env.production.
  • Använd hemlighetshanterare: För produktionsmiljöer, använd hemlighetshanterare istället för att lagra hemligheter i filer.
  • Validera miljövariabler: Använd ett konfigurationsverktyg eller ett startskript som kontrollerar om nödvändiga variabler är definierade innan appen körs. Detta hjälper till att förhindra körfels.
  • Rotera autentiseringsuppgifter regelbundet: Uppdatera databaskredentialer med jämna mellanrum för att minska konsekvenserna av eventuella läckor.
  • Begränsa databasåtkomst: Konfigurera databasanvändarroller så att de har de lägsta privilegierna som krävs för applikationen.

Genom att implementera miljövariabler och följa dessa metoder säkerställer du att din Sequelize-applikation bibehåller både flexibilitet och säkerhet i både utvecklings- och produktionsmiljöer.

Bästa praxis för migrering och synkronisering

När man utvecklar ett databasschema har man två huvudsakliga tillvägagångssätt med Sequelize: att skriva och köra explicita migrationer, eller att använda sequelize.sync() för att låta Sequelize generera schemaförändringar automatiskt. Båda tillvägagångssätten är giltiga, men de tjänar olika syften och har olika kompromisser. Låt oss förstå när man ska använda respektive metod, hur man skriver säkra migrationer och hur man kör dem på ett pålitligt sätt i utveckling och produktion.

Migrationer vs sequelize.sync() — när ska man använda vilken

  • Migreringar (rekommenderas för produktion): Migreringar är explicita, versionshanterade ändringar i ditt schema. De lagras i källkontroll, granskas genom kodgranskning och utförs som en del av din distributionsprocess. Använd migreringar i produktion för alla schematiska ändringar som påverkar dataintegritet eller tillgänglighet.

  • sequelize.sync() (endast för utveckling och prototyper): sync() är praktiskt för lokal utveckling, tester och snabba prototyper eftersom det kan skapa eller justera tabeller automatiskt. Använd dock inte sync({ force: true }) eller sync({ alter: true }) i produktion: dessa alternativ kan radera data eller göra osäkra ändringar utan en kontrollerad återställningsväg.

Verktyg: sequelize-cli och migrationsverktyg

Det officiella CLI:t, sequelize-cli, är det enklaste sättet att hantera migrationer med Sequelize. För team som behöver mer kontroll eller anpassade arbetsflöden är umzug ett populärt alternativ.

För att installera och initiera CLI i ditt projekt, kör:

npm install --save-dev sequelize-cli

npx sequelize-cli init

Detta skapar följande mappar:

config/        # Stores database configuration files
models/        # Stores your Sequelize model definitions
migrations/    # Stores migration files
seeders/       # Stores seeder files for inserting initial data

Du bör lägga till dessa mappar i versionskontrollen (förutom filer som innehåller autentiseringsuppgifter). Detta säkerställer att alla miljöer kör samma databassändringar konsekvent.

Skapa och köra migrationer

För att skapa en ny migrationsfil, använd följande kommando:

npx sequelize-cli migration:generate --name add-isbn-to-books

Detta skapar en tidsstämplad fil i mappen migrations/. Öppna filen och definiera vad som ska hända när du tillämpar migrationen (up) och hur du ångrar den (down):

module.exports = {
  async up(queryInterface, Sequelize) {
    await queryInterface.addColumn('books', 'isbn', {
      type: Sequelize.STRING
    });
  },
  async down(queryInterface) {
    await queryInterface.removeColumn('books', 'isbn');
  }
};
  • Funktionen up applicerar migreringen (lägger till kolumnen).
  • Funktionen down ångrar ändringen (tar bort kolumnen).

Kör migreringen med:

npx sequelize-cli db:migrate

För att återställa den senaste migreringen, använd:

npx sequelize-cli db:migrate:undo

Du kan också ångra alla migrationer i utveckling genom att köra:

npx sequelize-cli db:migrate:undo:all

Att skriva säkra, idempotenta migreringar

Följ dessa regler när du skriver migrationer:

  • Omge operationer med transaktioner när databasen stöder det. Detta säkerställer att migreringen antingen lyckas helt eller helt återställs vid fel.

    module.exports = {
      async up(queryInterface, Sequelize) {
        return queryInterface.sequelize.transaction(async (t) => {
          await queryInterface.addColumn('books', 'isbn', {
            type: Sequelize.STRING
          }, { transaction: t });
        });
      },
      async down(queryInterface) {
        return queryInterface.sequelize.transaction(async (t) => {
          await queryInterface.removeColumn('books', 'isbn', { transaction: t });
        });
      }
    };
  • Håll migreringar små och fokuserade. Varje migrering bör utföra en enda logisk förändring (lägga till en kolumn, skapa ett index, byta namn på en kolumn). Mindre migreringar är lättare att granska, testa och återställa.

  • Var defensiv och idempotent. När det är lämpligt, kontrollera om något finns för att undvika fel i miljöer med drift. Använd queryInterface.describeTable() eller råa frågor för att skydda operationer.

  • Undvik destruktiva operationer i ett steg. Till exempel, för att säkert ta bort en kolumn, lägg till den nya kolumnen, fyll den med data, ändra läsningar till den nya kolumnen i applikationskoden, och ta först bort den gamla kolumnen i en senare migrering.

Långvariga och nertidfria migreringar

Stora tabeller och indexoperationer kan orsaka lås. Använd dessa strategier för att minimera påverkan:

  1. Lägg till kolumner som kan vara null först. Att lägga till en kolumn som kan vara null går vanligtvis snabbt. Undvik att lägga till kolumner med icke-triviala standardvärden som utlöser fullständiga tabellomskrivningar.
  2. Fyll på i små omgångar. Implementera ett bakgrundsjobb för att fylla nya kolumner i delar istället för att köra en enda massiv UPDATE.
  3. Skapa index utan exklusiva lås när det är möjligt. Använd databasspecifika funktioner (till exempel Postgres CONCURRENTLY och nyare MySQL online DDL) via rå SQL i migrationer.
  4. Feature-flag-utrullningar. Distribuera applikationskod som läser den nya kolumnen bakom en feature-flag. När backfill är klart och testerna godkänns, slå om flaggan och ta senare bort det gamla fältet.

Återställningar och akuta åtgärder

  • Ge en down-migrering. Varje up bör ha en motsvarande down som dokumenterar hur man återställer ändringen. Även om du sällan kör down i produktion, fungerar det som en tydlig återställningsplan.
  • Planera för akuta återställningar. Om en migration orsakar problem, var redo att först återställa applikationskoden och återställa databasen från säkerhetskopior om det behövs. Testa återställningsprocedurer regelbundet.

Initiering av data och schemauppdateringar

  • Håll seeders minimala och stabila. Använd seeders för viktiga uppslags- eller konfigurationsrader. Undvik att fylla på stora mängder affärsdata genom migrationer.
  • Separera fröer från strukturella migrationer. Om du måste fylla data som beror på en ändring av schemat, föredra en efterföljande seeder så att ansvarsområdena förblir tydliga.

CI, kodgranskning och automatisering av distribution

  • Kör migrationer i CI och staging först. Lägg till ett CI-steg som kör migrationer mot en temporär databas för att fånga upp fel tidigt.

  • Behandla migrationer som kod. Lint och granska migrationsfiler i pull requests. Inkludera automatiska kontroller när det är möjligt.

  • Automatisera körning av migrationer under distributioner. Se till att migrationer körs innan applikationsprocesser börjar ta emot trafik. Exempel på package.json-skript:

    "scripts": {
      "migrate": "npx sequelize-cli db:migrate",
      "start": "node server.js",
      "deploy": "npm run migrate && npm run start"
    }

I containeriserade distributioner, kör migrationer som en init-container eller i en distribueringshook så att webbprocesserna startar först efter att migrationerna är klara.

Testar migreringar

  • Testa båda riktningarna. Kör db:migrate och sedan db:migrate:undo:all lokalt och i CI för att verifiera att både up och down fungerar.
  • Använd engångsdatabaser för tester. Föredra tillfälliga databaser eller containrar för deterministiska testrundor.

Att följa dessa bästa praxis säkerställer att dina Sequelize-migreringar förblir pålitliga, spårbara och säkra för långsiktiga projekt.

Felsökning och prestandatips

Även med en stabil uppsättning kan Sequelize-applikationer ibland stöta på oväntade problem såsom databasanslutningsfel, misslyckade migreringar, långsamma frågor, låsningar eller samtidighetskonflikter. Denna sektion ger steg-för-steg-anvisningar för att identifiera och åtgärda dessa problem, tillsammans med bästa praxis för prestanda som hjälper dig att hålla din applikation stabil och effektiv.

Felsökning av vanliga problem

1. Anslutningsfel

Problem: Sequelize kan inte ansluta till MySQL-databasen och ger fel som SequelizeConnectionError: connect ECONNREFUSED, Access denied for user eller SequelizeHostNotFoundError.

Hur man åtgärdar:

Börja med att bekräfta att dina anslutningsuppgifter är korrekta. Dubbelkolla värdena i din .env-fil, inklusive databasenamn, användarnamn, lösenord, värd och port. Även ett litet stavfel eller ett efterföljande blanksteg kan göra att Sequelize misslyckas med att ansluta.

Nästa steg är att se till att din MySQL-server är igång och lyssnar på standardporten (3306). Du kan testa anslutningen genom att logga in manuellt:

mysql -u your_username -p -h your_host -P 3306

Om detta kommando misslyckas ligger problemet troligen hos din MySQL-tjänst eller dina inloggningsuppgifter.

Om du använder dotenv-paketet, se till att require('dotenv').config() finns innan Sequelize initialiseras. Detta steg säkerställer att alla miljövariabler är tillgängliga vid körning.

Slutligen, för fjärranslutningar, kontrollera dina brandväggsinställningar eller regler för säkerhetsgrupper. MySQL-servern måste acceptera inkommande anslutningar från din applikations värd.

2. Migreringsfel

Problem: Du kör npx sequelize-cli db:migrate eller sequelize.sync() och stöter på fel som saknade tabeller, dubbla kolumner eller schemaavvikelser.

Så här åtgärdar du:

Problem med migrationer uppstår vanligtvis när filer körs i fel ordning eller innehåller fel i SQL-operationer. Sequelize behandlar migrationer baserat på tidsstämplar i filnamnen, så kontrollera att filerna är korrekt namngivna.

Om en migrering misslyckas, undersök felmeddelandet noggrant. Återgå sedan säkert till den senaste migreringen med:

npx sequelize-cli db:migrate:undo

Efter att ha åtgärdat migrationsfilen, kör den igen.

Linda alltid in din migrationslogik inom en transaktion för att säkerställa atomäritet: antingen lyckas alla ändringar eller inga alls. Innan du kör migrationer i produktion, testa dem noggrant på en staging- eller lokal databas för att bekräfta att de fungerar korrekt.

3. Problem med modell-synkronisering

Problem: Dina Sequelize-modeller och databasschema stämmer inte överens, vilket leder till saknade kolumner, felaktiga datatyper eller föråldrade tabeller.

Hur man åtgärdar:

Undvik att använda sequelize.sync({ force: true }) i produktion, eftersom det kommer att ta bort och återskapa tabeller, vilket orsakar irreversibel förlust av data. Använd på samma sätt sequelize.sync({ alter: true }) med försiktighet; det kan ändra scheman på ett oförutsägbart sätt.

Föredra istället explicita migrationer som tydligt definierar varje schemasändring. För att jämföra dina modeller med den faktiska databasen, använd:

await queryInterface.describeTable('tableName');

Detta hjälper till att identifiera avvikelser innan de påverkar produktionen.

4. Fråge- och tidsgränsfel

Problem: Du ser tidsgränsrelaterade fel som Connection timeout eller Too many connections.

Hur man åtgärdar:

Timeout-problem uppstår ofta på grund av uttömda anslutningspooler eller oavslutade anslutningar. Se till att alla Sequelize-frågor väntas ordentligt så att anslutningarna återgår till poolen efter användning.

Du kan också finjustera Sequelizes poolkonfiguration för att bättre passa din applikations arbetsbelastning:

const sequelize = new Sequelize(DB_NAME, DB_USER, DB_PASSWORD, {
  host: DB_HOST,
  dialect: 'mysql',
  pool: {
    max: 10,
    min: 0,
    acquire: 30000,
    idle: 10000
  }
});

Om din applikation hanterar många samtidiga användare, överväg att öka MySQL-parametern max_connections i din databaskonfiguration. Övervaka aktiva anslutningar med SHOW PROCESSLIST; i MySQL för att upptäcka läckor eller oanvända sessioner.

5. Långsam frågeprestanda

Problem: Vissa frågor tar betydligt längre tid än väntat, vilket orsakar långsamma API-svar eller hög fördröjning.

Hur man diagnostiserar:

Börja med att identifiera vilka frågor som är långsamma. Du kan logga alla frågor som Sequelize kör genom att tillfälligt aktivera loggning:

const sequelize = new Sequelize(..., { logging: console.log });

Använd sedan MySQLs EXPLAIN-sats för att förstå hur databasen utför frågan:

EXPLAIN SELECT * FROM users WHERE email = 'user@example.com';

Om resultatet visar en "fullständig tabellgenomsökning" saknar frågan ett index.

Du kan också aktivera MySQL logg för långsamma frågor för att automatiskt fånga långsamma operationer:

SET GLOBAL slow_query_log = 'ON';
SET GLOBAL long_query_time = 1;

Hur man åtgärdar:

Lägg till index på kolumner som ofta frågas efter (särskilt de som används i WHERE, JOIN och ORDER BY-satser). Undvik SELECT *, hämta istället uttryckligen endast de fält du behöver med alternativet attributes.

Om Sequelize genererar ineffektiva frågor med onödiga joinar, skriv om frågan med ren SQL. För stora rapporter eller analysfrågor, dela upp dem i mindre steg eller använd cacheverktyg som Redis för att lagra upprepade resultat.

6. Dödlägen och samtidighetsfel

Problem: Du får fel som Deadlock found when trying to get lock; try restarting transaction, särskilt vid hög belastning.

Hur man diagnostiserar:

Kontrollera InnoDB:s status i MySQL för att identifiera vilka frågor eller tabeller som var inblandade:

SHOW ENGINE INNODB STATUS\G

Denna utskrift innehåller detaljerad information om nyligen inträffade deadlocks och låsväntningar. Du kan också aktivera allmänna eller transaktionsloggar för att granska sekvensen av frågor som ledde till problemet.

Hur man åtgärdar:

Deadlocks uppstår när två eller fler transaktioner väntar på varandras lås. För att minimera dem:

  1. Håll transaktioner så korta som möjligt. Anropa inte externa tjänster eller utför tung beräkning medan en låsning hålls.

  2. Använd alltid tabeller och rader i samma ordning över transaktioner för att undvika cirkulära väntetider.

  3. För återkommande låsproblem, implementera en enkel omförsöksmekanism med exponentiell backoff:

    async function runWithRetry(fn, retries = 3) {
      for (let i = 0; i < retries; i++) {
        try {
          return await fn();
        } catch (err) {
          if (isDeadlockError(err) && i < retries - 1) {
            await sleep(100 * (i + 1));
            continue;
          }
          throw err;
        }
      }
    }
  4. Använd lås på radnivå (SELECT ... FOR UPDATE) endast när det är nödvändigt, och släpp dem snabbt.

  5. Dela upp stora transaktioner i mindre partier för att minska konkurrens.

  6. Justera transaktionsisolationsnivåer om det är lämpligt, men endast efter att ha bekräftat att det inte påverkar datakonsistensen.

Tips för prestandaoptimering

Prestandaproblem beror ofta på ineffektiva frågor, saknade index eller dålig hantering av anslutningar. Här är några praktiska tips för att förbättra Sequelize-prestanda utan att offra tydlighet eller underhållbarhet.

1. Optimera frågor

Skriv frågor som bara begär det som behövs. Att hämta onödig data ökar minnesanvändningen och sänker svarshastigheten. Använd attributes för att begränsa fälten:

const users = await User.findAll({ attributes: ['id', 'name'] });

Filtrera alltid resultat med hjälp av indexerade kolumner och undvik vid möjliga breda sökningar som LIKE '%term%'.

2. Använd index effektivt

Index gör uppslagningar snabbare men kan sakta ner skrivningar. Lägg till index endast där de ger mätbara fördelar. Analysera frågeprestanda med MySQL:s EXPLAIN för att verifiera förbättringar före och efter att ett index lagts till:

await queryInterface.addIndex('users', ['email']);

3. Justera anslutningspoolen

Anslutningspoolen bestämmer hur många databasanslutningar Sequelize upprätthåller.

  • För små appar räcker det vanligtvis med 5–10 anslutningar.
  • För system med hög belastning, öka poolstorleken och justera timeoutvärden för att förhindra anslutningsflaskhalsar. Övervaka användningen regelbundet med MySQL:s SHOW PROCESSLIST;.

4. Aktivera loggning och övervakning

Aktivera Sequelize-loggning temporärt för att granska SQL-frågor. Använd MySQL:s logg för långsamma frågor för att identifiera frågor som överskrider din prestandatröskel. För realtidsövervakning, integrera övervakningsverktyg som PM2, New Relic eller Datadog för att mäta latens och resursanvändning.

5. Cachar vanliga frågor

Cachelagra resultat för data som inte ändras ofta. Verktyg som Redis eller Memcached minskar antalet databasförfrågningar och förbättrar svarstider, särskilt för arbetsbelastningar med mycket läsning.

6. Sätt sidnummer på resultaten

Stora resultatmängder förbrukar mycket minne. Dela alltid upp förfrågningar i APIs i sidor:

const users = await User.findAll({ limit: 50, offset: 100 });

Pagination håller svaren lätta och konsekventa under belastning.

7. Använd råa frågor för komplexa operationer

Om Sequelizes abstraktion resulterar i ineffektiv SQL för ett specifikt användningsfall, kör en rå SQL-fråga direkt:

const [results] = await sequelize.query('SELECT name FROM users WHERE active = 1');

Använd råa frågor sparsamt och dokumentera dem tydligt för framtida underhåll.

Vanliga frågor

1. Vad är Sequelize i Node.js?

Sequelize är en objekt-relationell mapper (ORM) för Node.js som erbjuder ett hög-nivå, JavaScript-baserat API för att arbeta med SQL-databaser som MySQL, PostgreSQL, SQLite och MariaDB. Istället för att skriva rå SQL för varje operation definierar du modeller som mappas till databastabeller och använder modellmetoder för att infoga, hämta, uppdatera och ta bort poster. Sequelize stöder även associationer (relationer mellan modeller), transaktioner, migrationer och råa frågor när du behöver direkt SQL.

2. Hur ansluter jag Sequelize till MySQL?

För att ansluta Sequelize till MySQL skapar du en Sequelize-instans med dina databaskredentialer och alternativ. I en Node.js-fil, importera Sequelize, ladda eventuellt miljövariabler, och instansiera det sedan med databasens namn, användarnamn, lösenord samt host-/dialektalternativ. Till exempel:

require('dotenv').config();
const { Sequelize } = require('sequelize');

const sequelize = new Sequelize(
  process.env.DB_NAME,
  process.env.DB_USER,
  process.env.DB_PASSWORD,
  {
    host: process.env.DB_HOST || 'localhost',
    dialect: 'mysql'
  }
);

await sequelize.authenticate();
console.log('Connected to the database successfully!');

Håll alltid autentiseringsuppgifter utanför källkontroll (till exempel i en .env-fil eller en sekretesshanterare).

3. Hur skapar och synkroniserar jag modeller i Sequelize?

I Sequelize representerar modeller tabeller. Du definierar dem med sequelize.define() eller genom att utöka Model-klassen. Efter det kan du synkronisera dem med din databas så att Sequelize skapar tabellerna automatiskt (bra för utveckling). Här är ett litet exempel:

const { DataTypes } = require('sequelize');

const Book = sequelize.define('Book', {
  title: { type: DataTypes.STRING, allowNull: false },
  author: { type: DataTypes.STRING, allowNull: false },
  releaseDate: DataTypes.DATEONLY
});

// Create the table if it does not exist
await sequelize.sync();

För produktionsmiljöer är det bättre att använda migrationer så att du har versionskontroll över schemavändringar.

4. Hur använder jag Sequelize med Express?

I en Express-app, initiera Sequelize i en separat fil (som db.js), exportera den anslutna instansen och modellerna, och importera dem där du behöver dem i dina route-handlers eller controllers. Använd async/await i route-handlers för att anropa Sequelize-modellmetoder, och hantera fel med try/catch eller en fel-middleware. Så här ser det ut i praktiken:

// db.js
const sequelize = new Sequelize(...);
const User = sequelize.define(...);
module.exports = { sequelize, User };

// app.js
const { User } = require('./db');
app.get('/users', async (req, res) => {
  const users = await User.findAll();
  res.json(users);
});

Se till att du kör migrationer eller anropar sequelize.sync() innan du startar din Express-server så att dina databastabeller finns när förfrågningar kommer in.

5. Vad är skillnaden mellan Sequelize och råa SQL-frågor?

Sequelize låter dig skriva databaskod i JavaScript, medan rå SQL betyder att skriva SQL-satser direkt. Sequelize gör din kod renare och lättare att underhålla eftersom du kan definiera modeller och relationer en gång och använda dem i hela din app. Rå SQL ger dig mer kontroll och kan ibland vara snabbare för mycket komplexa frågor.

Kort sagt, använd Sequelize för de flesta vardagliga uppgifter, och använd rå SQL när du behöver finjustera prestanda eller köra något som Sequelize inte lätt kan uttrycka.

6. Hur kan jag definiera associationer i Sequelize?

Sequelize gör det enkelt att beskriva relationer mellan tabeller. Du kan skapa en-till-en, en-till-många eller många-till-många relationer med enkla metoder som hasOne, hasMany och belongsToMany. Till exempel:

// One to one
User.hasOne(Profile);
Profile.belongsTo(User);

// One to many
Author.hasMany(Book);
Book.belongsTo(Author);

// Many to many
Student.belongsToMany(Course, { through: 'StudentCourse' });
Course.belongsToMany(Student, { through: 'StudentCourse' });

När det väl är definierat kan du använda include i dina frågor för att automatiskt hämta relaterad data.

7. Hur hanterar jag migrationer och ändringar i databasschemat?

Under utveckling kan du använda sequelize.sync() för att snabbt skapa tabeller. Men i produktion bör du alltid använda migrationer. Migrationer är versionshanterade filer som beskriver hur din databasstruktur förändras över tid, liknande hur Git-commits spårar ändringar i koden.

Du kan skapa en migration med Sequelize CLI:

npx sequelize-cli migration:generate --name add-users-table

Varje migration har up och down-metoder, en för att genomföra förändringen och en för att ångra den. Kör dina migrationer med:

npx sequelize-cli db:migrate

På det här sättet behåller alla i ditt team (och varje distribution) samma databasstruktur.

Använd sequelize.sync() för snabba experiment, men håll dig till migrationer när din app är live eftersom de är säkrare, kan återställas och är lättare att följa.

Slutsats

I denna handledning ställer du in Sequelize med Node.js och MySQL för att hantera data genom modeller, associationer och migrationer. Du säkrade också dina databasuppgifter med hjälp av miljövariabler och utforskade bästa praxis för felsökning och prestandaoptimering.

Med dessa steg har du nu en solid grund för att bygga och underhålla säkra, effektiva Node.js-applikationer som använder Sequelize och MySQL för databehandling.

För att lära dig mer om Sequelize, kolla in produktdokumentationen. För fler sådana Node.js-handledningar, kolla in följande artiklar:

  • Hur man startar en GraphQL-server i Node.js med Apollo Server och Sequelize
  • Hur man implementerar caching i Node.js med Redis
  • Hur man skapar en webbserver i Node.js med HTTP-modulen

Tack för att du lär dig tillsammans med Linux-Console.net-communityn.