Перейти к основному содержимому

MySQL — практическая работа и API

Разработчику Аналитику Инженеру

Другие СУБД в этом цикле: SQLite · PostgreSQL · Microsoft SQL Server · SQL — о разделе.

MySQL — серверная реляционная СУБД. Чаще всего используется с движком InnoDB, который даёт транзакции, внешние ключи, блокировки на уровне строк и надёжность для веб-приложений.


Как работает MySQL

  • Запускается сервер mysqld.
  • Клиенты подключаются по TCP или Unix socket.
  • Данные и индексы хранятся в таблицах выбранного storage engine.
  • InnoDB использует redo/undo logs и MVCC.
  • Репликация работает в binlog-архитектуре.
SELECT VERSION();
SHOW VARIABLES LIKE 'default_storage_engine';
SHOW VARIABLES LIKE 'transaction_isolation';

Подключение и запуск

mysql CLI

mysql -h localhost -P 3306 -u app_user -p app_db

URI-подключение

mysql://app_user:secret@localhost:3306/app_db
mysql://app_user:secret@localhost:3306/app_db?charset=utf8mb4

Базовая настройка

CREATE DATABASE app_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'app_user'@'%' IDENTIFIED BY 'secret';
GRANT ALL PRIVILEGES ON app_db.* TO 'app_user'@'%';
FLUSH PRIVILEGES;

Типы данных и синтаксис

Основные типы MySQL:

  • Числовые: TINYINT, INT, BIGINT, DECIMAL, FLOAT, DOUBLE
  • Строковые: CHAR, VARCHAR, TEXT
  • Дата/время: DATE, TIME, DATETIME, TIMESTAMP
  • Бинарные: BLOB, VARBINARY
  • JSON: JSON
  • Логические значения обычно задают через TINYINT(1) или BOOLEAN (синоним)
