One place for hosting & domains

      Como usar o Migrations de banco de dados e o Seeders para abstrair a configuração do banco de dados em Laravel


      Migrations [Migrações] e seeders [Propagadores] são utilitários de banco de dados eficazes, fornecidos pela framework do Laravel para PHP, que permite que os desenvolvedores façam a inicialização, destruição e recriação do banco de dados de um aplicativo rapidamente. Esses utilitários ajudam a minimizar problemas de inconsistência de banco de dados que podem surgir com vários desenvolvedores trabalhando no mesmo aplicativo: novos colaboradores precisam apenas executar alguns comandos do artisan para definir o banco de dados em uma nova instalação.

      Neste guia, vamos criar migrations (migrações) e seeders (propagadores) para preencher o banco de dados de um aplicativo de demonstração do Laravel com dados de amostra. No final, você poderá destruir e recriar as tabelas de seu banco de dados quantas vezes quiser, usando apenas comandos do artisan.

      Pré-requisitos

      Para seguir este guia, você vai precisar do seguinte:

      Nota: neste guia, utilizaremos um ambiente de desenvolvimento em contêiner, gerenciado pelo Docker Compose para executar o aplicativo, mas você também pode optar por executar o aplicativo em um servidor LEMP. Para configurar isso, siga nosso guia sobre Como instalar e configurar o Laravel com LEMP no Ubuntu 18.04.

      Passo 1 — Obtendo o aplicativo Demo

      Para começar, iremos buscar o aplicativo de demonstração do Laravel a partir de seu repositório do GitHub. Estamos interessados na ramificação do tutorial-02, que inclui uma Configuração do Docker Compose para executar o aplicativo em contêineres. Neste exemplo, baixaremos o aplicativo para nossa pasta base, mas também é possível usar qualquer diretório de sua escolha:

      • cd ~
      • curl -L https://github.com/do-community/travellist-laravel-demo/archive/tutorial-2.0.1.zip -o travellist.zip

      Como baixamos o código do aplicativo como um arquivo .zip, precisaremos do comando unzip para desempacotá-lo. Se não tiver feito isso recentemente, atualize o índice de pacotes local de sua máquina:

      Depois, instale o pacote unzip:

      Em seguida, descompacte o conteúdo do aplicativo:

      Em seguida, renomeie o diretório descompactado como travellist-demo para facilitar o acesso:

      • mv travellist-laravel-demo-tutorial-2.0.1 travellist-demo

      No próximo passo, vamos criar um arquivo de configuração .env para configurar o aplicativo.

      Passo 2 — Configurando o arquivo .env do aplicativo

      No Laravel, o arquivo .env é usado para configurar as configurações dependentes de ambiente, como credenciais e quaisquer informações que possam variar entre as implantações. Esse arquivo não está incluído no controle de revisão.

      Aviso: o arquivo de configuração de ambiente contém informações confidenciais sobre o seu servidor, incluindo credenciais para o banco de dados e chaves de segurança. Por esse motivo, nunca compartilhe esse arquivo publicamente.

      Os valores contidos no arquivo .env terão precedência sobre os valores definidos nos arquivos de configuração regulares, localizados no diretório config. Cada instalação em um novo ambiente exige um arquivo de ambiente personalizado para definir coisas como as configurações de conexão com o banco de dados, as opções de depuração, o URL do aplicativo, entre outros itens que possam variar, dependendo do ambiente em que o aplicativo esteja funcionando.

      Navegue até o diretório travellist-demo:

      Agora, vamos criar um novo arquivo .env para personalizar as opções de configuração do ambiente de desenvolvimento que estamos preparando. O Laravel vem com um exemplo de arquivo do .env que podemos copiar para criar o nosso:

      Abra este arquivo, usando o nano ou outro editor de texto de sua escolha:

      Esta é a aparência do seu arquivo .env agora:

      .env

      APP_NAME=Travellist
      APP_ENV=dev
      APP_KEY=
      APP_DEBUG=true
      APP_URL=http://localhost:8000
      
      LOG_CHANNEL=stack
      
      DB_CONNECTION=mysql
      DB_HOST=db
      DB_PORT=3306
      DB_DATABASE=travellist
      DB_USERNAME=travellist_user
      DB_PASSWORD=password

      O arquivo .env atual do aplicativo de demonstração travellist contém configurações para usar o ambiente em contêiner que criamos com o Docker Compose na última parte desta série. Você não precisa alterar nenhum desses valores, mas fique à vontade para modificar o DB_DATABASE, o DB_USERNAME e o DB_PASSWORD se quiser, uma vez que eles são puxados automaticamente pelo nosso arquivo docker-compose.yml para configurar o banco de dados de desenvolvimento. Certifique-se apenas de que a variável DB_HOST permaneça inalterada, uma vez que ela faz referência ao nome do nosso serviço de banco de dados dentro do ambiente do Docker Compose.

      Caso faça quaisquer alterações no arquivo, certifique-se de salvar e fechar ele pressionando CTRL + X, Y e, então, ENTER.

      Nota: caso tenha optado por executar o aplicativo em um servidor LEMP, será necessário alterar os valores destacados para refletir as configurações do seu próprio banco de dados, incluindo a variável DB_HOST.

      Agora, usaremos o Composer, uma ferramenta de gerenciamento de dependências do PHP, para instalar as dependências do aplicativo e garantir que possamos executar os comandos do artisan.

      Abra seu ambiente do Docker Compose com o comando a seguir. Isso compilará a imagem do travellist para o serviço do app e extrairá imagens adicionais do Docker – exigidas pelos serviços nginx e db, para criar o ambiente do aplicativo:

      Output

      Creating network "travellist-demo_travellist" with driver "bridge" Building app Step 1/11 : FROM php:7.4-fpm ---> fa37bd6db22a Step 2/11 : ARG user ---> Running in 9259bb2ac034 … Creating travellist-app ... done Creating travellist-nginx ... done Creating travellist-db ... done

      Esta operação pode levar alguns minutos para completar. Assim que o processo terminar, podemos executar o Composer para instalar as dependências do aplicativo.

      Para executar o composer e outros comandos no contêiner de serviço do app, utilizaremos o docker-compose exec. O comando exec permite que executemos qualquer comando de nossa escolha em contêineres gerenciados pelo Docker Compose. Ele usa a seguinte sintaxe: docker-compose exec service_name command.

      Nota: caso tenha optado por usar um servidor LEMP para executar o aplicativo de demonstração, ignore a parte do docker-compose exec app dos comandos listados durante todo este guia. Por exemplo, em vez de executar o seguinte comando como ele está escrito, você apenas executaria:

      Para executar o composer install no contêiner do app, execute:

      • docker-compose exec app composer install

      Output

      Loading composer repositories with package information Installing dependencies (including require-dev) from lock file Package operations: 85 installs, 0 updates, 0 removals - Installing doctrine/inflector (1.3.1): Downloading (100%) - Installing doctrine/lexer (1.2.0): Downloading (100%) - Installing dragonmantank/cron-expression (v2.3.0): Downloading (100%) …

      Quando o Composer terminar de instalar as dependências do aplicativo, você poderá executar os comandos do artisan. Para testar se o aplicativo consegue se conectar ao banco de dados, execute o seguinte comando que limpará quaisquer tabelas pré-existentes:

      • docker-compose exec app php artisan db:wipe

      Esse comando removerá quaisquer tabelas pré-existentes do banco de dados configurado. Se ele foi executado com sucesso e o aplicativo conseguiu se conectar ao banco de dados, você verá um resultado parecido com este:

      Output

      Dropped all tables successfully.

      Agora que você tem as dependências do aplicativo instaladas com o Composer, você pode utilizar a ferramenta artisan para criar migrations e seeders.

      Passo 4 — Criando migrations de banco de dados

      A ferramenta de linha de comando do artisan que vem com o Laravel contém uma série de comandos auxiliares que podem ser usados para gerenciar o aplicativo e inicializar novas classes. Para gerar uma nova classe de migration, podemos usar o comando make:migration como segue:

      • docker-compose exec app php artisan make:migration create_places_table

      O Laravel deduz a operação a ser executada (create), o nome da tabela (places) e se essa migration criará uma nova tabela ou não, com base no nome descritivo fornecido para o comando make:migration.

      Você verá um resultado semelhante a este:

      Output

      Created Migration: 2020_02_03_143622_create_places_table

      Isso gerará um novo arquivo no diretório database/migrations do aplicativo. O carimbo de data/hora no arquivo gerado automaticamente é utilizado pelo Laravel para determinar em qual ordem as migrations devem ser executadas.

      Utilize seu editor de texto preferido para abrir o arquivo migration gerado. Lembre-se de substituir o valor destacado pelo nome de arquivo de migration de sua escolha:

      • nano database/migrations/2020_02_03_143622_create_places_table.php

      O arquivo de migration gerado contém uma classe chamada CreatePlacesTable:

      database/migrations/2020_02_03_143622_create_places_table.php

      <?php
      
      use IlluminateDatabaseMigrationsMigration;
      use IlluminateDatabaseSchemaBlueprint;
      use IlluminateSupportFacadesSchema;
      
      class CreatePlacesTable extends Migration
      {
          /**
           * Run the migrations.
           *
           * @return void
           */
          public function up()
          {
              Schema::create('places', function (Blueprint $table) {
                  $table->bigIncrements('id');
                  $table->timestamps();
              });
          }
      
          /**
           * Reverse the migrations.
           *
           * @return void
           */
          public function down()
          {
              Schema::dropIfExists('places');
          }
      }
      
      

      Essa classe tem dois métodos: up e down. Ambos os métodos contêm o código de inicialização que podem ser estendidos para personalizar o que acontece quando essa migration for executada e também o que acontece quando ela for revertida.

      Vamos modificar o método up, de modo que a tabela places reflita a estrutura que já estamos usando na versão atual do aplicativo:

      • id: campo de chave primária.
      • name: nome do lugar.
      • visited: se este lugar já foi visitado ou não.

      O compilador de esquemas do Laravel expõe métodos para a criação, atualização e exclusão de tabelas em um banco de dados. A classe Blueprint define a estrutura da tabela e ela proporciona vários métodos para abstrair a definição de cada campo da tabela.

      O código gerado automaticamente define um campo de id primário chamado id. O método timestamps cria dois campos de datetime que são atualizados automaticamente pelas classes de banco de dados subjacentes, quando os dados são inseridos ou atualizados dentro dessa tabela. Além disso, precisaremos incluir um campo name e um visited.

      Nosso campo name será do tipo string e nosso campo visited será definido com o tipo boolean. Também vamos definir um valor padrão de 0 para o campo visited, de modo que se nenhum valor for transferido, significa que o lugar ainda não foi visitado. É assim que o método up se parecerá agora:

      database/migrations/2020_02_03_143622_create_places_table.php

      …
          public function up()
          {
              Schema::create('places', function (Blueprint $table) {
                  $table->bigIncrements('id');
                  $table->string('name', 100);
                  $table->boolean('visited')->default(0);
                  $table->timestamps();
              });
          }
      …
      

      Nota: você pode encontrar a lista completa dos tipos de coluna disponíveis na documentação do Laravel.

      Após incluir as duas linhas destacadas em seu próprio script de migration, salve e feche o arquivo.

      Agora, sua migration está pronta para ser executada através do artisan migrate. No entanto, isso criaria apenas uma tabela vazia; também precisamos conseguir inserir dados da amostra para o desenvolvimento e teste. No próximo passo, veremos como fazer isso usando os seeders de banco de dados.

      Passo 5 — Criando os Seeders de banco de dados

      Um seeder é uma classe especial utilizada para gerar e inserir dados de amostra (seeds) em um banco de dados. Essa é uma característica importante em ambientes de desenvolvimento, uma vez que permite que você recrie o aplicativo com um banco de dados novo, usando valores de amostra que, de qualquer forma você teria que inserir manualmente toda vez que o banco de dados fosse recriado.

      Agora, utilizaremos o comando artisan para gerar uma nova classe de seeders para nossa tabela de places chamada PlacesTableSeeder:

      • docker-compose exec app php artisan make:seeder PlacesTableSeeder

      O comando criará um novo arquivo chamado PlacesTableSeeder.php dentro do diretório database/seeds. Abra aquele arquivo usando seu editor de texto preferido:

      • nano database/seeds/PlacesTableSeeder.php

      É assim que o arquivo PlacesTableSeeder.php, gerado automaticamente, se parece:

      database/seeds/PlacesTableSeeder.php

      <?php
      
      use IlluminateDatabaseSeeder;
      
      class PlacesTableSeeder extends Seeder
      {
          /**
           * Run the database seeds.
           *
           * @return void
           */
          public function run()
          {
              //
          }
      }
      
      

      Nossa nova classe de seeder contém um método vazio chamado run. Esse método será chamado quando o comando db:seed do Artisan for executado.

      Precisamos editar o método run para incluir instruções para inserir dados de amostra no banco de dados. Vamos utilizar o compilador de consultas do Laravel para simplificar esse processo.

      O compilador de consultas do Laravel oferece uma interface fluente para as operações de banco de dados como a inserção, atualização e recuperação de dados. Ele também introduz proteções contra ataques de injeção de SQL. O compilador de consulta é exposto pela facade do DB – um proxy estático para as classes de banco de dados subjacentes no contêiner de serviço.

      Para começar, criaremos uma variável de classe estática para reter todos os locais das amostras que desejamos inserir no banco de dados como uma matriz. Isso nos permitirá usar um loop foreach para iterar em todos os valores, inserindo cada um no banco de dados utilizando o compilador de consulta.

      Chamaremos essa variável de $places:

      database/seeds/PlacesTableSeeder.php

      <?php
      
      use IlluminateDatabaseSeeder;
      
      class PlacesTableSeeder extends Seeder
      {
          static $places = [
              'Berlin',
              'Budapest',
              'Cincinnati',
              'Denver',
              'Helsinki',
              'Lisbon',
              'Moscow',
              'Nairobi',
              'Oslo',
              'Rio',
              'Tokyo'
          ];

      Em seguida, precisaremos incluir uma instrução use no topo de nossa classe PlacesTableSeeder para facilitar a referência da facade DB em todo o código:

      database/seeds/PlacesTableSeeder.php

      <?php
      
      use IlluminateDatabaseSeeder;
      use IlluminateSupportFacadesDB;
      
      class PlacesTableSeeder extends Seeder
      …
      

      Agora, podemos iterar através dos valores da matriz $places, usando um loop foreach e inserir cada um deles em nossa tabela places com o compilador de consultas:

      database/seeds/PlacesTableSeeder.php

      …
          public function run()
          {
              foreach (self::$places as $place) {
                  DB::table('places')->insert([
                      'name' => $place,
                      'visited' => rand(0,1) == 1
                  ]);
              }
          }
      
      

      O loop foreach itera através de cada valor da matriz estática $places. Em cada iteração, usamos a facade DB para inserir uma nova linha na tabela places. Definimos o campo name para o nome do lugar que acabamos de obter da matriz $places e definimos o campo visited para um valor aleatório de 0 ou 1.

      É assim que a classe PlacesTableSeeder completa se parecerá após todas as atualizações:

      database/seeds/PlacesTableSeeder.php

      <?php
      
      use IlluminateDatabaseSeeder;
      use IlluminateSupportFacadesDB;
      
      class PlacesTableSeeder extends Seeder
      {
          static $places = [
              'Berlin',
              'Budapest',
              'Cincinnati',
              'Denver',
              'Helsinki',
              'Lisbon',
              'Moscow',
              'Nairobi',
              'Oslo',
              'Rio',
              'Tokyo'
          ];
      
          /**
           * Run the database seeds.
           *
           * @return void
           */
          public function run()
          {
              foreach (self::$places as $place) {
                  DB::table('places')->insert([
                      'name' => $place,
                      'visited' => rand(0,1) == 1
                  ]);
              }
          }
      }
      

      Salve e feche o arquivo quando terminar de fazer essas alterações.

      As classes do seeder não são carregadas automaticamente no aplicativo. Precisamos editar a classe principal, DatabaseSeeder, para incluir uma chamada para o seeder que acabamos de criar.

      Abra o arquivo database/seeds/DatabaseSeeder.php com o nano ou com o seu editor favorito:

      • nano database/seeds/DatabaseSeeder.php

      A classe DatabaseSeeder se parece com qualquer outro seeder: ela se estende a partir da classe Seeder e tem um método run. Atualizaremos esse método para incluir uma chamada para o PlacesTableSeeder.

      Atualize o método run atual, dentro da classe DatabaseSeeder, excluindo a linha comentada e substituindo-a pelo código destacado a seguir:

      database/seeds/DatabaseSeeder.php

      …
          public function run()
          {
              $this->call(PlacesTableSeeder::class);
          }
      ...
      

      É assim que a classe DatabaseSeeder completa se parecerá após a atualização:

      database/seeds/DatabaseSeeder.php

      <?php
      
      use IlluminateDatabaseSeeder;
      
      class DatabaseSeeder extends Seeder
      {
          /**
           * Seed the application's database.
           *
           * @return void
           */
          public function run()
          {
              $this->call(PlacesTableSeeder::class);
          }
      }
      
      
      

      Salve e feche o arquivo quando terminar de atualizar seu conteúdo.

      Agora, terminamos a configuração da migration e de um seeder para nossa tabela places. No próximo passo, veremos como executá-las.

      Passo 6 — Executando as migrations e os seeders do banco de dados

      Antes de prosseguir, precisamos garantir que seu aplicativo esteja em funcionamento. Vamos configurar a chave de criptografia do aplicativo e, depois, acessar o aplicativo a partir de um navegador para testar o servidor Web.

      Para gerar a chave de criptografia que o Laravel exige, utilize o comando artisan key:generate:

      • docker-compose exec app php artisan key:generate

      Assim que a chave tiver sido gerada, você poderá acessar o aplicativo, apontando seu navegador para o nome do host ou endereço IP do servidor na porta 8000:

      http://server_host_or_ip:8000
      

      Você verá uma página como esta:

      Erro do MySQL

      Isso significa que o aplicativo conseguiu conectar-se ao banco de dados, mas que não encontrou uma tabela chamada places. Vamos criar a tabela places agora, utilizando o comando do artisan migrate:

      • docker-compose exec app php artisan migrate

      Você obterá um resultado parecido com este:

      Output

      Migration table created successfully. Migrating: 2014_10_12_000000_create_users_table Migrated: 2014_10_12_000000_create_users_table (0.06 seconds) Migrating: 2014_10_12_100000_create_password_resets_table Migrated: 2014_10_12_100000_create_password_resets_table (0.06 seconds) Migrating: 2019_08_19_000000_create_failed_jobs_table Migrated: 2019_08_19_000000_create_failed_jobs_table (0.03 seconds) Migrating: 2020_02_10_144134_create_places_table Migrated: 2020_02_10_144134_create_places_table (0.03 seconds)

      Você verá que algumas outras migrations foram executadas junto com a migration create_places_table que configuramos. Essas migrations são geradas automaticamente quando o Laravel é instalado. Embora não estejamos usando essas tabelas adicionais agora, elas serão necessárias no futuro quando expandirmos o aplicativo para ele ter usuários registrados e trabalhos agendados. Por enquanto, deixe-as como estão.

      Neste ponto, nossa tabela ainda está vazia. Precisamos executar o comando db:seed para propagar o banco de dados com nossas amostras de locais:

      • docker-compose exec app php artisan db:seed

      Isso executará nosso seeder e irá inserir os valores da amostra que definimos dentro da nossa classe PlacesTableSeeder. Você verá um resultado semelhante a este:

      Output

      Seeding: PlacesTableSeeder Seeded: PlacesTableSeeder (0.06 seconds) Database seeding completed successfully.

      Agora, recarregue a página do aplicativo no seu navegador. Você verá uma página parecida com esta:

      Demo do aplicativo Laravel

      Sempre que precisar começar do zero, você poderá remover todas as tabelas de banco de dados com:

      • docker-compose exec app php artisan db:wipe

      Output

      Dropped all tables successfully.

      Para executar o aplicativo migrations e propagar as tabelas em um único comando, utilize:

      • docker-compose exec app php artisan migrate --seed

      Output

      Migration table created successfully. Migrating: 2014_10_12_000000_create_users_table Migrated: 2014_10_12_000000_create_users_table (0.06 seconds) Migrating: 2014_10_12_100000_create_password_resets_table Migrated: 2014_10_12_100000_create_password_resets_table (0.07 seconds) Migrating: 2019_08_19_000000_create_failed_jobs_table Migrated: 2019_08_19_000000_create_failed_jobs_table (0.03 seconds) Migrating: 2020_02_10_144134_create_places_table Migrated: 2020_02_10_144134_create_places_table (0.03 seconds) Seeding: PlacesTableSeeder Seeded: PlacesTableSeeder (0.06 seconds) Database seeding completed successfully.

      Se quiser reverter uma migration, você pode executar:

      • docker-compose exec app php artisan migrate:rollback

      Isso acionará o método down para cada classe de migration dentro da pasta migrations. Normalmente, ele removerá todas as tabelas que foram criadas através das classes de migration, deixando sozinha quaisquer outras tabelas que possam ter sido criadas manualmente. Você verá um resultado como este:

      Output

      Rolling back: 2020_02_10_144134_create_places_table Rolled back: 2020_02_10_144134_create_places_table (0.02 seconds) Rolling back: 2019_08_19_000000_create_failed_jobs_table Rolled back: 2019_08_19_000000_create_failed_jobs_table (0.02 seconds) Rolling back: 2014_10_12_100000_create_password_resets_table Rolled back: 2014_10_12_100000_create_password_resets_table (0.02 seconds) Rolling back: 2014_10_12_000000_create_users_table Rolled back: 2014_10_12_000000_create_users_table (0.02 seconds)

      O comando de reversão é especialmente útil quando estiver fazendo alterações nos modelos do aplicativo e um comando db:wipe não puder ser usado – por exemplo, caso vários sistemas dependerem de um mesmo banco de dados.

      Conclusão

      Neste guia, vimos como usar as migrations e os seeders de banco de dados para facilitar a configuração de bancos de dados para desenvolvimento e teste para um aplicativo Laravel 6.

      Como um passo seguinte, talvez você queira conferir a documentação do Laravel para obter mais informações sobre como usar o compilador de consultas e como usar os Modelos eloquentes para se concentrar ainda mais no esquema do banco de dados do seu aplicativo.



      Source link

      Como gerenciar e utilizar acionadores de banco de dados do MySQL no Ubuntu 18.04


      O autor selecionou a Apache Software Foundation para receber uma doação como parte do programa Write for DOnations.

      Introdução

      No MySQL, um acionador é um comando SQL definido por usuário que é chamado automaticamente durante uma operação INSERT, DELETE, ou UPDATE. O código de acionador está associado a uma tabela e é destruído assim que uma tabela for descartada. Você pode especificar um momento de ação do acionador e definir se ele será ativado antes ou após o evento de banco de dados definido.

      Os acionadores possuem várias vantagens. Por exemplo, você pode usá-los para gerar o valor de uma coluna derivada durante uma instrução de INSERT. Outro caso de uso é a aplicação da integridade referencial, onde é possível utilizar um acionador para salvar um registro em várias tabelas relacionadas. Outros benefícios dos acionadores incluem o registro de ações do usuário para auditar tabelas, bem como cópias de dados em tempo real em diferentes esquemas de bancos de dados para fins de redundância, com o objetivo de evitar um único ponto de falha.

      Você também pode utilizar acionadores para manter as regras de validação no nível do banco de dados. Isso ajuda no compartilhamento da fonte de dados em vários aplicativos, sem quebrar a lógica de negócios. Isso também reduz bastante os testes de viagem de ida e volta para o servidor de banco de dados, o que, portanto, melhora o tempo de resposta dos seus aplicativos. Como o servidor de banco de dados executa os acionadores, eles podem aproveitar-se de recursos de servidor melhorados, como RAM e CPU.

      Neste tutorial, você criará, utilizará e excluirá vários tipos de acionadores no seu banco de dados do MySQL.

      Pré-requisitos

      Antes de começar, certifique-se de ter o seguinte:

      Passo 1 — Criando um banco de dados de amostra

      Neste passo, você criará um banco de dados de clientes de amostra com várias tabelas para demonstrar como os acionadores do MySQL funcionam.

      Para entender melhor sobre as consultas do MySQL, leia nossa Introdução às consultas no MySQL.

      Primeiro, faça login no seu servidor do MySQL como raiz:

      Digite sua senha raiz do MySQL quando solicitado e clique em ENTER para continuar. Quando você vir o prompt do mysql>, execute o seguinte comando para criar um banco de dados test_db:

      Output

      Query OK, 1 row affected (0.00 sec)

      Em seguida, mude para o test_db com:

      Output

      Database changed

      Você começará criando uma tabela de customers. Essa tabela terá os registros dos clientes, incluindo a customer_id, o customer_name e o level. Haverá dois níveis de clientes: BASIC e VIP.

      • Create table customers(customer_id BIGINT PRIMARY KEY, customer_name VARCHAR(50), level VARCHAR(50) ) ENGINE=INNODB;

      Output

      Query OK, 0 rows affected (0.01 sec)

      Agora, adicione alguns registros à tabela customers. Para fazer isso, execute os comandos um a um:

      • Insert into customers (customer_id, customer_name, level )values('1','JOHN DOE','BASIC');
      • Insert into customers (customer_id, customer_name, level )values('2','MARY ROE','BASIC');
      • Insert into customers (customer_id, customer_name, level )values('3','JOHN DOE','VIP');

      Você verá o seguinte resultado após executar cada um dos comandos INSERT:

      Output

      Query OK, 1 row affected (0.01 sec)

      Para garantir que os registros de amostra foram inseridos com sucesso, execute o comando SELECT:

      Output

      +-------------+---------------+-------+ | customer_id | customer_name | level | +-------------+---------------+-------+ | 1 | JOHN DOE | BASIC | | 2 | MARY ROE | BASIC | | 3 | JOHN DOE | VIP | +-------------+---------------+-------+ 3 rows in set (0.00 sec)

      Você criará também outra tabela para reter informações relacionadas sobre a conta customers. A tabela terá os campos customer_id e status_notes.

      Execute o seguinte comando:

      • Create table customer_status(customer_id BIGINT PRIMARY KEY, status_notes VARCHAR(50)) ENGINE=INNODB;

      Em seguida, você criará uma tabela de sales (vendas). Esta tabela terá os dados de vendas relacionados a diferentes clientes através da coluna customer_id:

      • Create table sales(sales_id BIGINT PRIMARY KEY, customer_id BIGINT, sales_amount DOUBLE ) ENGINE=INNODB;

      Output

      Query OK, 0 rows affected (0.01 sec)

      Você adicionará os dados da amostra aos dados de sales nos passos próximos, enquanto testa os acionadores. Em seguida, crie uma tabela audit_log para registrar as atualizações feitas para a tabela de sales quando você implementar o acionador AFTER UPDATE no Passo 5:

      • Create table audit_log(log_id BIGINT PRIMARY KEY AUTO_INCREMENT, sales_id BIGINT, previous_amount DOUBLE, new_amount DOUBLE, updated_by VARCHAR(50), updated_on DATETIME ) ENGINE=INNODB;

      Output

      Query OK, 0 rows affected (0.02 sec)

      Com o banco de dados test_db e as quatro tabelas em funcionamento, siga em frente para trabalhar com os vários acionadores do MySQL no seu banco de dados.

      Passo 2 — Criando um acionador antes de inserir

      Neste passo, você examinará a sintaxe de um acionador do MySQL, antes da aplicação dessa lógica para criar um acionador BEFORE INSERT, que valida o campo sales_amount quando os dados são inseridos na tabela de sales.

      A sintaxe geral para a criação de um acionador do MySQL é mostrada no exemplo a seguir:

      DELIMITER //
      CREATE TRIGGER [TRIGGER_NAME]
      [TRIGGER TIME] [TRIGGER EVENT]
      ON [TABLE]
      FOR EACH ROW
      [TRIGGER BODY]//
      DELIMITER ;
      

      A estrutura do acionador inclui:

      DELIMITER //: o delimitador padrão do MySQL é o ; — ele é necessário para modificá-lo para outra coisa, de modo a permitir que o MySQL trate as linhas seguintes como um comando até que ele atinja seu delimitador personalizado. Neste exemplo, o delimitador é alterado para // e, em seguida, o delimitador ; é redefinido no final.

      [TRIGGER_NAME]: um acionador deve ter um nome e é aqui que você inclui o valor.

      [TRIGGER TIME]: um acionador pode ser chamado durante diferentes intervalos de tempo. O MySQL permite que você defina se o acionador iniciará antes ou após uma operação de banco de dados.

      [TRIGGER EVENT]: os acionadores são chamados apenas por operações de INSERT, UPDATE e DELETE. Você pode utilizar qualquer valor aqui, dependendo do que quiser fazer.

      [TABLE]: qualquer acionador que você criar no seu banco de dados do MySQL deve estar associado a uma tabela.

      FOR EACH ROW: essa instrução diz ao MySQL para executar o código do acionador para cada linha que o acionador afeta.

      [TRIGGER BODY]​​​: o código que é executado quando o acionador é chamado tem o nome de trigger body. Pode ser uma única instrução do SQL ou vários comandos. Note que, se estiver executando várias instruções do SQL no corpo do acionador, você deve envolvê-las entre um bloco BEGIN... END.

      Nota: ao criar o corpo do acionador, você pode utilizar as palavras-chave OLD e NEW para acessar os valores de coluna antigos e novos inseridos durante uma operação INSERT, UPDATE e DELETE. Em um acionador de DELETE, apenas a palavra-chave OLD pode ser usada (que você usará no Passo 4).

      Agora, você criará seu primeiro acionador BEFORE INSERT. Este acionador estará associado à tabela de sales e será chamado antes de um registro ser inserido para validar o sales_amount. A função do acionador é a de verificar se o sales_amount que está sendo inserido no quadro de vendas é maior do que 10000 e de gerar um erro, caso isso seja verdadeiro.

      Certifique-se de estar logado no servidor do MySQL. Em seguida, digite os comandos do MySQL seguintes um de cada vez:

      • DELIMITER //
      • CREATE TRIGGER validate_sales_amount
      • BEFORE INSERT
      • ON sales
      • FOR EACH ROW
      • IF NEW.sales_amount>10000 THEN
      • SIGNAL SQLSTATE '45000'
      • SET MESSAGE_TEXT = 'Sale has exceeded the allowed amount of 10000.';
      • END IF//
      • DELIMITER ;

      Você está usando a instrução IF... THEN... END IF para avaliar se a quantidade que está sendo fornecida durante a instrução INSERT está dentro da sua faixa. O acionador consegue extrair o novo valor de sales_amount que está sendo fornecido, usando a palavra-chave NEW.

      Para gerar uma mensagem de erro genérica, use as linhas seguintes para informar o usuário sobre o erro:

      SIGNAL SQLSTATE '45000'
      SET MESSAGE_TEXT = 'Sale has exceeded the allowed amount of 10000.';
      

      Em seguida, insira um registro com um sales_amount de 11000 para a tabela de sales para verificar se o acionador interromperá a operação:

      • Insert into sales(sales_id, customer_id, sales_amount) values('1','1','11000');

      Output

      ERROR 1644 (45000): Sale has exceeded the allowed amount of 10000.

      Este erro mostra que o código do acionador está funcionando como esperado.

      Agora, teste um novo registro com um valor de 7500 para verificar se o comando será bem-sucedido:

      • Insert into sales(sales_id, customer_id, sales_amount) values('1','1','7500');

      Como o valor está dentro da faixa recomendada, você verá o seguinte resultado:

      Output

      Query OK, 1 row affected (0.01 sec)

      Para confirmar que os dados foram inseridos, execute o seguinte comando:

      O resultado confirma que os dados estão na tabela:

      Output

      +----------+-------------+--------------+ | sales_id | customer_id | sales_amount | +----------+-------------+--------------+ | 1 | 1 | 7500 | +----------+-------------+--------------+ 1 row in set (0.00 sec)

      Neste passo, você testou os acionadores para validar dados antes da inserção deles em um banco de dados.

      Em seguida, você trabalhará com o acionador AFTER INSERT para salvar informações relacionadas em tabelas diferentes.

      Passo 3 — Criando um acionador após inserir

      Os acionadores AFTER INSERT são executados quando os registros são inseridos com sucesso em uma tabela. Essa funcionalidade pode ser usada para executar outras lógicas relacionados a negócios de maneira automática. Por exemplo, em um aplicativo bancário, um acionador AFTER INSERT pode fechar uma conta de empréstimo quando um cliente terminar de pagar o empréstimo. O acionador pode monitorar todos os pagamentos inseridos em uma tabela de transação e fechar o empréstimo automaticamente assim que o saldo do empréstimo se tornar zero.

      Neste passo, você trabalhará com sua tabela de customer_status usando um acionador AFTER INSERT para digitar registros de clientes relacionados.

      Para criar o acionador AFTER INSERT, digite os comandos a seguir:

      • DELIMITER //
      • CREATE TRIGGER customer_status_records
      • AFTER INSERT
      • ON customers
      • FOR EACH ROW
      • Insert into customer_status(customer_id, status_notes) VALUES(NEW.customer_id, 'ACCOUNT OPENED SUCCESSFULLY')//
      • DELIMITER ;

      Output

      Query OK, 0 rows affected (0.00 sec)

      Aqui, você instruirá o MySQL para salvar outro registro para a tabela customer_status assim que um novo registro de cliente for inserido na tabela customers.

      Agora, insira um novo registro na tabela customers para confirmar que seu código do acionador será chamado:

      • Insert into customers (customer_id, customer_name, level )values('4','DAVID DOE','VIP');

      Output

      Query OK, 1 row affected (0.01 sec)

      Como o registro foi inserido com sucesso, verifique se um novo registro de status foi inserido na tabela customer_status:

      • Select * from customer_status;

      Output

      +-------------+-----------------------------+ | customer_id | status_notes | +-------------+-----------------------------+ | 4 | ACCOUNT OPENED SUCCESSFULLY | +-------------+-----------------------------+ 1 row in set (0.00 sec)

      O resultado confirma que o acionador foi executado com sucesso.

      O acionador AFTER INSERT é útil no monitoramento do ciclo de vida de um cliente. Em um ambiente de produção, as contas dos clientes podem ser submetidas a diferentes etapas, como a abertura da conta, a suspensão da conta e o fechamento da conta.

      Nos passos a seguir, você trabalhará com os acionadores de UPDATE.

      Passo 4 — Criando um acionador antes de atualizar

      Um acionador BEFORE UPDATE é semelhante ao acionador BEFORE INSERT—a diferença é o momento onde eles são chamados. Você pode utilizar o acionador BEFORE UPDATE para verificar uma lógica de negócios antes de um registro ser atualizado. Para testar isso, você utilizará a tabela customers, na qual você já inseriu alguns dados.

      Você tem dois níveis para seus clientes no banco de dados. Neste exemplo, assim que uma conta de cliente for atualizada para o nível VIP, a conta não poderá ser rebaixada para o nível BASIC. Para aplicar essa regra, você criará um acionador BEFORE UPDATE que executará antes da instrução UPDATE, como mostrado a seguir. Se um usuário de banco de dados tentar rebaixar um cliente do nível VIP para o nível BASIC, será acionada uma exceção definida pelo usuário.

      Digite os comandos SQL seguintes um de cada vez para criar o acionador BEFORE UPDATE:

      • DELIMITER //
      • CREATE TRIGGER validate_customer_level
      • BEFORE UPDATE
      • ON customers
      • FOR EACH ROW
      • IF OLD.level='VIP' THEN
      • SIGNAL SQLSTATE '45000'
      • SET MESSAGE_TEXT = 'A VIP customer can not be downgraded.';
      • END IF //
      • DELIMITER ;

      Use a palavra-chave OLD para capturar o nível que o usuário está fornecendo ao executar o comando UPDATE. Novamente, use a instrução IF... THEN… END IF para sinalizar uma instrução de erro genérica para o usuário.

      Em seguida, execute o comando SQL a seguir, que tenta rebaixar uma conta de cliente associada ao customer_id de 3:

      • Update customers set level='BASIC' where customer_id='3';

      Você verá o seguinte resultado, fornecendo o SET MESSAGE_TEXT:

      Output

      ERROR 1644 (45000): A VIP customer can not be downgraded.

      Se executar o mesmo comando para um cliente de nível BASIC e tentar atualizar a conta para o nível VIP, o comando será executado com sucesso:

      • Update customers set level='VIP' where customer_id='1';

      Output

      Rows matched: 1 Changed: 1 Warnings: 0

      Você usou o acionador BEFORE UPDATE para aplicar uma regra de negócios. Agora, siga em frente para usar um acionador AFTER UPDATE para log de auditoria.

      Passo 5 — Criando um acionador após atualizar

      Um acionador AFTER UPDATE é chamado assim que um registro de banco de dados for atualizado com sucesso. Este comportamento torna o acionador adequado para o log de auditoria. Em um ambiente de muitos usuários, o administrador pode querer exibir um histórico de usuários atualizando os registros em uma tabela específica para fins de auditoria.

      Você criará um acionador que registra a atividade de atualização da tabela sales. Nossa tabela audit_log terá as informações sobre os usuários do MySQL atualizando a tabela de sales, a date da atualização e os valores old e new da sales_amount.

      Para criar o acionador, execute os comandos SQL seguintes:

      • DELIMITER //
      • CREATE TRIGGER log_sales_updates
      • AFTER UPDATE
      • ON sales
      • FOR EACH ROW
      • Insert into audit_log(sales_id, previous_amount, new_amount, updated_by, updated_on) VALUES (NEW.sales_id,OLD.sales_amount, NEW.sales_amount,(SELECT USER()), NOW() )//
      • DELIMITER ;

      Insira um novo registro para a tabela audit_log. Use a palavra-chave NEW para recuperar o valor do sales_id e o novo sales_amount. Além disso, use a palavra-chave OLD para recuperar o sales_amount anterior, já que deseja registrar ambos os montantes para fins de auditoria.

      O comando SELECT USER() recupera o usuário atual que executa a operação e a instrução NOW() recupera o valor da data e hora atual do servidor MySQL.

      Agora, caso um usuário tente atualizar o valor de qualquer registro na tabela sales, o acionador log_sales_updates inserirá um novo registro para a tabela audit_log.

      Vamos criar um novo registro de vendas com uma sales_id aleatória de 5 e tentar atualizá-lo. Primeiro, insira o registro de vendas com:

      • Insert into sales(sales_id, customer_id, sales_amount) values('5', '2','8000');

      Output

      Query OK, 1 row affected (0.00 sec)

      Em seguida, atualize o registro:

      • Update sales set sales_amount='9000' where sales_id='5';

      Você verá o seguinte resultado:

      Output

      Rows matched: 1 Changed: 1 Warnings: 0

      Agora, execute o comando a seguir para verificar se o acionador AFTER UPDATE conseguiu registrar um novo registro na tabela audit_log:

      O acionador registrou a atualização Seu resultado mostra o sales_amount e o new amount previamente registrados com o usuário que atualizou os registros:

      Output

      +--------+----------+-----------------+------------+----------------+---------------------+ | log_id | sales_id | previous_amount | new_amount | updated_by | updated_on | +--------+----------+-----------------+------------+----------------+---------------------+ | 1 | 5 | 8000 | 9000 | root@localhost | 2019-11-07 09:28:36 | +--------+----------+-----------------+------------+----------------+---------------------+ 1 row in set (0.00 sec)

      Você também tem a data e hora que a atualização foi realizada, que são valiosos para fins de auditoria.

      Em seguida, você usará o acionador DELETE para aplicar a integridade da referenciação no nível de banco de dados.

      Passo 6 — Criando um acionador antes de excluir

      Acionadores do BEFORE DELETE são chamados antes que uma instrução DELETE seja executada em uma tabela. Normalmente, esses tipos de acionadores são usados para aplicar a integridade referencial em diferentes tabelas relacionadas. Por exemplo, cada registro da tabela de sales se relaciona a um customer_id da tabela customers. Se um usuário excluísse um registro da tabela customers que tem um registro relacionado na tabela sales, você não teria como saber qual era o cliente associado àquele registro.

      Para evitar isso, é possível criar um acionador BEFORE DELETE para aplicar sua lógica. Execute os comandos SQL a seguir, um de cada vez:

      • DELIMITER //
      • CREATE TRIGGER validate_related_records
      • BEFORE DELETE
      • ON customers
      • FOR EACH ROW
      • IF OLD.customer_id in (select customer_id from sales) THEN
      • SIGNAL SQLSTATE '45000'
      • SET MESSAGE_TEXT = 'The customer has a related sales record.';
      • END IF//
      • DELIMITER ;

      Agora, tente excluir um cliente que tenha um registro de vendas relacionado a ele:

      • Delete from customers where customer_id='2';

      Como resultado, você verá a seguinte saída:

      Output

      ERROR 1644 (45000): The customer has a related sales record.

      O acionador BEFORE DELETE pode evitar a exclusão acidental de informações relacionadas em um banco de dados.

      No entanto, em algumas situações, você pode querer excluir todos os registros associados a um registro em específico de diferentes tabelas relacionadas. Nesta situação, você usaria o acionador AFTER DELETE, que será testado no próximo passo.

      Passo 7 — Criando um acionador após excluir

      Os acionadores AFTER DELETE são ativados assim que um registro tenha sido excluído com sucesso. Um exemplo de como se pode utilizar um acionador AFTER DELETE é uma situação em que o nível de desconto que um determinado cliente recebe é determinado pelo número de vendas realizadas durante um período definido. Se alguns dos registros do cliente forem excluídos da tabela de sales, o nível de desconto de cliente terá que ser rebaixado.

      Outro uso do acionador AFTER DELETE é o de excluir as informações relacionadas de outra tabela assim que um registro de uma tabela base for excluído. Por exemplo, você definirá um acionador que exclui o registro de clientes se os registros de vendas com o customer_id relacionado forem excluídos da tabela de sales. Execute o comando a seguir para criar seu acionador:

      • DELIMITER //
      • CREATE TRIGGER delete_related_info
      • AFTER DELETE
      • ON sales
      • FOR EACH ROW
      • Delete from customers where customer_id=OLD.customer_id;//
      • DELIMITER ;

      Em seguida, execute o seguinte comando para excluir todos os registros de vendas associados a um customer_id de 2:

      • Delete from sales where customer_id='2';

      Output

      Query OK, 1 row affected (0.00 sec)

      Agora, verifique se há registros para o cliente na tabela de sales:

      • Select * from customers where customer_id='2';

      Você receberá um resultado em um Empty Set, já que o registro de cliente associado ao customer_id de 2 foi excluído pelo acionador:

      Output

      Empty set (0.00 sec)

      Agora, você usou cada uma das diferentes formas de acionadores para realizar funções específicas. Em seguida, você verá como remover um acionador do banco de dados caso não precise mais dele.

      Passo 8 — Excluindo acionadores

      De maneira similar a qualquer outro objeto, você pode excluir acionadores utilizando o comando DROP. A seguir temos a sintaxe para excluir um acionador:

      Drop trigger [TRIGGER NAME];
      

      Por exemplo, para excluir o último acionador AFTER DELETE que você criou, execute o comando a seguir:

      • Drop trigger delete_related_info;

      Output

      Query OK, 0 rows affected (0.00 sec)

      A necessidade de excluir acionadores surge quando você quiser recriar a estrutura deles. Em tal caso, você pode remover o acionador e redefinir um novo com os diferentes comandos de acionador.

      Conclusão

      Neste tutorial, você criou, utilizou e excluiu diferentes tipos de acionadores de um banco de dados do MySQL. Utilizando um exemplo de banco de dados relacionados a clientes, você implementou acionadores para diferentes casos de uso, como validação de dados, aplicação de lógica de negócios, log de auditoria e aplicação da integridade referencial.

      Para obter mais informações sobre como utilizar seu banco de dados do MySQL, confira o seguinte:



      Source link

      Como Migrar Dados do Redis para um Banco de Dados Gerenciado na DigitalOcean


      Introdução

      Existem vários métodos que você pode usar para migrar dados de uma instância Redis para outra, tais como a replicação ou o snapshotting. No entanto, as migrações podem ficar mais complicadas quando você está movendo dados para uma instância Redis gerenciada por um provedor de nuvem, uma vez que os bancos de dados gerenciados muitas vezes limitam o controle que você tem sobre a configuração dos mesmos.

      Este tutorial descreve um método que você pode usar para migrar dados para uma instância do Redis gerenciada pela DigitalOcean. O método usa o comando interno migrate do Redis para transmitir dados com segurança por um túnel TLS configurado com o stunnel. Este guia também abordará algumas outras estratégias de migração comumente usadas, e por que elas são problemáticas ao migrar para um Banco de dados gerenciado na DigitalOcean.

      Pré-requisitos

      Para concluir este tutorial, você precisará de:

      Nota: Para ajudar a manter as coisas claras, este guia fará referência à instância Redis hospedada no seu servidor Ubuntu como a “origem”. Da mesma forma, ele se referirá à instância gerenciada pela DigitalOcean como o “destino” ou o “Banco de Dados Gerenciado”.

      Coisas a Considerar ao Migrar Dados do Redis para um Banco de Dados Gerenciado

      Existem vários métodos que você pode empregar para migrar dados de uma instância Redis para outra. No entanto, algumas dessas abordagens apresentam problemas ao migrar dados para uma instância Redis gerenciada pela DigitalOcean.

      Por exemplo, você pode usar a replicação para transformar sua instância Redis de destino em uma cópia exata da origem. Para fazer isso, você se conectaria ao servidor Redis de destino e executaria o comando replicaof com a seguinte sintaxe:

      • replicaof ip_ou_hostname_da_origem porta_da_origem

      Isso fará com que a instância de destino replique todos os dados mantidos na origem sem destruir nenhum dado que estava armazenado anteriormente nela. Depois disso, você promoveria a réplica de volta a ser uma instância primária com o seguinte comando:

      No entanto, as instâncias Redis gerenciadas pela DigitalOcean são configuradas para se tornarem somente réplicas de leitura. Se você tiver clientes gravando dados no banco de dados de origem, você não poderá configurá-los para gravar na instância gerenciada, pois ela está replicando dados. Isso significa que você perderia todos os dados enviados pelos clientes após promover a instância gerenciada como uma réplica e antes de configurá-los para começar a gravar dados nela, tornando a replicação uma solução de migração ineficiente.

      Outro método para migrar dados do Redis é tirar um snapshot ou instantâneo dos dados mantidos em sua instância de origem com um dos comandos save ou bgsave do Redis. Ambos os comandos exportam o snapshot para um arquivo que termina em .rdb, que você então transfere para o servidor de destino. Depois disso, você reiniciaria o serviço Redis para que ele possa carregar os dados.

      No entanto, muitos provedores de bancos de dados gerenciados — incluindo a DigitalOcean — não permitem acessar o sistema de arquivos subjacente do servidor de banco de dados gerenciado. Isso significa que não há como fazer upload do arquivo de snapshot ou fazer as alterações necessárias no arquivo de configuração do banco de dados de destino para permitir que os Redis importe os dados.

      Como a configuração dos bancos de dados gerenciados da DigitalOcean limita a eficácia tanto da replicação e quanto do snapshotting como meio de migração de dados, este tutorial utilizará o comando migrate do Redis para mover dados da origem para o destino. O comando migrate é projetado para mover apenas uma chave de cada vez, mas vamos usar alguns truques de linha de comando para mover um banco de dados Redis inteiro com um único comando.

      Este passo opcional envolve o carregamento da instância Redis de origem com alguns dados de amostra para que você possa experimentar a migração de dados para o banco de dados Redis gerenciado. Se você já possui dados que deseja migrar para sua instância de destino, você pode avançar para o Passo 2.

      Para começar, execute o seguinte comando para acessar o seu servidor Redis:

      Se você configurou seu servidor Redis para exigir autenticação por senha, execute o comando auth seguido da sua senha Redis:

      Em seguida, execute os seguintes comandos. Isso criará um número de chaves contendo algumas strings, um hash, uma lista e um set:

      • mset string1 "Redis" string2 "is" string3 "fun!"
      • hmset hash1 field1 "Redis" field2 "is" field3 "fast!"
      • rpush list1 "Redis" "is" "feature-rich!"
      • sadd set1 "Redis" "is" "free!"

      Além disso, execute os seguintes comandos expire para fornecer um tempo limite para algumas dessas chaves. Isso as tornará voláteis, o que significa que o Redis as excluirá após o período especificado, 7500 segundos:

      • expire string2 7500
      • expire hash1 7500
      • expire set1 7500

      Com isso, você tem alguns dados de exemplo que podem ser exportados para sua instância Redis de destino. Você pode manter o prompt do redis-cli aberto por enquanto, pois executaremos mais alguns comandos a partir dele no próximo passo para fazer backup desses dados.

      Passo 2 — Fazendo Backup dos Seus Dados

      Anteriormente, discutimos o uso do comando bgsave do Redis para tirar uma snapshot de um banco de dados Redis e migrá-lo para outra instância. Embora não utilizemos o bgsave como meio de migrar os dados do Redis, vamos usá-lo aqui para fazer backup dos dados, caso encontremos um erro durante o processo de migração.

      Se você ainda não o tiver aberto, comece abrindo a interface de linha de comandos do Redis:

      Além disso, se você configurou o seu servidor Redis para exigir autenticação por senha, execute o comando auth seguido da sua senha Redis:

      Em seguida, execute o comando bgsave. Isso criará um snapshot do seu data set atual e o exportará para um arquivo de dump cujo nome termina em .rdb:

      Nota: Conforme mencionado na seção anterior Coisas a Considerar, você pode tirar um snapshot do seu banco de dados Redis com os comandos save ou bgsave. A razão pela qual usamos o comando bgsave aqui é que o comando save é executado de forma síncrona, o que significa que ele bloqueará quaisquer outros clientes conectados ao banco de dados. Por isto, a documentação do comando save recomenda que esse comando quase nunca seja executado em um ambiente de produção.

      Em vez disso, ela sugere o uso do comando bgsave, que executa de forma assíncrona. Isso fará com que o Redis faça um fork do banco de dados em dois processos: o processo pai continuará a servir os clientes enquanto o filho salva o banco de dados antes de sair:

      Observe que se os clientes adicionarem ou modificarem dados enquanto a operação bgsave estiver em execução ou após a conclusão, essas alterações não serão capturadas no snapshot.

      Depois disso, você pode fechar a conexão com sua instância Redis executando o comando exit:

      Se você precisar no futuro, você poderá encontrar este arquivo de dump no seu diretório de trabalho da instalação do Redis. Se você não tiver certeza de qual diretório é esse, pode verificar abrindo seu arquivo de configuração Redis com o seu editor de texto preferido. Aqui, usaremos o nano:

      • sudo nano /etc/redis/redis.conf

      Navegue até a linha que começa com dbfilename. Por padrão, ele se apresentará assim:

      /etc/redis/redis.conf

      . . .
      # The filename where to dump the DB
      dbfilename dump.rdb
      . . .
      

      Esta diretiva define o arquivo para o qual o Redis exportará snapshots. A próxima linha (após qualquer comentário) ficará assim:

      /etc/redis/redis.conf

      . . .
      dir /var/lib/redis
      . . .
      

      A diretiva dir define o diretório de trabalho do Redis onde os snapshots são armazenados. Por padrão, isso é definido como /var/lib/redis, como mostrado neste exemplo.

      Feche o arquivo redis.conf. Supondo que você não tenha alterado o arquivo, você pode fazer isso pressionando CTRL+X.

      Em seguida, liste o conteúdo do seu diretório de trabalho Redis para confirmar que ele está mantendo o arquivo de dump de dados exportado:

      Se o arquivo de dump foi exportado corretamente, você o verá na saída deste comando:

      Output

      dump.rdb

      Depois de confirmar que você fez backup dos seus dados com êxito, você pode iniciar o processo de migração para o seu Banco de Dados Gerenciado.

      Passo 3 — Migrando os Dados

      Lembre-se de que este guia usa o comando interno migrate do Redis para mover as chaves uma a uma do banco de dados de origem para o destino. No entanto, ao contrário dos passos anteriores deste tutorial, não executaremos este comando no prompt redis-cli. Em vez disso, vamos executá-lo diretamente no prompt bash do servidor. Isso nos permitirá usar alguns truques do bash para migrar todas as chaves no banco de dados de origem com um comando.

      Nota: Se você tiver clientes gravando dados na sua instância Redis de origem, agora seria um bom momento para configurá-los para também gravar dados no seu Banco de Dados Gerenciado. Dessa forma, você pode migrar os dados existentes da origem para o seu destino sem perder nenhuma gravação que ocorra após a migração.

      Além disso, esteja ciente de que este comando de migração não substituirá nenhuma chave existente no banco de dados de destino, a menos que uma das chaves existentes tenha o mesmo nome da chave que você está migrando.

      A migração ocorrerá após a execução do seguinte comando. Antes de executá-lo, porém, vamos dividi-lo parte por parte:

      • redis-cli -n banco_de_dados_de_origem -a senha_da_origem scan 0 | while read key; do redis-cli -n banco_de_dados_de_origem -a senha_da_origem MIGRATE localhost 8000 "$key" banco_de_dados_de_destino 1000 COPY AUTH senha_do_redis_gerenciado; done

      Vamos analisar cada parte deste comando separadamente:

      • redis-cli -n banco_de_dados_de_origem -a senha_da_origem scan 0 . . .

      A primeira parte do comando, redis-cli, abre uma conexão com o servidor Redis local. A flag -n especifica a qual dos bancos de dados lógicos do Redis se conectar. O Redis possui 16 bancos de dados prontos para uso (com o primeiro sendo numerado como 0, o segundo numerado como 1 e assim por diante), portanto, banco_de_dados_de_origem pode ser qualquer número entre 0 e 15. Se sua instância de origem mantém apenas dados no banco de dados padrão (numerado como 0), você não precisará incluir a flag -n ou especificar um número de banco de dados.

      A seguir, vem a flag -a e a senha da instância de origem, que juntos autenticam a conexão. Se sua instância de origem não exigir autenticação por senha, você não precisará incluir a flag -a.

      Em seguida, ele executa o comando scan do Redis, que itera sobre as chaves mantidas no data set e as retorna como uma lista. O scan requer ser seguido de um cursor — a iteração começa quando o cursor está definido como 0, e termina quando o servidor retorna um cursor 0. Portanto, seguimos o scan com um cursor 0 para iterar sobre todas as chaves do conjunto.

      • . . . | while read key; do . . .

      A próxima parte do comando começa com uma barra vertical (|). Nos sistemas tipo Unix, as barras verticais são conhecidas como pipes e são usadas para direcionar a saída de um processo para a entrada de outro.

      A seguir, é iniciado o loop while. No bash, assim como na maioria das linguagens de programação, um loop while é uma declaração de fluxo de controle que permite repetir um determinado processo, código ou comando, enquanto uma certa condição permanecer verdadeira.

      A condição neste caso é o subcomando read key, que lê a entrada que foi canalizada e a atribui à variável key. O ponto-e-vírgula (;) significa o final da declaração condicional do loop while, e o do a seguir precede a ação que será repetida enquanto a expressão while permanecer verdadeira. Toda vez que a instrução do for concluída, a instrução condicional lerá a próxima linha canalizada a partir do comando scan e atribuirá essa entrada à variável key.

      Essencialmente, esta seção diz “enquanto houver saída do comando scan para ser lida, execute a seguinte ação”.

      • . . . redis-cli -n banco_de_dados_de_origem -a senha_da_origem migrate localhost 8000 "$key" . . .

      Esta seção do comando é a que executa a migração real. Após outra chamada do redis-cli, ela especifica mais uma vez o número do banco de dados de origem com a flag -n e autentica com a flag -a. Você precisa incluí-las novamente, porque essa chamada redis-cli é distinta daquela no início do comando. Mais uma vez, porém, você não precisa incluir a flag -n ou o número do banco de dados se a instância Redis de origem mantém apenas dados no banco de dados padrão 0, e você não precisa incluir a flag -a se ela não requer autenticação por senha.

      A seguir, está o comando migrate. Sempre que você usar o comando migrate, deverá segui-lo com o nome do host ou endereço IP do banco de dados de destino e o número da porta. Aqui, seguimos a convenção estabelecida no tutorial de pré-requisito do stunnel e apontamos o comando migrate para localhost na porta 8000.

      $key é a variável definida na primeira parte do loop while e representa as chaves de cada linha da saída do comando scan.

      • . . . banco_de_dados_de_destino 1000 copy auth senha_do_redis_gerenciado; done

      Esta seção é uma continuação do comando migrate. Ela começa com banco_de_dados_de_destino, que representa o banco de dados lógico na instância de destino em que você deseja armazenar os dados. Novamente, este pode ser qualquer número entre 0 e 15.

      Em seguida está um número que representa um tempo limite. Esse tempo limite é a quantidade máxima de tempo de comunicação inativa entre as duas máquinas. Observe que este não é um limite de tempo para a operação, apenas que a operação deve sempre fazer algum nível de progresso dentro do tempo limite definido. Tanto o número do banco de dados quanto os argumentos de tempo limite são necessários para cada comando migrate.

      Após o tempo limite está a flag opcional copy. Por padrão, o migrate excluirá cada chave do banco de dados de origem depois de transferi-la para o destino; Ao incluir esta opção, você está instruindo o comando migrate a meramente copiar as chaves para que elas persistam na origem.

      Após o copy, aparece a flag auth, seguido da senha do seu Banco de Dados Redis Gerenciado. Isso não é necessário se você estiver migrando dados para uma instância que não requer autenticação, mas é necessário quando você estiver migrando dados para um banco gerenciado pela DigitalOcean.

      A seguir, outro ponto-e-vírgula, indicando o final da ação a ser executada enquanto a condição while for verdadeira. Finalmente, o comando fecha com done, indicando o fim do loop. O comando verifica a condição na instrução while e repete a ação na instrução do até que ela não seja mais verdadeira.

      Em conjunto, este comando executa os seguintes passos:

      • Examina um banco de dados na instância Redis de origem e retorna todas as chaves nela contidas
      • Passa cada linha da saída do comando scan para um loop while
      • Lê a primeira linha e atribui seu conteúdo à variável key
      • Migra qualquer chave no banco de dados de origem que corresponda à variável key para um banco de dados na instância Redis na outra extremidade do túnel TLS mantida em localhost na porta 8000
      • Volta e lê a próxima linha, e repete o processo até que não haja mais chaves para ler

      Agora que examinamos cada parte do comando de migração, você pode prosseguir e executá-lo.

      Se sua instância de origem tiver apenas dados no banco de dados 0 padrão, você não precisa incluir quaisquer das flags -n ou seus argumentos. Se, no entanto, você estiver migrando dados de qualquer banco de dados que não seja o 0 na sua instância de origem, você deve incluir as flags -n e alterar as duas ocorrências de banco_de_dados_de_origem para alinhar com o banco de dados que você deseja migrar.

      Se o seu banco de dados de origem exigir autenticação por senha, certifique-se de alterar senha_da_origem para a senha real da instância do Redis. Caso contrário, certifique-se de remover ambas as ocorrências de -a senha_da_origem do comando. Além disso, altere senha_do_redis_gerenciado para a senha do seu Banco de Dados Gerenciado e certifique-se de alterar banco_de_dados_de_destino para o número do banco de dados lógico na sua instância de destino em que você deseja gravar os dados:

      Nota: Se você não tiver a senha do seu banco de dados Redis gerenciado em mãos, poderá encontrá-la navegando primeiramente para o Painel de controle da DigitalOcean. A partir daí, clique em Databases no menu da barra lateral esquerda e depois clique no nome da instância Redis para a qual você deseja migrar os dados. Role para baixo até a seção Connection Details, onde você encontrará um campo chamado password. Clique no botão show para revelar a senha e copie e cole-a no comando de migração — substituindo senha_do_redis_gerenciado – para autenticar.

      • redis-cli -n banco_de_dados_de_origem -a senha_da_origem scan 0 | while read key; do redis-cli -n banco_de_dados_de_origem -a senha_da_origem MIGRATE localhost 8000 "$key" banco_de_dados_de_destino 1000 COPY AUTH senha_do_redis_gerenciado; done

      Você verá uma saída semelhante à seguinte:

      Output

      NOKEY OK OK OK OK OK OK

      Nota: Observe a primeira linha da saída do comando que lê NOKEY. Para entender o que isso significa, execute a primeira parte do comando de migração sozinho:

      • redis-cli -n banco_de_dados_de_origem -a senha_da_origem scan 0

      Se você migrou os dados de amostra adicionados no Passo 2, a saída deste comando será parecida com esta:

      Output

      1) "0" 2) 1) "hash1" 2) "string3" 3) "list1" 4) "string1" 5) "string2" 6) "set1"

      O valor "0" mantido na primeira linha não é uma chave mantida no seu banco de dados Redis de origem, mas um cursor retornado pelo comando scan. Como não há chaves no servidor denominadas “0”, não há nada lá para o comando migrate enviar à sua instância de destino e ele retorna NOKEY.

      No entanto, o comando não falha e sai. Em vez disso, ele continua lendo e migrando as chaves encontradas nas próximas linhas da saída do comando scan.

      Para testar se a migração foi bem-sucedida, conecte-se ao seu Banco de Dados Redis Gerenciado:

      • redis-cli -h localhost -p 8000 -a senha_do_redis_gerenciado

      Se você migrou dados para qualquer banco de dados lógico que não o padrão, conecte-se a esse banco de dados com o comando select:

      • select banco_de_dados_de_destino

      Execute um comando scan para ver quais chaves são mantidas lá:

      Se você concluiu o Passo 2 deste tutorial e adicionou os dados de exemplo ao seu banco de dados de origem, você verá resultados como este:

      Output

      1) "0" 2) 1) "set1" 2) "string2" 3) "hash1" 4) "list1" 5) "string3" 6) "string1"

      Por fim, execute um comando ttl em qualquer chave que você configurou para expirar para confirmar que ela ainda é volátil:

      Output

      (integer) 3944

      Esta saída mostra que, embora você tenha migrado a chave para o seu Banco de Dados Gerenciado, ela ainda está configurada para expirar com base no comando expireat que você executou anteriormente.

      Depois de confirmar que todas as chaves do seu banco de dados Redis de origem foram exportadas para o destino com êxito, você pode fechar sua conexão com o Banco de Dados Gerenciado. Se você tiver clientes gravando dados na instância Redis de origem e já os configurou para enviar suas gravações para o destino, nesse momento você pode configurá-los para parar de enviar dados para a origem.

      Conclusão

      Ao concluir este tutorial, você transferiu os dados do seu repositório de dados Redis autogerenciado para uma instância Redis gerenciada pela DigitalOcean. O processo descrito neste guia pode não ser o ideal em todos os casos. Por exemplo, você teria que executar o comando de migração várias vezes (uma vez para cada banco de dados lógico que contém dados) se sua instância de origem estiver usando bancos de dados diferentes do padrão. No entanto, quando comparado a outros métodos, como replicação ou snapshotting, este é um processo bastante direto que funciona bem com a configuração de um Banco de Dados Gerenciado pela DigitalOcean.

      Agora que você está usando um Banco de Dados Redis Gerenciado pela DigitalOcean para armazenar seus dados, você pode medir seu desempenho executando alguns testes de benchmarking. Além disso, se você é novo no trabalho com o Redis, você pode conferir nossa série Como Gerenciar um Banco de Dados Redis.



      Source link