MySQL: Iniziare

Come iniziare con MySQL

👋 Benvenuti nella documentazione di Stackhero!

Stackhero offre una soluzione MySQL cloud pronta all'uso che fornisce una serie di vantaggi, tra cui:

  • Connessioni e trasferimenti illimitati.
  • Interfaccia web phpMyAdmin inclusa.
  • Aggiornamenti facili con un solo clic.
  • Prestazioni ottimali e sicurezza robusta grazie a una VM privata e dedicata.

Risparmia tempo e semplifica la tua vita: ci vogliono solo 5 minuti per provare la soluzione di MySQL cloud hosting di Stackhero!

Il modo più semplice per connettersi al vostro servizio MySQL è utilizzare il formato URL MySQL se il vostro driver lo supporta:

mysql://root:<ROOT_PASSWORD>@<XXXXXX>.stackhero-network.com:<PORT>/root?useSSL=true&requireSSL=true

Per gli utenti Ruby, il formato URL MySQL è leggermente diverso:

mysql2://root:<ROOT_PASSWORD>@<XXXXXX>.stackhero-network.com:<PORT>/root?reconnect=true&useSSL=true&requireSSL=true
<?php

$hostname = '<XXXXXX>.stackhero-network.com';
$port = '<PORT>';
$user = 'root';
$password = '<ROOT_PASSWORD>';
$database = 'root'; // Non raccomandiamo l'uso del database "root". Questo esempio è fornito solo a scopo dimostrativo. La migliore pratica è creare un database e un utente dedicati in phpMyAdmin e utilizzarli qui.

$mysqli = mysqli_init();
$mysqliConnected = $mysqli->real_connect($hostname, $user, $password, $database, $port, NULL, MYSQLI_CLIENT_SSL);
if (!$mysqliConnected) {
  die("Errore di connessione: " . $mysqli->connect_error);
}

echo 'Connessione riuscita... ' . $mysqli->host_info . "\n";

$mysqli->close();

?>
<?php

$hostname = '<XXXXXX>.stackhero-network.com';
$port = '<PORT>';
$user = 'root';
$password = '<ROOT_PASSWORD>';
$database = 'root'; // Non raccomandiamo l'uso del database "root". Questo esempio è solo a scopo dimostrativo. È meglio creare un database e un utente dedicati in phpMyAdmin e utilizzarli qui.

$mysqli = mysqli_init();
$mysqliConnected = mysqli_real_connect($mysqli, $hostname, $user, $password, $database, $port, NULL, MYSQLI_CLIENT_SSL);
if (!$mysqliConnected) {
  die("Errore di connessione: " . mysqli_connect_error($mysqli));
}

echo 'Successo: ' . mysqli_get_host_info($mysqli) . "\n";

mysqli_close($mysqli);

?>
<?php

$hostname = '<XXXXXX>.stackhero-network.com';
$port = '<PORT>';
$user = 'root';
$password = '<ROOT_PASSWORD>';
$database = 'root'; // Non raccomandiamo l'uso del database "root". Questo è solo a scopo dimostrativo. La migliore pratica è creare un database e un utente dedicati in phpMyAdmin e utilizzarli qui.

$dsn = "mysql:host=$hostname;port=$port;dbname=$database";

$options = array(
  // Se si verifica un errore come "Uncaught PDOException: PDO::__construct(): SSL operation failed with code 1. OpenSSL Error messages: error:0A000086:SSL routines::certificate verify failed",
  // assicurarsi che la directory /etc/ssl/certs/ contenga certificati CA.
  // Vedere sotto per ulteriori informazioni.
  PDO::MYSQL_ATTR_SSL_CAPATH => '/etc/ssl/certs/',
  // PDO::MYSQL_ATTR_SSL_CA => 'isrgrootx1.pem',
  PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT => true,
);

$pdo = new PDO($dsn, $user, $password, $options);

$stm = $pdo->query("SELECT VERSION()");
$version = $stm->fetch();

echo "Siete connessi a un database che esegue la versione " . $version[0] . "\n";

?>

Se si verifica l'errore:

Uncaught PDOException: PDO::__construct(): SSL operation failed with code 1. OpenSSL Error messages: error:0A000086:SSL routines::certificate verify failed