CREATE TABLE users (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
email VARCHAR(255) NOT NULL UNIQUE,
profile JSON,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB;

Возможности MySQL

  • Полный базовый SQL для DDL/DML
  • Транзакции (InnoDB)
  • INSERT ... ON DUPLICATE KEY UPDATE для upsert-сценариев
  • Индексы, составные индексы, уникальные ограничения
  • VIEW, TRIGGER, PROCEDURE, FUNCTION, события (EVENT)
  • Репликация и кластерные варианты (Group Replication, InnoDB Cluster)
  • JSON-тип и JSON-функции
  • Партиционирование

Доступные и недоступные команды

КатегорияКоманда / конструкцияСтатус в MySQLКомментарий
DMLSELECT, INSERT, UPDATE, DELETEДоступноПолная поддержка
DDLCREATE/ALTER/DROPДоступноПоддерживается
ТранзакцииBEGIN, COMMIT, ROLLBACK, SAVEPOINTДоступно (InnoDB)Зависит от storage engine
ПраваCREATE USER, GRANT, REVOKEДоступноРазвитая модель привилегий
Server-side логикаPROCEDURE, FUNCTION, TRIGGER, EVENTДоступноПоддерживается
Материализованные представленияCREATE MATERIALIZED VIEWНедоступноИмитация через таблицы + расписание
Полноценный RETURNING в DMLЧастично/ограниченоПроверяйте версию и совместимость
MERGEНедоступноОбычно заменяют upsert-паттернами
Нативный тип массивов как в PostgreSQLНедоступноИспользуют JSON или отдельные таблицы
PostgreSQL-специфика (DISTINCT ON, ILIKE)НедоступноИспользуют альтернативы MySQL

Практика SQL в MySQL

CRUD

CREATE TABLE tasks (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
title VARCHAR(255) NOT NULL,
done TINYINT(1) NOT NULL DEFAULT 0
) ENGINE=InnoDB;

INSERT INTO tasks(title) VALUES ('Пройти MySQL');
SELECT id, title, done FROM tasks ORDER BY id;
UPDATE tasks SET done = 1 WHERE id = 1;
DELETE FROM tasks WHERE id = 1;

Upsert

INSERT INTO tasks(id, title, done)
VALUES (1, 'Обновлённая задача', 0)
ON DUPLICATE KEY UPDATE
title = VALUES(title),
done = VALUES(done);

Транзакция

START TRANSACTION;
INSERT INTO tasks(title) VALUES ('A');
INSERT INTO tasks(title) VALUES ('B');
COMMIT;

Клиенты и инструменты

  • mysql CLI
  • MySQL Workbench
  • phpMyAdmin
  • DBeaver
  • DataGrip
  • TablePlus
  • Beekeeper Studio
  • VS Code + MySQL extensions

API по языкам — подключение, CRUD, библиотеки, классы и функции

Как читать блоки API
В каждом блоке указаны библиотека, ключевые классы/типы, основные свойства и методы, затем минимальный рабочий пример подключения и CRUD.


C# — MySqlConnector

Библиотека

  • MySqlConnector (NuGet)

Ключевые классы

  • MySqlConnection
  • MySqlCommand
  • MySqlTransaction
  • MySqlDataReader
  • MySqlParameter

Свойства и методы

  • Open(), BeginTransaction(), Close()
  • CommandText, Parameters.AddWithValue()
  • ExecuteNonQuery(), ExecuteReader(), ExecuteScalar()
  • Read(), GetString(), GetInt64()
using MySqlConnector;

var cs = "Server=localhost;Port=3306;User ID=app_user;Password=secret;Database=app_db;";
await using var conn = new MySqlConnection(cs);
await conn.OpenAsync();

await using (var cmd = new MySqlCommand("""
CREATE TABLE IF NOT EXISTS users(
id BIGINT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(255) NOT NULL
) ENGINE=InnoDB
""", conn))
{
await cmd.ExecuteNonQueryAsync();
}

await using (var ins = new MySqlCommand("INSERT INTO users(name) VALUES (@name)", conn))
{
ins.Parameters.AddWithValue("@name", "Anna");
await ins.ExecuteNonQueryAsync();
}

await using (var sel = new MySqlCommand("SELECT id, name FROM users", conn))
await using (var reader = await sel.ExecuteReaderAsync())
{
while (await reader.ReadAsync())
Console.WriteLine($"{reader.GetInt64(0)} {reader.GetString(1)}");
}

Python — mysql-connector-python или PyMySQL

Библиотеки

  • mysql-connector-python
  • PyMySQL

Ключевые классы

  • MySQLConnection
  • Cursor

Методы

  • connect()
  • cursor(), execute(), executemany()
  • fetchone(), fetchall()
  • commit(), rollback(), close()
import mysql.connector

conn = mysql.connector.connect(
host="localhost", port=3306, user="app_user", password="secret", database="app_db"
)
cur = conn.cursor()

cur.execute("""
CREATE TABLE IF NOT EXISTS users(
id BIGINT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(255) NOT NULL
) ENGINE=InnoDB
""")

cur.execute("INSERT INTO users(name) VALUES (%s)", ("Anna",))
conn.commit()

cur.execute("SELECT id, name FROM users")
for row in cur.fetchall():
print(row[0], row[1])

cur.execute("UPDATE users SET name=%s WHERE id=%s", ("Ann", 1))
cur.execute("DELETE FROM users WHERE id=%s", (1,))
conn.commit()
conn.close()

Java — MySQL Connector/J

Библиотека

  • com.mysql:mysql-connector-j

Ключевые классы

  • Connection
  • PreparedStatement
  • ResultSet
  • DriverManager

Методы

  • DriverManager.getConnection("jdbc:mysql://...")
  • prepareStatement(), setAutoCommit(false), commit(), rollback()
  • setString(), executeUpdate(), executeQuery()
  • next(), getLong(), getString()
import java.sql.*;

try (Connection conn = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/app_db", "app_user", "secret")) {

try (Statement st = conn.createStatement()) {
st.execute("""
CREATE TABLE IF NOT EXISTS users(
id BIGINT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(255) NOT NULL
) ENGINE=InnoDB
""");
}

try (PreparedStatement ins = conn.prepareStatement("INSERT INTO users(name) VALUES (?)")) {
ins.setString(1, "Anna");
ins.executeUpdate();
}

try (PreparedStatement sel = conn.prepareStatement("SELECT id, name FROM users");
ResultSet rs = sel.executeQuery()) {
while (rs.next()) {
System.out.println(rs.getLong("id") + " " + rs.getString("name"));
}
}
}

C — MySQL C API (libmysqlclient)

Библиотека

  • libmysqlclient

Ключевые типы

  • MYSQL
  • MYSQL_RES
  • MYSQL_ROW
  • MYSQL_STMT

Ключевые функции

  • mysql_init(), mysql_real_connect(), mysql_close()
  • mysql_query(), mysql_store_result(), mysql_fetch_row()
  • Prepared statements: mysql_stmt_init(), mysql_stmt_prepare(), mysql_stmt_bind_param(), mysql_stmt_execute()
  • Ошибки: mysql_error(), mysql_errno()
#include <mysql.h>
#include <stdio.h>

int main(void) {
MYSQL *conn = mysql_init(NULL);
if (!mysql_real_connect(conn, "localhost", "app_user", "secret", "app_db", 3306, NULL, 0)) return 1;

mysql_query(conn, "CREATE TABLE IF NOT EXISTS users(id BIGINT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(255) NOT NULL) ENGINE=InnoDB");
mysql_query(conn, "INSERT INTO users(name) VALUES ('Anna')");
mysql_query(conn, "SELECT id, name FROM users");

MYSQL_RES *res = mysql_store_result(conn);
MYSQL_ROW row;
while ((row = mysql_fetch_row(res))) {
printf("%s %s\n", row[0], row[1]);
}
mysql_free_result(res);
mysql_close(conn);
return 0;
}

C++ — MySQL Connector/C++ или SOCI

Библиотеки

  • MySQL Connector/C++
  • SOCI (через backend MySQL)

Ключевые классы (Connector/C++)

  • sql::Driver
  • sql::Connection
  • sql::PreparedStatement
  • sql::ResultSet

Методы

  • driver->connect(...)
  • prepareStatement(), execute(), executeQuery()
  • setString(), next(), getString(), getInt64()
#include <iostream>
// Примерный стиль API Connector/C++
// auto* driver = get_driver_instance();
// std::unique_ptr<sql::Connection> conn(driver->connect("tcp://127.0.0.1:3306", "app_user", "secret"));
// conn->setSchema("app_db");
// ...

Go — go-sql-driver/mysql

Библиотеки

  • database/sql
  • github.com/go-sql-driver/mysql

Ключевые типы

  • *sql.DB
  • *sql.Tx
  • *sql.Rows
  • sql.Result

Методы

  • sql.Open("mysql", dsn)
  • Exec(), Query(), QueryRow()
  • Begin(), Commit(), Rollback()
  • Rows.Next(), Rows.Scan()
package main

import (
"database/sql"
"fmt"
_ "github.com/go-sql-driver/mysql"
)

func main() {
db, _ := sql.Open("mysql", "app_user:secret@tcp(localhost:3306)/app_db?parseTime=true")
defer db.Close()

db.Exec(`CREATE TABLE IF NOT EXISTS users(id BIGINT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(255) NOT NULL) ENGINE=InnoDB`)
db.Exec(`INSERT INTO users(name) VALUES (?)`, "Anna")

rows, _ := db.Query(`SELECT id, name FROM users`)
defer rows.Close()
for rows.Next() {
var id int64
var name string
rows.Scan(&id, &name)
fmt.Println(id, name)
}
}

PHP — mysqli и PDO_MySQL

Библиотеки

  • mysqli
  • PDO (mysql)

Ключевые классы

  • mysqli, mysqli_stmt, mysqli_result
  • PDO, PDOStatement

Методы

  • new mysqli(...), prepare(), bind_param(), execute(), get_result()
  • new PDO("mysql:host=...;dbname=..."), prepare(), execute(), fetchAll()
<?php
$db = new PDO("mysql:host=localhost;port=3306;dbname=app_db;charset=utf8mb4", "app_user", "secret");
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

$db->exec("CREATE TABLE IF NOT EXISTS users(id BIGINT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(255) NOT NULL) ENGINE=InnoDB");

$stmt = $db->prepare("INSERT INTO users(name) VALUES (:name)");
$stmt->execute([':name' => 'Anna']);

$rows = $db->query("SELECT id, name FROM users")->fetchAll(PDO::FETCH_ASSOC);
foreach ($rows as $row) {
echo $row['id'] . " " . $row['name'] . PHP_EOL;
}

Kotlin — JDBC (MySQL)

Библиотека

  • JDBC + MySQL Connector/J

Ключевые классы

  • Connection
  • PreparedStatement
  • ResultSet

Методы

  • DriverManager.getConnection()
  • prepareStatement(), executeUpdate(), executeQuery()
  • setString(), next(), getLong(), getString()
import java.sql.DriverManager

fun main() {
DriverManager.getConnection(
"jdbc:mysql://localhost:3306/app_db", "app_user", "secret"
).use { conn ->
conn.createStatement().use { st ->
st.execute(
"CREATE TABLE IF NOT EXISTS users(id BIGINT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(255) NOT NULL) ENGINE=InnoDB"
)
}
conn.prepareStatement("INSERT INTO users(name) VALUES (?)").use { ps ->
ps.setString(1, "Anna")
ps.executeUpdate()
}
conn.prepareStatement("SELECT id, name FROM users").use { ps ->
ps.executeQuery().use { rs ->
while (rs.next()) println("${rs.getLong("id")} ${rs.getString("name")}")
}
}
}
}

Rust — mysql и sqlx

Библиотеки

  • mysql (синхронный клиент)
  • sqlx (async)

Ключевые типы (mysql crate)

  • Pool
  • PooledConn
  • TxOpts
  • Queryable

Методы

  • Pool::new()
  • get_conn()
  • query_drop(), exec_drop(), query()
  • start_transaction(), commit(), rollback()
use mysql::*;
use mysql::prelude::*;

fn main() -> Result<()> {
let pool = Pool::new("mysql://app_user:secret@localhost:3306/app_db")?;
let mut conn = pool.get_conn()?;

conn.query_drop("CREATE TABLE IF NOT EXISTS users(id BIGINT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(255) NOT NULL) ENGINE=InnoDB")?;
conn.exec_drop("INSERT INTO users(name) VALUES (?)", ("Anna",))?;

let rows: Vec<(u64, String)> = conn.query("SELECT id, name FROM users")?;
for (id, name) in rows {
println!("{id} {name}");
}
Ok(())
}

JavaScript — mysql2

Библиотека

  • mysql2 (promise API)

Ключевые объекты

  • Connection
  • Pool
  • результаты RowDataPacket[]

Методы

  • createConnection(), createPool()
  • execute(sql, params), query()
  • транзакции: beginTransaction(), commit(), rollback()
import mysql from "mysql2/promise";

const conn = await mysql.createConnection({
host: "localhost",
port: 3306,
user: "app_user",
password: "secret",
database: "app_db",
});

await conn.execute(
"CREATE TABLE IF NOT EXISTS users(id BIGINT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(255) NOT NULL) ENGINE=InnoDB"
);
await conn.execute("INSERT INTO users(name) VALUES (?)", ["Anna"]);

const [rows] = await conn.execute("SELECT id, name FROM users");
for (const row of rows) {
console.log(row.id, row.name);
}

await conn.execute("UPDATE users SET name=? WHERE id=?", ["Ann", 1]);
await conn.execute("DELETE FROM users WHERE id=?", [1]);
await conn.end();

Минимальный шаблон безопасной работы

  • Используйте параметризованные запросы.
  • Выбирайте InnoDB для транзакционных таблиц.
  • Фиксируйте charset как utf8mb4.
  • Ограничивайте права пользователей по ролям/схемам.
  • Настраивайте таймауты и пул подключений.
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
SET SESSION innodb_lock_wait_timeout = 10;
SHOW VARIABLES LIKE 'sql_mode';

Когда MySQL подходит и когда выбрать другой путь

MySQL подходит:

  • веб-приложения и сервисы с привычным стеком LAMP/LEMP;
  • высоконагруженные OLTP-сценарии на InnoDB;
  • проекты, где важна простота эксплуатации и большой рынок tooling.

Другой путь выбирают:

  • для сложной аналитики и специфических типов удобен PostgreSQL;
  • для локального файла внутри приложения удобнее SQLite;
  • для специализированного OLAP часто берут колоночные СУБД.

См. также

Другие статьи этого же раздела в боковом меню (как на странице "О разделе").