Используем несколько баз данных в Laravel

от автора

Привет, Хабр!

Бывало ли у вас такое?

  • Основная MySQL-база разрослась до гигантских размеров, и аналитические запросы тормозят продакшен.

  • Нужно подключиться к старой легаси-системе, но переносить данные в основную БД слишком дорого.

  • Часть данных идеально ложится в документоориентированную MongoDB, а другая — в реляционную PostgreSQL.

И тут возникает вопрос: стоит ли использовать несколько баз данных в одном проекте?

Когда это действительно нужно?

Разные типы данных – если часть данных (например, логи, аналитика) плохо уживается с реляционной моделью.
Интеграция с легаси-системой – когда старая БД остаётся, но новому коду нужно с ней работать.
Горизонтальное масштабирование – шардинг или выделение отдельных БД под разные сервисы. Изоляция критичных данных – например, финансовая информация в отдельной защищённой БД.

Подключение к двум разным базам данных в Laravel

Laravel предоставляет удобные инструменты для работы с несколькими базами данных. Рассмотрим пошаговую настройку.

1. Настройка конфигурации

Добавляем подключения в config/database.php:

'connections' => [     'mysql' => [  // Основная база         'driver' => 'mysql',         'host' => env('DB_HOST', '127.0.0.1'),         'port' => env('DB_PORT', '3306'),         'database' => env('DB_DATABASE', 'forge'),         'username' => env('DB_USERNAME', 'forge'),         'password' => env('DB_PASSWORD', ''),         'charset' => 'utf8mb4',         'collation' => 'utf8mb4_unicode_ci',     ],      'secondary' => [  // Вторая база         'driver' => 'mysql',         'host' => env('DB_SECONDARY_HOST', '127.0.0.1'),         'port' => env('DB_SECONDARY_PORT', '3306'),         'database' => env('DB_SECONDARY_DATABASE', 'forge'),         'username' => env('DB_SECONDARY_USERNAME', 'forge'),         'password' => env('DB_SECONDARY_PASSWORD', ''),         'charset' => 'utf8mb4',         'collation' => 'utf8mb4_unicode_ci',     ], ],

2. Добавляем данные в .env

DB_SECONDARY_HOST=127.0.0.1 DB_SECONDARY_PORT=3306 DB_SECONDARY_DATABASE=secondary_db DB_SECONDARY_USERNAME=root DB_SECONDARY_PASSWORD=secret

Теперь, когда мы настроили подключение к двум базам данных, давайте реализуем полноценную работу с ними. Рассмотрим весь цикл разработки: от создания миграций и моделей до реализации CRUD с элементами горизонтального шардинга.

1. Создание миграций для разных баз

Основная база (пользователи)

php artisan make:migration create_users_table

Schema::create('users', function (Blueprint $table) {     $table->id();     $table->string('name');     $table->string('email')->unique();     $table->string('shard_key')->comment('Ключ для шардинга');     $table->timestamps(); });

Вторичная база (заказы)

php artisan make:migration create_orders_table

Schema::connection('secondary')->create('orders', function (Blueprint $table) {     $table->id();     $table->foreignId('user_id');     $table->decimal('amount', 10, 2);     $table->string('status');     $table->timestamps(); });

2. Создание моделей с отношениями

Модель User (основная база)

class User extends Model {     protected $connection = 'mysql';          public function orders(): HasMany     {         // Логическая связь с заказами во второй базе. В моделе Order обязательно        нужно указать $connection!          return $this->hasMany(             Order::class,             'user_id',             'id',         );     }          // Определяем шард для пользователя      public function getConnectionName()     {         if ($this->shard_key !== null) {             return $this->shard_key % 2 == 0                  ? 'mysql_shard1'                  : 'mysql_shard2';         }                  return parent::getConnectionName();     } }

Модель Order (вторая база)

class Order extends Model {     protected $connection = 'secondary';          public function user(): BelongsTo     {         // Обратная связь с пользователем. В моделе User обязательно        нужно указать $connection!          return $this->belongsTo(             User::class,             'user_id',             'id',         );     } }

3. Реализация базового CRUD с шардингом

UserService (работа с пользователями)

class UserService {     public function createUser(array $data)     {         // Автоматическое определение шарда на основе email         $shardKey = crc32($data['email']) % 2;         $data['shard_key'] = $shardKey;                  return User::create($data);     } }
public function getUserWithOrders($userId)     {         $user = User::findOrFail($userId);         $orders = $user->orders()->get();                  return [             'user' => $user,             'orders' => $orders         ];     }

Таким образом, запись сразу достаётся и кладётся в нужную нам базу данных. Но, к сожалению, у Laravel есть ограничения, при работе с двумя и более базами данных. Практически всегда вам придётся указывать подключения явно, используя метод connection()

Свыкнуться с этим можно, но хотелось бы видеть более удобный способ кооперации двух баз данных. Если эта тема будет интересна, я бы хотел поработать над пакетом для Laravel для реализации подобного функционала. Неравнодушные, сплочаемся!

Работа с несколькими базами данных в Laravel требует дополнительных усилий, но в определённых сценариях это единственный разумный путь. Основные правила:

  1. Чётко разделяйте данные по функциональному признаку

  2. Документируйте, какие модели к каким БД относятся

  3. Реализуйте механизмы синхронизации критичных данных

  4. Мониторьте производительность всех подключений

А вам приходилось работать с несколькими БД в одном проекте? Делитесь опытом в комментариях — обсудим лучшие практики и подводные камни!


ссылка на оригинал статьи https://habr.com/ru/articles/896568/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *