乐趣区

关于程序员:Flutter-5-大本地数据库解决方案

Flutter 5 大本地数据库解决方案

原文 https://levelup.gitconnected….

前言

这里列出了最风行的数据库解决方案以及代码示例。

抉择正确的数据管理系统对于提高效率和可 extension 性以及影响可用性和用户体验至关重要。只管 flutter 依然处于晚期阶段,然而有很多数据管理解决方案可供选择,其中一些曾经能够投入生产。我将概述用于在本地保护数据的最常见的数据库管理系统。

注释

Sqflite

Sqflite 是一个驰名的 SQLite flutter 插件。这是一个具备良好交易和批量反对的关系数据库。当数据库关上时,它会主动治理版本控制。它还包含用于常见 CRUD 操作的帮忙器。后盾线程解决所有数据库操作。它与 ACID 兼容,因而简直反对所有 SQL 规范。如果您喜爱将本人的 SQL 查问编写为字符串,那么这个简略的插件将满足您的数据管理需要。

// 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)');
});

// 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');
});

// Update some record
int count = await database.rawUpdate(
    'UPDATE Test SET name = ?, value = ? WHERE name = ?',
    ['updated name', '9876', 'some name']);
print('updated: $count');

// Get the records
List<Map> list = await database.rawQuery('SELECT * FROM Test');
List<Map> expectedList = [{'name': 'updated name', 'id': 1, 'value': 9876, 'num': 456.789},
  {'name': 'another name', 'id': 2, 'value': 12345678, 'num': 3.1416}
];

正如您从示例中看到的,我发现浏览这段代码并不容易。随着应用程序的增长,保护此代码将变得十分繁琐。因为 sqflite 是一个根本的数据库管理系统 (DBMS) 插件,所以我置信您应该构建本人的构造并将其包装在 sqflite 四周,就像大多数用于 flutter 的关系数据库管理系统包一样。

SQLite 通常是一个自蕴含的、无服务器的、轻量级的解决方案。它的性能是有争议的,但它能够让你的工作与一个夺目的疾速内存数据库。根底软件包包含挪动平台反对。没有网络反对,但 sqflite_common_ffi 能够用来反对桌面平台。

floor

Floor 是一个十分有用的 SQLite 形象,它蕴含一个对象映射器。它依赖于 sqflite,并在此基础上减少了类型平安等个性。它反对 sqflite 反对的所有内容,包含内存数据库。

尽管它充当 sqflite 的包装器,但它引入了更高级的概念,如 DAO 和实体。实体能够用来将内存中的对象映射到数据记录,而 DAO 容许您拜访和操作数据。分明地分隔实体、DAO 和数据库总是一个好主见。您还能够为您的 DAO 编写好的测试,并确保您的查问通过这种形式失去验证。

@entity
class Person {
  @primaryKey
  final int id;

  final String name;

  Person(this.id, this.name);
}

后面的代码示例演示如何创立实体。地板是领导创立适当的数据库表应用正文。这是一种十分用户敌对的设计数据库的办法。让咱们来看看如何构建 DAO。

@dao
abstract class PersonDao {@Query('SELECT * FROM Person')
  Future<List<Person>> findAllPersons();

  @Query('SELECT * FROM Person WHERE id = :id')
  Stream<Person?> findPersonById(int id);

  @insert
  Future<void> insertPerson(Person person);
}

您所要做的就是提供一个具备适当正文的抽象类。遗憾的是,没有查问 API,因而依然必须以字符串模式提供 SQL 查问。这种办法对我来说特地没有吸引力,因为这些查问没有可用的语法查看。您依然能够测试和验证这些查问。

final personDao = database.personDao;
final person = Person(1, 'Frank');

await personDao.insertPerson(person);
final result = await personDao.findPersonById(1);

地板是生成必要的代码在一个建设者的帮忙下。因而,所有的 DAO 都存储在数据库中。要插入一个人,您能够调用 database. person. insert tPerson (person)。诚实说,我不认为通过数据库对象拜访所有 DAO 是一个好主见。然而,这种俊俏能够通过应用依赖注入(DI) container 来防止。

总的来说,地板是一个有前途的平方弗莱特包装与许多有用的性能。无关详细信息,请参阅他们的文档。它通过示例和图表分明地展现了所有个性。

Drift (Moor)

Moor 无疑是性能最丰盛的 Flutter 关系数据库解决方案。它也是 sqflite 的包装器,然而它提供了更弱小的性能,并且蕴含一个查问 API。只管 Web 反对是实验性的,但它反对所有潜在的平台。此外,它还为事务、模式迁徙、简单的筛选器和表达式以及批处理提供了极好的反对。