questo è probabilmente dovuto al fatto che la directory /etc/ssl/certs/ non contiene certificati CA.

Se avete accesso al sistema che esegue il vostro codice PHP, potete installare questi certificati come segue:

  1. Su Ubuntu/Debian, eseguire sudo apt-get install ca-certificates
  2. Su Alpine Linux, eseguire apk add ca-certificates

Se non avete accesso diretto al sistema che esegue il vostro codice PHP, potete installare il certificato manualmente:

  1. Scaricare il certificato sul vostro computer: https://letsencrypt.org/certs/isrgrootx1.pem
  2. Aggiungere il file isrgrootx1.pem ai file del vostro progetto PHP.
  3. Commentare la riga PDO::MYSQL_ATTR_SSL_CAPATH => '/etc/ssl/certs/'
  4. Decommentare la riga PDO::MYSQL_ATTR_SSL_CA => 'isrgrootx1.pem'

Se si verifica l'errore:

Fatal error: Uncaught Error: Undefined constant PDO::MYSQL_ATTR_SSL_CAPATH

o un messaggio simile come:

Fatal error: Uncaught Error: Undefined constant PDO::MYSQL_*

questo indica che PDO è stato installato senza supporto MySQL.

Soluzione per Ubuntu/Debian

Per risolvere questo problema su sistemi basati su Ubuntu o Debian, installare l'estensione PHP MySQL richiesta eseguendo il seguente comando:

sudo apt-get install php-mysql
Soluzione per Docker

Se si utilizza Docker, assicurarsi che il supporto MySQL sia incluso durante il processo di build. Aggiungere la seguente riga al vostro Dockerfile:

RUN docker-php-ext-install pdo pdo_mysql

Modificare il file .env e definire la variabile DATABASE_URL come segue:

DATABASE_URL="mysql://<USER>:<PASSWORD>@XXXXXX.stackhero-network.com:<PORT>/<DATABASE>"

Quindi, modificare il file config/packages/doctrine.yaml e impostare il driver e le opzioni come segue:

doctrine:
    dbal:
        url: '%env(resolve:DATABASE_URL)%'
        driver: 'pdo_mysql'
        options:
            # PDO::MYSQL_ATTR_SSL_CAPATH
            1010: '/etc/ssl/certs'
            # PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT
            1014: true

Se ricevete l'errore:

Uncaught PDOException: PDO::__construct(): SSL operation failed with code 1. OpenSSL Error messages: error:0A000086:SSL routines::certificate verify failed

questo è probabilmente dovuto al fatto che la directory /etc/ssl/certs/ non contiene certificati CA.

Se avete accesso al sistema che esegue il vostro codice PHP, potete installare questi certificati come segue:

  1. Su Ubuntu/Debian, eseguire sudo apt-get install ca-certificates
  2. Su Alpine Linux, eseguire apk add ca-certificates

Se non avete accesso diretto al sistema, potete installare il certificato manualmente:

  1. Scaricare il certificato sul vostro computer: https://letsencrypt.org/certs/isrgrootx1.pem
  2. Aggiungere il file isrgrootx1.pem al vostro progetto Symfony.
  3. Modificare il file config/packages/doctrine.yaml e impostare il driver e le opzioni come segue:
doctrine:
    dbal:
        url: '%env(resolve:DATABASE_URL)%'
        driver: 'pdo_mysql'
        options:
            # PDO::MYSQL_ATTR_SSL_CA
            1009: 'isrgrootx1.pem'
            # PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT
            1014: true

Modificare il file config/database.php e sostituire la configurazione mysql con le seguenti impostazioni:

'mysql' => [
  'driver' => 'mysql',
  'host' => env('STACKHERO_MYSQL_HOST'),
  'port' => env('STACKHERO_MYSQL_PORT'),
  'username' => env('STACKHERO_MYSQL_USER'),
  'password' => env('STACKHERO_MYSQL_PASSWORD'),
  'database' => env('STACKHERO_MYSQL_USER'),
  'charset' => 'utf8mb4',
  'collation' => 'utf8mb4_unicode_ci',
  'prefix' => '',
  'prefix_indexes' => true,
  'strict' => true,
  'engine' => null,
  'sslmode' => 'require',
  'options' => extension_loaded('pdo_mysql')
    ? array_filter([
      // Se si verifica un errore come "Uncaught PDOException: PDO::__construct(): SSL operation failed with code 1. OpenSSL Error messages: error:0A000086:SSL routines::certificate verify failed",
      PDO::MYSQL_ATTR_SSL_CAPATH => '/etc/ssl/certs/',
      // PDO::MYSQL_ATTR_SSL_CA => 'isrgrootx1.pem',
      PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT => true,
    ])
    : [],
],

