Escolhendo o banco de dados certo para o seu aplicativo Flutter

Tempo de leitura: 8 minutes

Não importa quem você seja ou o que faça, mais cedo ou mais tarde você precisará armazenar dados em seu aplicativo e recuperá-los posteriormente. Mas qual é o melhor banco de dados para Flutter?

Existem muitas opções disponíveis hoje quando se trata de bancos de dados em seu aplicativo. Eles normalmente se encaixam nessas três categorias:

  • Relacional – estes são os bancos de dados no sentido tradicional. Eles não apenas armazenam dados, mas também os relacionamentos entre os dados. SQLite é um exemplo de banco de dados relacional.

  • NoSQL – esses bancos de dados armazenam dados como documentos . Um esquema não é imposto como é o caso de um banco de dados relacional. Eles são extremamente rápidos e lidam muito bem com grandes pedaços de dados não estruturados. MongoDB é um exemplo de banco de dados NoSQL.

  • Armazenamento de dados personalizado – embora essa opção não seja tecnicamente um banco de dados, você não precisa usar as soluções acima. Você pode armazenar seus dados em um arquivo JSON e lidar com a serialização e desserialização por conta própria. Isso seria incrivelmente rápido , mas abriria você para alguns bugs estranhos se você não fosse um gênio da programação. 🤓

    Ao final deste artigo, você saberá:

  • O básico de como cada banco de dados funciona. 📰
  • Como configurar cada banco de dados. ⚙
  • Que bom caso de uso seria para cada banco de dados. 📳

Neste artigo, dividiremos nossos tipos de banco de dados de acordo com as três categorias mencionadas acima.

Então, vamos começar, mas primeiro, deixe-nos saber quantos projetos de aplicativos móveis você tem nos repositórios Git?

Nenhum                Um                  Dois

Relacional

Os bancos de dados relacionais existem há muito tempo (desde 1970, de acordo com uma rápida pesquisa no Google). Vejamos algumas das opções que você tem no Flutter para bancos de dados relacionais hoje.

SQflite

 

SQflite é uma implementação do SQLite para Flutter. Ele oferece controle total sobre seu banco de dados, consultas, relacionamentos, tudo o que você deseja.

Interagir com um banco de dados SQLite no Flutter se parece com isso ( dos documentos ):

 // Get a location using getDatabasesPath
  var databasesPath = await getDatabasesPath();
  String path = join(databasesPath, 'demo.db');

  // Delete the database
  await deleteDatabase(path);

  // open the database
  Database database = await openDatabase(path, version: 1,
    onCreate: (Database db, int version) async {
   // When creating the db, create the table
   await db.execute(
     'CREATE TABLE Test (id INTEGER PRIMARY KEY, name TEXT, value INTEGER, num REAL)');
  });

Inserting data follows the same age-old SQLite tenants

  // Insert some records in a transaction
  await database.transaction((txn) async {
   int id1 = await txn.rawInsert(
     'INSERT INTO Test(name, value, num) VALUES("some name", 1234, 456.789)');
   print('inserted1: $id1');
   int id2 = await txn.rawInsert(
     'INSERT INTO Test(name, value, num) VALUES(?, ?, ?)',
     ['another name', 12345678, 3.1416]);
   print('inserted2: $id2');
  });

E a consulta acontece assim:

// Get the records
List<Map> list = await database.rawQuery('SELECT * FROM Test');

Prós 👍

  • Controle total sobre o banco de dados.
  • Um banco de dados SQLite muito eficiente para seu aplicativo (desde que você tenha conhecimento SQLite pré-existente).
  • Facilmente lido por aplicativos de terceiros que podem abrir bancos de dados SQLite (para que você possa abrir o banco de dados em seu computador e ver como são os dados).

Contras 👎

  • Escrever todas as suas consultas à mão pode levar muito tempo.
  • Os dados retornados do banco de dados não são fortemente tipados desde o início.
  • É potencialmente difícil lidar com migrações no dispositivo (quando o esquema muda entre atualizações de versão, por exemplo).
  • Não tem suporte para web.

Caso de uso

O SQFlite é bom quando você precisa de dados relacionais, mas também de controle refinado sobre as consultas reais. Se você se sente à vontade para escrever suas próprias consultas e não se importa em escrever muitas consultas e o código para converter os resultados de e para suas classes, isso pode ser uma boa opção para você.

 

Abstrações SQLite

Usar diretamente o SQLite para gerenciar seu banco de dados de aplicativos pode ser bastante poderoso, mas também complicado. É por isso que existem tantas soluções que abstraem algumas das funcionalidades do SQLite em funcionalidades de uso mais fácil. Essas abstrações podem tornar um banco de dados SQLite mais fácil de usar, mantendo muitos dos benefícios do SQLite.

Floor e Drift são exemplos bastante populares dessa abordagem. Neste artigo, veremos o Drift, mas a abordagem que esses dois pacotes adotam na abstração do SQLite é bastante semelhante.