它为 DAO 和实体 (如 floor) 提供了相似的反对,然而它是以一种高度模块化的形式进行的,容许您轻松地将它与 DI container 绑定联合起来。此解决方案的另一个优良个性是内置的线程反对,它容许您在不须要额定工作的状况下跨隔离区运行数据库代码。最初,值得注意的是,它蕴含一个用于 SQL 查问的集成 IDE。多酷啊!

让咱们看一些代码示例,以便您能够将其与 floor 进行比拟。上面是一个如何定义表的示例。

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()();}

咱们不应用正文,而是 extension Table 类,并为该列的数据类型应用特定的列类型。在这里,咱们能够为独自的列配置各种属性,比方空性、外键和束缚。说到桌子的定义,我必须抵赖我喜爱地板的形式。它只是对我来说更具可读性,并且正文的应用是一个绝妙的概念。

这就是 DAO 的定义形式。

@DriftAccessor(tables: [Todos])
class TodosDao extends DatabaseAccessor<MyDatabase> with _$TodosDaoMixin {
  // this constructor is required so that the main database can create an instance
  // of this object.
  TodosDao(MyDatabase db) : super(db);

  Stream<List<TodoEntry>> todosInCategory(Category category) {if (category == null) {return (select(todos)..where((t) => isNull(t.category))).watch();} else {return (select(todos)..where((t) => t.category.equals(category.id)))
          .watch();}
  }
}

毫无疑问,您首先留神到的是查问 API,而不是基于文本的 sql 查问。就集体而言,我喜爱查问 API,因为随着我的项目的 extension,您会发现一些过滤器或数据拜访办法可能会被简化。您能够在不就义查问可读性的状况下缩小代码复制。我明确,通过 SQLite 语法学习另一种 API 可能不是最舒服的抉择,但它相对是值得的。我很观赏这样的想法,即残缺的数据库逻辑能够用 Dart 编写,并且在编译过程中能够检测到可能的谬误。

当我须要应用关系型本地数据库时,漂移是我的第一抉择。它只是提供了一种更无效的开发和伸缩形式。因为该插件应用代码生成,所以我置信实体和 DAO 申明可能更加用户敌对。该我的项目仍在踊跃开发中,每个新版本都比前一个版本有所改进。

hive

Hive 是一个十分弱小和有前途的 NoSQL 数据库。它与所有平台兼容,包含网络。我没有第一手的常识,然而疾速的搜寻显示读写速度的基准是十分令人印象粗浅的。它有很强的内置加密。将其视为一个映射,其中对象以键 - 值对的模式存储。

因为它是一个 NoSQL 数据库,术语“table”被替换为术语“box”(kind of)。因而,您的数据被组织在这些框中。因为 NoSQL 具备很强的适应性,所以您能够为每个值定义任何类型的构造。因而,框的存在并不意味着存在统一的数据模型。如果您的应用程序须要为雷同类型的实体提供灵便的数据列,那么这可能是一个重要的益处。

在应用框之前,必须首先关上它,以便将数据从本地存储加载到内存中以便进行即时拜访。因而,您能够在不应用“wait”的状况下进行查问,并且在 widget 的构建办法中应用它将非常简单。如果你不须要立刻拜访,你能够随时应用懒箱。

var box = Hive.box('products');

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

var name = box.get('name');

print('Product Name: $name');

您能够看到如何应用下面的 Hive 创立一个盒子。这不难理解。Hive 为所有根本类型提供了根本反对,但大多数状况下,您心愿存储的是实体或实体的子集。为此,必须首先创立 TypeAdapter。这里有一个例子:

@HiveType(typeId: 0)
class Product extends HiveObject {@HiveField(0)
  String name;

  @HiveField(1)
  int price;

  @HiveField(2)
  String color;
}

将 HiveObjects 视为实体。不过,在这种状况下,您能够 extension Product 并将其存储在同一个框中。上面是如何应用 Product 类的示例。

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

var product = Product()
  ..name = 'Foo'
  ..price = 10
  ..color = 'orange';
box.add(product);

print(box.getAt(0)); // Foo - 10 - orange

product.price = 12;
product.save();

print(box.getAt(0)) // Foo - 12 - orange

在我看来,蜂巢是小规模和灵便应用程序的现实抉择。它易于学习并适应变动。我很快乐能把它用在一个副业上。

sembast

