从零开始用flutter写一个完整应用⑼:持久化储存1--SQL

2022-07-02  本文已影响0人  逃离_102

说明

持久化储存,在应用开发中也是个很重要的功能,有些数据是需要在应用进程退出,再次启动时还能知道前一次的数据的,这种情况就需要持久化储存,最常见的就是设置的一些状态信息等。持久化储存在flutter里,可大致分3种:1,数据库SQLite;2,文件形式;3,键值对形式。本文先对数据库SQLite进行说明,后面再对后2种一一说明

SQLite 数据持久化

如果您正在编写一个需要持久化且查询大量本地设备数据的 app,可考虑采用数据库,而不是本地文件夹或关键值库。总的来说,相比于其他本地持久化方案来说,数据库能够提供更为迅速的插入、更新、查询功能。Flutter应用程序中可以通过 sqflite package 来使用 SQLite 数据库

添加依赖

为了使用 SQLite 数据库,首先需要导入 sqflite 和 path 这两个 package。
1,sqflite 提供了丰富的类和方法,以便你能便捷实用 SQLite 数据库。
2,path 提供了大量方法,以便你能正确的定义数据库在磁盘上的存储位置。

//增加依赖
dependencies:
  flutter:
    sdk: flutter
  sqflite:
  path:

//确保你已将 packages 导入要使用的文件中。
import 'dart:async';
import 'package:flutter/widgets.dart';
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';

定义数据模型

数据模型,也就是实体数据类。示例如下

class Dog {
  final int id;
  final String name;
  final int age;

  const Dog({
    required this.id,
    required this.name,
    required this.age,
  });

  Map<String, dynamic> toMap() {
    return {
      'id': id,
      'name': name,
      'age': age,
    };
  }

  @override
  String toString() {
      return 'Dog{id: $id, name: $name, age: $age}';
  }
}

打开数据库

在你准备读写数据库的数据之前,你要先打开这个数据库。打开一个数据库有以下两个步骤:
使用 sqflite package 里的 getDatabasesPath 方法并配合 path package里的 join 方法定义数据库的路径。
使用 sqflite package 里的 openDatabase 方法打开数据库。

WidgetsFlutterBinding.ensureInitialized();
final database = openDatabase(
  join(await getDatabasesPath(), 'doggie_database.db'),
);

创建表

使用SQLite 语句创建表,示例如下

final database = openDatabase(
  join(await getDatabasesPath(), 'doggie_database.db'),
  onCreate: (db, version) {
    // 创建表
    return db.execute(
      'CREATE TABLE dogs(id INTEGER PRIMARY KEY, name TEXT, age INTEGER)',
    );
  },
  //版本号
  version: 1,
);

插入数据

使用SQLite 语句创建表,示例如下
分以下两步:1. 把 Dog 转换成一个 Map 数据类型;2. 使用 insert() 方法把Map保存到dogs` 数据表中。

Future<void> insertDog(Dog dog) async {
  final db = await database;

  await db.insert(
    'dogs',
    dog.toMap(),
    conflictAlgorithm: ConflictAlgorithm.replace,
  );
}

查询列表

分为以下两步:
1,调用 dogs 表对像的 query 方法。这将返回一个List <Map>。
2,将 List<Map> 转换成 List<Dog> 数据类型。

Future<List<Dog>> dogs() async {
  final db = await database;
  final List<Map<String, dynamic>> maps = await db.query('dogs');

  return List.generate(maps.length, (i) {
    return Dog(
      id: maps[i]['id'],
      name: maps[i]['name'],
      age: maps[i]['age'],
    );
  });
}

修改数据

修改数据操作包含以下两步:
1,将一条狗狗的数据转换成 Map 数据类型;
2,使用 where 语句定位到具体将要被修改的数据。

Future<void> updateDog(Dog dog) async {
  final db = await database;

  await db.update(
    'dogs',
    dog.toMap(),
    where: 'id = ?',
    whereArgs: [dog.id],
  );
}

注意
使用 whereArgs 将参数传递给 where 语句。有助于防止 SQL 注入攻击。
这里不要使用字符串模板,比如: where: "id = ${dog.id}"!

删除数据

Future<void> deleteDog(int id) async {
  // 获得数据库引用
  final db = await database;

  await db.delete(
    'dogs',
    where: 'id = ?',
    whereArgs: [id],
  );
}

完整示例如下

import 'dart:async';

import 'package:flutter/widgets.dart';
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  final database = openDatabase(
    // 设置数据库的路径。注意:使用 `path` 包中的 `join` 方法是
    // 确保在多平台上路径都正确的最佳实践。
    join(await getDatabasesPath(), 'doggie_database.db'),
    // 当数据库第一次被创建的时候,创建一个数据表,用以存储狗狗们的数据。
    onCreate: (db, version) {
      return db.execute(
        'CREATE TABLE dogs(id INTEGER PRIMARY KEY, name TEXT, age INTEGER)',
      );
    },
    // 设置版本。它将执行 onCreate 方法,同时提供数据库升级和降级的路径。
    version: 1,
  );

  // 插入数据
  Future<void> insertDog(Dog dog) async {
    final db = await database;

    await db.insert(
      'dogs',
      dog.toMap(),
      conflictAlgorithm: ConflictAlgorithm.replace,
    );
  }

  // 获取数据
  Future<List<Dog>> dogs() async {
    final db = await database;
 
    final List<Map<String, dynamic>> maps = await db.query('dogs');
    // 将 List<Map<String, dynamic> 转换成 List<Dog> 数据类型
    return List.generate(maps.length, (i) {
      return Dog(
        id: maps[i]['id'],
        name: maps[i]['name'],
        age: maps[i]['age'],
      );
    });
  }

 //更新数据
  Future<void> updateDog(Dog dog) async {
    // 获得数据库引用
    final db = await database;
    // 修改给定的狗狗的数据
    await db.update(
      'dogs',
      dog.toMap(),
      where: 'id = ?',
      whereArgs: [dog.id],
    );
  }

  //删除数据
  Future<void> deleteDog(int id) async {
    // 获得数据库引用
    final db = await database;
    // 将狗狗从数据库移除
    await db.delete(
      'dogs',
      where: 'id = ?',
      whereArgs: [id],
    );
  }

  // 测试插入数据
  var fido = const Dog(
    id: 0,
    name: 'Fido',
    age: 35,
  );
  await insertDog(fido);
  print(await dogs()); 

  // 测试更新数据
  fido = Dog(
    id: fido.id,
    name: fido.name,
    age: fido.age + 7,
  );
  await updateDog(fido);
  print(await dogs());

 // 测试删除数据
  await deleteDog(fido.id);
  // 打印一个列表的狗狗们 (这里已经空了
  print(await dogs());
}

class Dog {
  final int id;
  final String name;
  final int age;

  const Dog({
    required this.id,
    required this.name,
    required this.age,
  });

  Map<String, dynamic> toMap() {
    return {
      'id': id,
      'name': name,
      'age': age,
    };
  }

  // 重写 toString 方法,以便使用 print 方法查看每个狗狗信息的时候能更清晰。
  @override
  String toString() {
    return 'Dog{id: $id, name: $name, age: $age}';
  }
}

数据库的应用,就说到这了,如有遗漏欢迎留言,如有错误欢迎指正,谢谢

上一篇 下一篇

猜你喜欢

热点阅读