Atracar

Para usar o Drift, importamos o pacote Drift do flutter pub , mas também precisamos importar algo chamado moor_generator. Isso é usado por build_runnerpara gerar o código para usar o banco de dados.

Por que usamosbuild_runner ? build_runneré usado principalmente para gerar código para seus projetos Flutter. Antes de vir para o Flutter, raramente, ou nunca, tive que usar um utilitário de geração de código. A principal razão para isso é porque a maioria das outras linguagens que eu usei até este ponto (como C#) suportava reflection .

Simplificando, isso possibilita que a estrutura invoque dinamicamente partes do programa em tempo de execução. É bastante poderoso, mas normalmente pode ser bastante lento. Também afeta a vinculação do aplicativo produzido, pois com a reflexão, tecnicamente, todas as partes do seu aplicativo podem ser acessadas ou usadas.

Quando os pacotes usam a funcionalidade que normalmente era fornecida por reflexão, eles geralmente usam build_runnerpara gerar o código necessário antecipadamente. Isso resulta em execução de código mais rápida em tempo de execução e também resulta em melhor ‘tremedeira de árvore’ ou minimização do binário do aplicativo no momento da implantação.

Uma olhada na documentação de Introdução nos ajuda a entender como um banco de dados é criado.

import 'package:drift/drift.dart';

// assuming that your file is called filename.dart. This will give an error at
// first, but it's needed for drift to know about the generated code
part 'filename.g.dart';

// this will generate a table called "todos" for us. The rows of that table will
// be represented by a class called "Todo".
class Todos extends Table {
  IntColumn get id => integer().autoIncrement()();
  TextColumn get title => text().withLength(min: 6, max: 32)();
  TextColumn get content => text().named('body')();
  IntColumn get category => integer().nullable()();
}

// This will make drift generate a class called "Category" to represent a row in
// this table. By default, "Categorie" would have been used because it only
//strips away the trailing "s" in the table name.
@DataClassName('Category')
class Categories extends Table {
  IntColumn get id => integer().autoIncrement()();
  TextColumn get description => text()();
}

// this annotation tells drift to prepare a database class that uses both of the
// tables we just defined. We'll see how to use that database class in a moment.
@DriftDatabase(tables: [Todos, Categories])
class MyDatabase extends _$MyDatabase {
}

Drift cria programaticamente o esquema para suas tabelas dependendo de como você define seu conteúdo. No início deste exemplo de código, podemos ver a partinstrução. Quando executamos o build_runnercomando, moorgera o esquema com base no que definimos neste arquivo. Você também pode retornar ao SQL bruto a qualquer momento se precisar executar uma consulta específica ou se desejar um controle mais refinado.

Prós 👍

  • Resultados fortemente tipados!
  • Baseado em SQLite.
  • Você não precisa construir manualmente todas as consultas.
  • Muito do trabalho pesado é feito pela geração de código.
  • O banco de dados SQLite pode ser navegado com uma ampla variedade de ferramentas disponíveis hoje para verificar os dados durante o desenvolvimento.

Contras 👎

  • Pode ser complicado lidar com atualizações de esquema no dispositivo local.
  • O suporte da Web ainda está em pré-visualização.
  • Possui dependências específicas da plataforma (não escritas em Dart puro).

Caso de uso

Se você ainda precisa de dados relacionais, mas deseja escrever o mínimo de SQL possível (se estiver acostumado com o Entity Framework, por exemplo), isso pode ser uma boa opção para você.

NoSQL

Existem algumas opções quando se trata de bancos de dados NoSQL para Flutter também. Temos os pesos pesados ​​que existem há muito tempo, como o Firebase , bem como as soluções mais recentes, como o Hive . Existem muitas diferenças entre o Hive e o Firebase, mas talvez a principal diferença seja que um pode sincronizar com uma loja online (Firebase), enquanto o outro é mais adequado para armazenar localmente no dispositivo (Hive).

Firebase – armazenamento NoSQL online

O Firebase é um banco de dados tradicional de armazenamento de documentos. Você armazena dados em coleções que são como tabelas em um banco de dados tradicional. Essas coleções armazenam documentos . Documentos armazenam tipos de dados, como stringint, etc. Eles também podem armazenar um link para outro documento, portanto, mesmo que o Firebase não seja estritamente relacional, você ainda pode criar relacionamentos entre seus dados.

A configuração do Firebase é bastante complicada em comparação com outras opções no dispositivo, como Moor ou Hive, mas você obtém sincronização de dados entre clientes e o servidor . Isso significa que, se você tiver vários clientes com um aplicativo e todos eles estiverem interagindo com os mesmos dados, esses dados poderão ser mantidos em sincronia entre esses clientes. Além disso, essa configuração é muito bem abordada em um Google Codelab aqui . A única desvantagem dessa abordagem é que você não obtém dados fortemente tipados da mesma forma que obtém com Moor ou Hive. Você tem que lidar com isso sozinho.

Prós 👍

  • Sincroniza com o Firebase online quase em tempo real.
  • Ótimo suporte de ferramentas.
  • Fácil de navegar pelos dados on-line por meio do Firebase Console.

Contras 👎

  • A configuração do Firebase pode ser complicada se você ainda não a adicionou ao seu aplicativo.
  • Como o banco de dados está online, você precisa estar atento a muito mais do que um banco de dados estritamente no dispositivo (como permissões de acesso, por exemplo).
  • O suporte do Firebase para Flutter ainda não está pronto para produção.

Caso de uso

Se seus dados devem ser distribuídos entre muitos dispositivos e você deseja uma sincronização (relativamente) indolor entre esses dispositivos, essa pode ser uma boa solução para você.

Hive – armazenamento NoSQL offline

Hive é uma opção de armazenamento NoSQL extremamente rápida para desenvolvedores Flutter. Seu maior ponto de venda é que é completamente nativo do Dart. Isso significa que em qualquer lugar que o Dart vá, o Hive pode ir, pois não requer nenhuma implementação específica do dispositivo.

O Hive permite armazenar dados como um HiveObject, o que também permite algumas relações entre objetos. Ele armazena objetos em um box, mas você pode gerar TypeAdapters para eles.

Criar um boxé bastante simples:

var box = await Hive.openBox('testBox');

Ler e escrever é tão fácil quanto:

import 'package:hive/hive.dart';

void main() async {
 var box = await Hive.openBox('testBox');

 box.put('name', 'David');

 print('Name: ${box.get('name')}');
}

Onde o Hive realmente se destaca é na capacidade de gerar TypeAdapters (leia mais na documentação ). Isso traz uma tipagem forte para seus Boxes e permite que você armazene suas classes e também permite que você faça referência a objetos em outros Boxes.

A documentação mostra como criar um boxbaseado em uma classe com sua própria definição, como abaixo.

import 'package:hive/hive.dart';
part 'person.g.dart';
@HiveType()
class Person
{
@HiveField(0) String name;
@HiveField(1) int age;
@HiveField(2) List<Person> friends;
}

Como podemos ver aqui, essa classe contém um Listof Person, então o Hive pode fazer referência a uma lista de objetos.

Caso de uso

Se você está apenas atrás de um banco de dados simples para armazenar dados em seu dispositivo, e não quer a sincronização que o Firebase oferece e quer algo que funcione em qualquer lugar, o Hive é para você . É o banco de dados que uso em todos os meus aplicativos.

Fazendo o seu próprio

Se você não estiver apaixonado por nenhuma das opções acima, poderá rolar seu próprio banco de dados. Você conseguiria isso usando uma biblioteca como json_serializable, e armazenando os arquivos JSON no dispositivo para o aplicativo acessar.

Na minha opinião, isso seria um pouco como construir seu próprio carro do zero. Claro, você pode fazê-lo, e as pessoas têm feito isso, mas não sei por que você faria. Criar um novo banco de dados significa criar uma nova biblioteca com possíveis bugs e tantos novos problemas a serem considerados e pensados. Se você decidiu criar um aplicativo, criar sua própria solução de banco de dados está realmente dentro do escopo de fazer isso?

Soluções existentes como Hive ou Moor já estão em uso por muitas pessoas, todas encontrando bugs e arquivando problemas no GitHub. Isso é o que dá qualidade a essas bibliotecas . Quem encontraria bugs em seu banco de dados novinho em folha, do zero? Porque você é a única pessoa que usa isso, só você usaria . Isso não soa muito atraente, não é? Espero que não.

Caso de uso

Se você desconfia completamente de todo o código que não foi escrito por você, ou tem algum caso de uso esotérico estranho, talvez considere fazer o seu próprio. Eu não consideraria fazer isso em nenhum aplicativo que eu faria…

Tantas opções! Qual devo usar?

Não há uma maneira fácil de responder qual banco de dados é “melhor” – depende do seu caso de uso. Mas deixe-me resumir.

  • Se seus dados são relacionais e você deseja poder visualizá-los facilmente em seu computador durante o desenvolvimento – e você não se importa em não ter suporte na web – você deve usar moor .
  • Se você precisar sincronizar seus dados entre dispositivos e não se importar com a configuração bastante estendida, use o Firebase .
  • Se você quiser começar a funcionar muito rapidamente e quiser um ótimo suporte para a Web , além de qualquer outra coisa em que o Dart seja executado, você deve usar o Hive .
  • Se você tiver dúvidas sobre a segurança desses bancos de dados e ninguém puder convencê-lo do contrário, e você tiver muito tempo em suas mãos, considere criar seu próprio banco de dados ou armazenamento de objetos com objetos JSON. Mas eu não faria.

Se eu estivesse fazendo um aplicativo hoje, provavelmente usaria o Hive .

Obrigado por ler este artigo sobre bancos de dados para Flutter. Espero que tenha feito a escolha de um um pouco mais fácil para você!