Sembast 是另一个用于 Flutter (和 Dart)应用程序的 NoSQL 数据库,它反对所有可能的平台,包含 web (通过 Sembast web 包)。Sembast 因为其有前途的性能而在这个名单上,但我不置信它还在那里。它以相似于 Hive 的形式治理数据库,但有一些不同之处。我没有看到任何对实体的反对,我认为这在数据模式可读性方面是无益的。您依然能够应用本人的类型,但它们必须是正确编码 / 解码的 JSON。

// File path to a file in the current directory
String dbPath = 'sample.db';
DatabaseFactory dbFactory = databaseFactoryIo;

// We use the database factory to open the database
Database db = await dbFactory.openDatabase(dbPath);

若要应用数据库,必须应用。分贝 extension。此文件将用于所有数据库操作,并将依据须要进行更新。如果你不想应用这个选项,你依然能够通过 sqflite 应用 Sembast。

// dynamically typed store
var store = StoreRef.main();
// Easy to put/get simple values or map
// A key can be of type int or String and the value can be anything as long as it can
// be properly JSON encoded/decoded
await store.record('title').put(db, 'Simple application');
await store.record('version').put(db, 10);
await store.record('settings').put(db, {'offline': true});

// read values
var title = await store.record('title').get(db) as String;
var version = await store.record('version').get(db) as int;
var settings = await store.record('settings').get(db) as Map;

// ...and delete
await store.record('version').delete(db);

在下面,您能够看到如何保留和读取记录。API 学起来很简略,但我更喜爱 Hive 语法而不是 Sembast 语法,因为它省去了在读取数据时“期待”的须要。然而,你依然能够摸索森巴斯特。值得注意的是,Sembast 反对“触发器”和“数据加密”这两个有用的个性能够帮忙进步数据的安全性和一致性。

shared_preferences

如果您的应用程序不是数据要害型的,那么您就不须要破费大量工夫学习额定的库。共享首选项应用特定于平台的存储 API 来存储和读取键值对。因为数据能够异步地保留到磁盘上,所以这个插件不应该用来存储要害数据。

_incrementCounter() async {SharedPreferences prefs = await SharedPreferences.getInstance();
  int counter = (prefs.getInt('counter') ?? 0) + 1;
  print('Pressed $counter times.');
  await prefs.setInt('counter', counter);
}

正如您所看到的,应用该插件是简略和间接的。

关系数据库或 NoSQL

我感觉有任务解释关系数据库管理系统和 NoSQL 解决方案之间的区别。它们都有长处和毛病,但这不是重点。因为咱们不能说一个比另一个好。归根结底就是你的须要。

关系数据库 Relational DBMS:

  • 数据一致性
  • 数据模式不太可能产生显著变动
  • 存储理论数据和数值数据

NoSQL:

  • 数量宏大,数据凌乱
  • 灵便的模式定义,实时数据,更容易伸缩
  • 没有连贯,查问速度更快,但数据复制更多

这些是两个数据库系统的要害个性。当波及到应用本地数据库进行开发时,您应该彻底了解应用程序的数据需要。

如果您正在开发同时具备数字产品和实体产品的商店应用程序,那么这些产品可能具备多种个性。即便是同一类别的产品也能够有不同的特点。在这种状况下,您须要一个 NoSQL 数据库,否则最终会失去一大堆可为空的列。

思考另一个示例应用程序,比方加密货币投资组合应用程序。当然,您的应用程序将依赖于第三方 API。这些 API 常常更改。您能够应用 NoSQL 数据库,而不是每次都更改模式,这比应用关系型 DBMS 更容易适应更改。我置信你明确这一点,然而你能够浏览更多对于这一主题的文章,以帮忙你为将来的我的项目做出更好的决策。

Conclusion

论断

我试图简化用于 flutter 开发的最风行的本地数据库解决方案的基本原理。这些都是十分棒的软件包,背地都有十分聪慧的头脑。试着通过给他们星级或者为他们的知识库做奉献来帮忙他们。我心愿这篇文章对你决定下一个数据库解决方案有帮忙。

最初一个想法。我很理解「幻界」和「伊萨」的数据库我晓得他们正在崛起。这里没有列出它们,因为它们最近才公布了 alpha 版本。

谢谢你贵重的工夫。

结束语

如果本文对你有帮忙,请转发让更多的敌人浏览。

兴许这个操作只有你 3 秒钟,对我来说是一个激励,感激。

祝你有一个美妙的一天~


© 猫哥

  • 微信 ducafecat
  • https://wiki.ducafecat.tech
  • https://video.ducafecat.tech

本文由 mdnice 多平台公布

退出移动版