Nel file database.php, aggiungere la seguente configurazione:

$db['default'] = array(
  'hostname' => getenv('STACKHERO_MYSQL_HOST'),
  'port'     => getenv('STACKHERO_MYSQL_PORT'),
  'username' => getenv('STACKHERO_MYSQL_USER'),
  'password' => getenv('STACKHERO_MYSQL_PASSWORD'),
  'database' => getenv('STACKHERO_MYSQL_USER'), // Per convenzione, il database ha lo stesso nome dell'utente.
  'dbdriver' => 'mysqli',
  'dbprefix' => '',
  'pconnect' => true,
  'char_set' => 'utf8',
  'dbcollat' => 'utf8_general_ci',
  'encrypt'  => array() // Importante: attivare la crittografia TLS
);

È una buona pratica non memorizzare le credenziali nel codice sorgente ma utilizzare invece variabili d'ambiente.

Di seguito è riportato un esempio per recuperare queste credenziali:

$hostname = getenv('STACKHERO_MYSQL_HOST');
$port = getenv('STACKHERO_MYSQL_PORT');
$user = getenv('STACKHERO_MYSQL_USER');
$password = getenv('STACKHERO_MYSQL_PASSWORD');
$database = getenv('STACKHERO_MYSQL_USER'); // Per convenzione, il database ha lo stesso nome dell'utente.

Connettere WordPress a Stackhero per MySQL è semplice. Basta modificare il file wp-config.php e configurare il database come segue:

define('DB_HOST', '<XXXXXX>.stackhero-network.com');
define('DB_PORT', '<PORT>');
define('DB_NAME', 'root');
define('DB_USER', 'root');
define('DB_PASSWORD', '<yourPassword>');

// Utilizzare la crittografia TLS (nota anche come SSL)
define('MYSQL_CLIENT_FLAGS', MYSQLI_CLIENT_SSL);

La parte importante qui è l'attivazione della crittografia TLS (nota anche come SSL). Senza di essa, la connessione non funzionerà.

In questo esempio, utilizziamo il pacchetto ufficiale xdevapi per sfruttare il protocollo MySQL X. Per installarlo, eseguire:

npm install @mysql/xdevapi

Di seguito è riportato un esempio completo che utilizza xdevapi:

const mysqlx = require('@mysql/xdevapi');

(async () => {
  // Connettersi a MySQL utilizzando il protocollo MySQL X
  const session = await mysqlx.getSession({
    host: '<XXXXXX>.stackhero-network.com',
    port: '<PORT>',
    user: 'root',
    password: '<ROOT_PASSWORD>'
  });

  // Creare uno schema (database) se non esiste
  const schemaExists = await session.getSchema('stackherotest').existsInDatabase();
  if (!schemaExists) {
    await session.createSchema('stackherotest');
  }

  // Creare la tabella 'users' se non esiste
  const tableExists = await session
    .getSchema('stackherotest')
    .getTable('users')
    .existsInDatabase();
  if (!tableExists) {
    await session
      .sql('CREATE TABLE `stackherotest`.`users` '
        + '('
        + '`userId` INT UNSIGNED NOT NULL,'
        + '`name` VARCHAR(128) NOT NULL,'
        + '`address` TEXT NOT NULL,'
        + '`email` VARCHAR(265) NOT NULL'
        + ') '
        + 'ENGINE = InnoDB;')
      .execute();
  }

  // Inserire un utente fittizio
  await session
    .getSchema('stackherotest') // Nome del database
    .getTable('users') // Nome della tabella
    .insert('userId', 'name', 'address', 'email') // Nomi delle colonne
    .values(
      Math.round(Math.random() * 100000), // Generare un userId fittizio
      'Nome utente', // colonna 'name'
      'Indirizzo utente', // colonna 'address'
      'user@email.com' // colonna 'email'
    )
    .execute();

  // Contare il numero di righe nella tabella 'users'
  const usersCount = await session
    .getSchema('stackherotest') // Nome del database
    .getTable('users')
    .count();

  console.log(`Ci sono ora ${usersCount} voci nella tabella "users"`);

  // Chiudere la connessione a MySQL
  await session.close();

})().catch(error => {
  console.error('');
  console.error('🐞 Si è verificato un errore!');
  console.error(error);
  process.exit(1);
});

