高頻網(wǎng)站開發(fā)百度關(guān)鍵詞查詢工具免費(fèi)
Flutter開發(fā)進(jìn)階之并發(fā)操作數(shù)據(jù)庫
盡管 Flutter 本身不包含任何數(shù)據(jù)庫功能,但可以使用各種第三方庫和插件來在 Flutter 應(yīng)用程序中實現(xiàn)數(shù)據(jù)庫功能;
以下將使用sqflite作為例子,sqflite允許在 Flutter 應(yīng)用程序中執(zhí)行 SQL 查詢,創(chuàng)建和管理數(shù)據(jù)庫表,以及執(zhí)行其他常見的數(shù)據(jù)庫操作。
在將sqflite添加到Flutter項目的依賴中后,就可以使用代碼創(chuàng)建數(shù)據(jù)庫和表了。
import 'package:sqflite/sqflite.dart'; Future<Database> getDatabase() async { final dir = (await getDatabasesPath()).resolve('my_database.db'); return await openDatabase(dir.path, version: 1, onCreate: _onCreate);
} Future _onCreate(Database db, int version) async { await db.execute(''' CREATE TABLE user ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, age INTEGER ) ''');
}
然后我們可以做一些插入、查詢、更新和刪除數(shù)據(jù)庫中數(shù)據(jù)的操作。
import 'package:sqflite/sqflite.dart'; Future<void> insertData() async { final db = await getDatabase(); await db.execute( 'INSERT INTO user (name, age) VALUES (?, ?)', ['John', 25], );
} Future<List<Map<String, dynamic>>> queryData() async { final db = await getDatabase(); return await db.query('user');
} Future<int> updateData() async { final db = await getDatabase(); return await db.update( 'user', {'age': 26}, where: 'name = ?', whereArgs: ['John'], );
} Future<int> deleteData() async { final db = await getDatabase(); return await db.delete('user', where: 'name = ?', whereArgs: ['John']);
}
在實際應(yīng)用中并不會這么簡單,特別是當(dāng)我們有需求在多個位置去操作數(shù)據(jù)庫的時候,這時候可能會有線程安全的問題;
比如說在一個作用域內(nèi),有多臺設(shè)備需要在我所在的這臺設(shè)備操作數(shù)據(jù)庫;
首先我所在的設(shè)備作為主機(jī)要監(jiān)聽子機(jī)的UDP廣播,然后將通過我驗證的子機(jī)向其發(fā)送我開放的TCP的地址和端口。
const String multicastGroup = '224.0.0.1'; // 定義多播組地址 const int port = 5000; // 定義端口號 const int bufferSize = 1024; // 定義緩沖區(qū)大小 final ByteData buffer = ByteData(bufferSize); DatagramSocket socket = DatagramSocket(); socket.bind(port); socket.joinMulticastGroup(multicastGroupIP); socket.listen(buffer.length); socket.onDatagramReceived = (Datagram datagram) async { final String receivedData = datagram.data.toString(); // 處理接收到的數(shù)據(jù)... };
然后合法的子機(jī)會收到我的信息,就可以通過TCP向主機(jī)發(fā)送命令;
這時就需要主機(jī)時刻監(jiān)聽TCP并對其響應(yīng)。
const int port = 5000; // 定義端口號 final ServerSocket serverSocket = ServerSocket(port); serverSocket.onAccept = (ServerSocket socket) async { final Stream stream = socket.accept(); stream.transform(utf8.decoder).listen((String data) { // 處理接收到的數(shù)據(jù)... }); };
假設(shè)對其響應(yīng)的本身是對數(shù)據(jù)庫進(jìn)行操作,而主機(jī)內(nèi)部也同時對數(shù)據(jù)庫有了操作,這時候就要注意數(shù)據(jù)庫的線程安全了;
首先可以通過對數(shù)據(jù)庫的操作加鎖來保證,比如sqflite提供了事務(wù)(Transaction),在事務(wù)中執(zhí)行數(shù)據(jù)庫操作可以確保操作的原子性,即要么全部成功,要么全部失敗;
通過使用事務(wù),我們可以實現(xiàn)對數(shù)據(jù)庫操作的加鎖,確保同一時間只有一個線程可以訪問數(shù)據(jù)庫中的特定資源。
Future<void> insertData() async { final db = await getDatabase(); await db.transaction((txn) async { // 在事務(wù)中執(zhí)行數(shù)據(jù)庫操作 await txn.execute('INSERT INTO user (name, age) VALUES (?, ?)', ('John', 25)); // 提交事務(wù) await txn.commit(); });
}
或者直接使用synchronized創(chuàng)建鎖。
import 'package:synchronized/synchronized.dart';
還可以通過數(shù)據(jù)庫連接池來限制最大連接數(shù)量。
import 'package:sqflite/sqflite.dart'; class DatabaseHelper { static final DatabaseHelper _instance = DatabaseHelper._internal(); static Database? _db; factory DatabaseHelper() { return _instance; } Future<Database> get db async { if (_db != null) return _db; _db = await _openDatabase(); return _db; } Future<void> close() async { if (_db != null) { await _db!.close(); _db = null; } } Future<Database> _openDatabase() async { final pool = await SqliteConnectionPool.forDatabase('path/to/database.db'); pool.maxSize = 10; // 設(shè)置最大連接數(shù)為10 return pool.openDatabase(); }
}
這樣同時還避免了直接使用Database實例。