Привет, Хабр!
Бывало ли у вас такое?
-
Основная 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 требует дополнительных усилий, но в определённых сценариях это единственный разумный путь. Основные правила:
-
Чётко разделяйте данные по функциональному признаку
-
Документируйте, какие модели к каким БД относятся
-
Реализуйте механизмы синхронизации критичных данных
-
Мониторьте производительность всех подключений
А вам приходилось работать с несколькими БД в одном проекте? Делитесь опытом в комментариях — обсудим лучшие практики и подводные камни!
ссылка на оригинал статьи https://habr.com/ru/articles/896568/
Добавить комментарий