In questo esempio, utilizziamo il pacchetto mysql2 con supporto delle promesse. Per installarlo, eseguire:

npm install mysql2
const mysql = require('mysql2/promise');

(async () => {
  const db = await mysql.createConnection({
    host: '<XXXXXX>.stackhero-network.com',
    port: '<PORT>',
    user: 'root',
    password: '<ROOT_PASSWORD>'
  });

  // Creare il database 'stackherotest' se non esiste ancora
  await db.query('CREATE DATABASE IF NOT EXISTS stackherotest');

  // Creare la tabella 'users' se non esiste ancora
  await db.query('CREATE TABLE IF NOT EXISTS `stackherotest`.`users` '
    + '('
    + '`userId` INT UNSIGNED NOT NULL,'
    + '`name` VARCHAR(128) NOT NULL,'
    + '`address` TEXT NOT NULL,'
    + '`email` VARCHAR(265) NOT NULL'
    + ') '
    + 'ENGINE = InnoDB;');

  // Inserire un utente fittizio
  await db.query(
    'INSERT INTO `stackherotest`.`users` (`userId`, `name`, `address`, `email`) VALUES ?',
    [
      [
        Math.round(Math.random() * 100000), // Generare un userId fittizio
        'Nome utente', // colonna 'name'
        'Indirizzo utente', // colonna 'address'
        'user@email.com' // colonna 'email'
      ]
    ]
  );

  // Contare il numero di righe nella tabella 'users'
  const [ usersCount ] = await db.query('SELECT COUNT(*) AS `cpt` FROM `stackherotest`.`users`');
  console.log(`Ci sono ora ${usersCount[0].cpt} voci nella tabella "users"`);

  // Chiudere la connessione a MySQL
  await db.end();

})().catch(error => {
  console.error('');
  console.error('🐞 Si è verificato un errore!');
  console.error(error);
  process.exit(1);
});

Per connettersi da Node.js, NestJS o TypeORM, includere l'opzione ssl come mostrato in questo esempio:

TypeOrmModule.forRoot({
  type: 'mysql',
  host: '<XXXXXX>.stackhero-network.com',
  port: <PORT>,
  username: 'root',
  password: '<ROOT_PASSWORD>',
  database: 'root',
  entities: [],
  synchronize: true,
  ssl: {}
});

Per connettersi utilizzando Prisma, aggiungere l'opzione sslaccept=strict per garantire che la crittografia SSL sia abilitata. Ecco un esempio utilizzando l'utente "root" e connettendosi al database "root":

datasource db {
  provider = "mysql"
  url = "mysql://root:<ROOT_PASSWORD>@<XXXXXX>.stackhero-network.com:<PORT>/root?sslaccept=strict"
}

Se il modulo mysqlclient non è ancora installato, installarlo poiché verrà utilizzato per connettersi a MySQL:

pip install mysqlclient

Se si verifica l'errore Exception: Can not find valid pkg-config name durante l'installazione di mysqlclient, installare il pacchetto libmysqlclient. Su Ubuntu/Debian, è possibile eseguire: apt-get update && apt-get install --no-install-recommends -y libmysqlclient-dev

In questo passaggio iniziale, la password è memorizzata direttamente nel file settings.py solo a scopo di test. Si consiglia di utilizzare un approccio più sicuro come descritto più avanti in questa documentazione.

Aprire il file settings.py e aggiungere quanto segue:

DATABASES = {
  'default': {
    'ENGINE': 'django.db.backends.mysql',
    'HOST': '<XXXXXX>.stackhero-network.com',
    'PORT': '<PORT>',
    'OPTIONS': {
      'ssl_mode': 'REQUIRED',
    },
    'NAME': 'root',
    'USER': 'root',
    'PASSWORD': '<ROOT_PASSWORD>'
  }
}

Attenzione: questo esempio non è raccomandato per la produzione ed è destinato solo a scopo di test!

Una volta che la connessione è riuscita, è possibile utilizzare il metodo raccomandato per memorizzare le credenziali in modo sicuro. In questo esempio, django-environ è utilizzato per gestire le variabili d'ambiente.

Per prima cosa, installare django-environ utilizzando il comando:

pip install django-environ

Quindi aprire il file settings.py e aggiungere quanto segue:

import environ
env = environ.Env()
environ.Env.read_env()

DATABASES = {
  'default': {
    'ENGINE': 'django.db.backends.mysql',
    'HOST': env('STACKHERO_MYSQL_HOST'),
    'PORT': env('STACKHERO_MYSQL_PORT'),
    'OPTIONS': {
      'ssl_mode': 'REQUIRED',
    },
    'NAME': 'root',
    'USER': 'root',
    'PASSWORD': env('STACKHERO_MYSQL_ROOT_PASSWORD')
  }
}

Successivamente, aprire o creare il file .env nella stessa directory di settings.py e aggiungere quanto segue:

STACKHERO_MYSQL_HOST=<XXXXXX>.stackhero-network.com
STACKHERO_MYSQL_PORT=<PORT>
STACKHERO_MYSQL_ROOT_PASSWORD=<ROOT_PASSWORD>

Infine, aggiungere .env al file .gitignore per garantire che le credenziali non vengano commesse nel vostro repository Git:

echo ".env" >> .gitignore

Per connettere la vostra applicazione Spring, impostare la variabile d'ambiente SPRING_DATASOURCE_URL con l'URL del vostro database, prefissato da jdbc::

SPRING_DATASOURCE_URL=jdbc:mysql://root:<ROOT_PASSWORD>@<XXXXXX>.stackhero-network.com:<PORT>/root?useSSL=true&requireSSL=true

Il seguente esempio dimostra come connettere la vostra applicazione Grails a MySQL:

dataSource {
  pooled = true
  driverClassName = "com.mysql.cj.jdbc.Driver"
  dialect = org.hibernate.dialect.MySQL8Dialect
  // Proprietà specifiche SSL
  properties {
    useSSL = true
    requireSSL = true
    verifyServerCertificate = true
    sslMode = "REQUIRED"
  }
}

environments {
  production {
    dataSource {
      dbCreate = "none"
      url = "jdbc:mysql://" + System.env.STACKHERO_MYSQL_HOST + ":" + System.env.STACKHERO_MYSQL_PORT + "/root?useSSL=true&requireSSL=true&verifyServerCertificate=true&sslMode=required" // Sostituire "/root" con il database a cui si desidera connettersi.
      username = "root" // È consigliabile creare un utente dedicato piuttosto che utilizzare le credenziali "root".
      password = System.env.STACKHERO_MYSQL_ROOT_PASSWORD // È consigliabile creare un utente dedicato piuttosto che utilizzare le credenziali "root".
      properties {
        maxActive = 50
        minEvictableIdleTimeMillis = 1800000
        timeBetweenEvictionRunsMillis = 1800000
        numTestsPerEvictionRun = 3
        testOnBorrow = true
        testWhileIdle = true
        testOnReturn = false
        validationQuery = "SELECT 1"
      }
    }
  }
}

Una buona pratica è creare un utente dedicato per la vostra applicazione piuttosto che utilizzare l'utente "root".

Il modo più semplice per farlo è tramite phpMyAdmin.

  1. In phpMyAdmin, cliccare su Account utente in alto.

  2. Cliccare su Aggiungi account utente.

  3. Completare il modulo di creazione dell'utente:

    1. Scegliere un nome account (tipicamente il nome della vostra applicazione)
    2. Cliccare su Genera password per creare una password sicura (copiarla negli appunti)
    3. Selezionare l'opzione Crea database con lo stesso nome e concedi tutti i privilegi

Una volta convalidato il modulo, il nuovo utente verrà creato insieme a un database corrispondente che condivide lo stesso nome dell'username.