Article directory
Flutter common database operation library
Flutter is a cross-platform mobile application development framework that supports the use of multiple types of databases for data storage and management. The use of databases in Flutter usually needs to rely on third-party libraries. The following are some commonly used Flutter database libraries:
- sqflite: It is a Flutter plug-in for SQLite database, which provides an API interface similar to SQLite in Android and supports basic CRUD operations.
- firebase_database: is a real-time NoSQL database provided by Google, which can be used for data storage and synchronization of Flutter applications.
- hive: is a fast, lightweight key-value pair database with high performance and low latency, suitable for local data storage in Flutter applications.
The most commonly used sqflite introduction
Introduction
sqflite is a Flutter plugin for SQLite database, which provides an API interface similar to SQLite in Android and supports basic CRUD operations. It is one of the most widely used local database libraries in Flutter, which can be used to store the local data of the application. Sqflite is lightweight, high performance, and easy to use, making it suitable for small applications or those that require simple local data storage.
example
Below is a sample code using the sqflite library, demonstrating how to create and use an SQLite database in a Flutter application:
- Add dependencies of the sqflite library:
Add the dependency of the sqflite library to the pubspec.yaml file of the Flutter project:
dependencies:
sqflite: ^2.2.8+4
- Create a database:
To create a database example in a Flutter application, a my_database.db
SQLite database named SQLite can be created by executing the following code:
import 'package:sqflite/sqflite.dart';
import 'package:path/path.dart';
class MyDatabase {
static final MyDatabase _instance = MyDatabase._internal();
factory MyDatabase() => _instance;
static Database _database;
MyDatabase._internal();
Future<Database> get database async {
if (_database != null) return _database;
_database = await _initDatabase();
return _database;
}
Future<Database> _initDatabase() async {
final dbPath = await getDatabasesPath();
final path = join(dbPath, 'my_database.db');
return await openDatabase(
path,
version: 1,
onCreate: (db, version) async {
await db.execute(
'CREATE TABLE users(id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT)',
);
},
);
}
}
In the above code, we use the methods sqflite
in the library openDatabase
to create the database and specify the database file path. We also provide a onCreate
callback function to perform some initialization operations when creating the database, such as creating tables and so on.
- Insert data:
The following is a sample code that demonstrates how to insert a piece of data into the database:
final db = await MyDatabase().database;
await db.insert(
'users',
{'name': 'John'},
conflictAlgorithm: ConflictAlgorithm.replace,
);
In the above code, we first obtain a database instance, and then use insert
the method to users
insert a piece of data into the table named. We store the data as a Map object where the keys are the column names and the values are the values to be inserted. If there are already records with the same primary key in the table, we use conflictAlgorithm
parameters to specify the conflict handling strategy, which is used here ConflictAlgorithm.replace
to indicate that the old data is replaced with new data.
- Query data:
Here is a sample code that demonstrates how to query data from the database:
final db = await MyDatabase().database;
final List<Map<String, dynamic>> users = await db.query('users');
In the above code, we first obtain a database instance, and then use query
the method to query users
all the data in the table named. The query result will return a list containing multiple Map objects, where each Map object represents a record, the key is the column name, and the value is the corresponding value.
- update data:
Here is a sample code that demonstrates how to update data in the database:
final db = await MyDatabase().database;
await db.update(
'users',
{'name': 'Mary'},
where: 'id = ?',
whereArgs: [1],
);
In the above code, we first obtain a database instance, and then use update
the method to update users
a piece of data in the table named. We use where
the parameter to specify the condition of the record to be updated, which is represented id
as 1 here, and use whereArgs
the parameter to specify the parameter value in the condition. We store the data to be updated as a Map object, where the key is the column name and the value is the value to be updated.
- delete data:
Here is a sample code that demonstrates how to delete data from the database:
final db = await MyDatabase().database;
await db.delete(
'users',
where: 'id = ?',
whereArgs: [1],
);
In the above code, we first obtain a database instance, and then use delete
the method to delete users
a piece of data in the table named. We use where
the parameter to specify the condition of the record to be deleted, which is represented id
as 1 here, and use whereArgs
the parameter to specify the parameter value in the condition.
Relying on sqflite, the singleton mode encapsulates a sqlite operation class
import 'package:path/path.dart';
import 'package:path_provider/path_provider.dart';
import 'package:sqflite/sqflite.dart';
import 'package:learning/model/task_model.dart';
class DatabaseHelper {
DatabaseHelper._(); //单例模式
static final DatabaseHelper db = DatabaseHelper._();
static Database? _database;
Future<Database?> get database async {
_database ??= await initDb();
return _database;
}
//init database and open it
Future<Database> initDb() async {
print("initDb");
Directory documentDirectory = await getApplicationDocumentsDirectory();
String path = join(documentDirectory.path, 'yytimer.db');
print("initDb ${path}");
Database db = await openDatabase(path, version: 1, onOpen: (db) async {
// 等待表创建完成
await db.execute(
'CREATE TABLE IF NOT EXISTS timerdata (id INTEGER PRIMARY KEY, title TEXT, sptime INTEGER, retime INTEGER, cycle INTEGER, setsgap INTEGER, groups INTEGER)');
});
return db;
}
//insert database
Future<int?> insert(Task task) async {
print('insert data Saving Task...');
final db = await database; // 确保database在上下文中定义
try {
var result = await db?.rawInsert(
'INSERT OR REPLACE INTO timerdata (id,title,sptime,retime, cycle,setsgap,groups) VALUES (?,?,?,?,?,?,?)',
[
task.id,
task.title,
task.sptime,
task.retime,
task.cycle,
task.setsgap,
task.groups
]);
print('insert data id timerdata saved! ${task.id}, ${task.title}, ${task.sptime}, ${task.retime},${task.cycle}, ${task.setsgap}, ${task.groups}');
return result;
} on DatabaseException catch (e) {
print(e);
return -1;
}
}
//query database
Future<List<Task>> getAll() async {
print('getAll database...');
var db = await database;
var query = await db?.query('timerdata', orderBy: 'id DESC');
List<Task> tasks =
query!.isNotEmpty ? query.map((t) => Task.fromMap(t)).toList() : [];
print('getAll in database: ${tasks.length} , ${tasks[0].title},${tasks[1].title}');
return tasks;
}
//delete sql by id
Future<void> delete(int id) async {
var db = await database;
await db?.rawDelete('DELETE FROM timerdata WHERE id = ?', [id]);
}
//delete sql by title
Future<void> deleteByTitle(String title) async {
var db = await database;
await db?.rawDelete('DELETE FROM timerdata WHERE title = ?', [title]);
}
//update database by id
Future<void> updateDatabase(Task task) async {
final db = await database;
await db?.update(
'timerdata',
task.toMap(),
where: "id = ?",
whereArgs: [task.id],
conflictAlgorithm: ConflictAlgorithm.replace,
);
}
//update database by title
Future<void> updateDatabaseByTitle(Task task) async {
final db = await database;
await db?.update(
'timerdata',
task.toMap(),
where: "title = ?",
whereArgs: [task.title],
conflictAlgorithm: ConflictAlgorithm.replace,
);
}
}
In initDb(), you can use await db.execute() to wait for the creation of the database table to be completed, avoiding problems in using the database before creating the table.
In the insert() method, you can use the INSERT OR REPLACE statement to implement insert or update operations to avoid inserting duplicate data.
In the getAll() method, you can use db!.query('timerdata', orderBy: 'id DESC') to get all the data in reverse order by id, which can avoid the operation of sorting after getting the data.
In the updateDatabase() and updateDatabaseByTitle() methods, you can use the conflictAlgorithm parameter of the update() method to implement insert or update operations to avoid the problem of updating duplicate data.
illustrate
initDb Description
onCreate is the callback function called when the database is opened for the first time to create database tables and initialize data. In Dart's sqflite library, the signature of the onCreate callback function is (Database db, int version), where the db parameter is the opened database object, and the version parameter is the version number of the database.
In the onCreate callback function, we can use the db.execute() method to execute SQL statements to create tables and initialize data. For example, in the following code:
Database db = await openDatabase(path, version: 1, onCreate: (Database db, int version) async {
await db.execute('CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT)');
await db.execute('INSERT INTO users (name) VALUES ("Alice")');
});
We created a table called users and inserted a record. Specifically, we used the CREATE TABLE IF NOT EXISTS statement to create a users table, which has two fields: id and name, where id is the primary key and name is the text type. Then, we use the INSERT INTO statement to insert a record into the users table, the name field of the record is "Alice"``onCreate is the callback function called when the database is opened for the first time, and is used to create the database table and initialize the data. In Dart's sqflite library, the signature of the onCreate callback function is (Database db, int version), where the db parameter is the opened database object, and the version parameter is the version number of the database.
conflictAlgorithm description
conflictAlgorithm
Is the resolution strategy when conflicts (such as violations of unique constraints) occur when data is inserted or updated. In the Dart sqflite
library, there are the following four conflict resolution strategies:
ConflictAlgorithm.rollback
: Rollback the transaction, discarding all changes.ConflictAlgorithm.abort
: Abort the current operation, but do not roll back the transaction.ConflictAlgorithm.fail
: Abandon the current operation, but do not roll back the transaction, and throw an exception.ConflictAlgorithm.replace
: Replace old data, or insert new data, to resolve conflicts.
In the code, ConflictAlgorithm.replace
the function is to replace the old data with the new data if a conflict occurs when inserting or updating data. This strategy can guarantee the uniqueness of the data and will not throw exceptions. If the data does not exist, the new data is directly inserted, and if the data already exists, the old data is replaced with the new data.
For example, in the code above, parameters are used in the updateDatabase()
and methods to avoid updating or inserting duplicate data. If data with the same id or title already exists in the table, the old data will be replaced with the new data, otherwise the new data will be inserted directly.updateDatabaseByTitle()
conflictAlgorithm: ConflictAlgorithm.replace
The interface written before, the effect of saving the data in the database is as follows: