Flutter Redis数据库交互插件redis的使用

发布于 1周前 作者 gougou168 来自 Flutter

Flutter Redis数据库交互插件redis的使用

简介

redis-dart 是一个用于 Dart 的 Redis 客户端库。它支持 Redis 协议解析,并且设计简单、快速,无需任何外部依赖即可运行。

支持的功能

  • 事务CAS(Check-and-Set) 模式
  • 发布/订阅 功能
  • Unicode 支持
  • 性能简洁性
  • TLS 支持

简单示例

连接和设置键值

import 'package:redis/redis.dart';

void main() async {
  final conn = RedisConnection();
  await conn.connect('localhost', 6379).then((Command command) {
    command.send_object(["SET", "key", "0"]).then((var response) {
      print(response); // 输出: OK
    });
  });
}

顺序执行命令

import 'package:redis/redis.dart';

void main() async {
  final conn = RedisConnection();
  await conn.connect('localhost', 6379).then((Command command) {
    command.send_object(["SET", "key", "0"]).then((var response) {
      assert(response == 'OK');
      return command.send_object(["INCR", "key"]);
    }).then((var response) {
      assert(response == 1);
      return command.send_object(["INCR", "key"]);
    }).then((var response) {
      assert(response == 2);
      return command.send_object(["INCR", "key"]);
    }).then((var response) {
      assert(response == 3);
      return command.send_object(["GET", "key"]);
    }).then((var response) {
      print(response); // 输出: 3
    });
  });
}

并行执行命令

import 'package:redis/redis.dart';

void main() async {
  final conn = RedisConnection();
  await conn.connect('localhost', 6379).then((Command command) {
    command.send_object(["SET", "key", "0"]).then((var response) {
      assert(response == 'OK');
    });
    command.send_object(["INCR", "key"]).then((var response) {
      assert(response == 1);
    });
    command.send_object(["INCR", "key"]).then((var response) {
      assert(response == 2);
    });
    command.send_object(["INCR", "key"]).then((var response) {
      assert(response == 3);
    });
    command.send_object(["GET", "key"]).then((var response) {
      print(response); // 输出: 3
    });
  });
}

泛型支持

Redis 响应和请求可以任意嵌套。以下是 Redis 和 Dart 之间的映射关系:

Redis Dart
String String
Integer Integer
Array List
Error RedisError
Bulk String 或 Binary

示例

import 'package:redis/redis.dart';

void main() async {
  final conn = RedisConnection();
  await conn.connect('localhost', 6379).then((Command command) {
    command.send_object(["EVAL", "return {KEYS[1],{KEYS[2],{ARGV[1]},ARGV[2]},2}", "2", "key1", "key2", "first", "second"]).then((response) {
      print(response); // 输出: [key1, [key2, [first], second], 2]
    });
  });
}

TLS 支持

import 'package:redis/redis.dart';

void main() async {
  final conn = RedisConnection();
  await conn.connectSecure('localhost', 6379).then((Command command) {
    command.send_object(["AUTH", "username", "password"]).then((var response) {
      print(response);
      command.send_object(["SET", "key", "0"]).then((var response) {
        print(response); // 输出: OK
      });
    });
  });
}

性能测试

import 'package:redis/redis.dart';

void main() async {
  const int N = 200000;
  int start;
  final conn = RedisConnection();
  await conn.connect('localhost', 6379).then((Command command) {
    print("test started, please wait ...");
    start = DateTime.now().millisecondsSinceEpoch;
    command.pipe_start();
    command.send_object(["SET", "test", "0"]);
    for (int i = 1; i <= N; i++) {
      command.send_object(["INCR", "test"]).then((v) {
        if (i != v) throw("wrong received value, we got $v");
      });
    }
    command.send_object(["GET", "test"]).then((v) {
      print(v);
      double diff = (DateTime.now().millisecondsSinceEpoch - start) / 1000.0;
      double perf = N / diff;
      print("$N operations done in $diff s\nperformance $perf/s");
    });
    command.pipe_end();
  });
}

事务支持

示例

import 'package:redis/redis.dart';

void main() async {
  final conn = RedisConnection();
  await conn.connect('localhost', 6379).then((Command command) {
    command.multi().then((Transaction trans) {
      trans.send_object(["SET", "val", "0"]);
      for (int i = 0; i < 200000; ++i) {
        trans.send_object(["INCR", "val"]).then((v) {
          assert(i == v);
        });
      }
      trans.send_object(["GET", "val"]).then((v) {
        print("number is now $v");
      });
      trans.exec();
    });
  });
}

CAS 支持

示例

import 'package:redis/redis.dart';

void main() async {
  final conn = RedisConnection();
  await conn.connect('localhost', 6379).then((Command command) {
    Cas cas = Cas(command);
    cas.watch(["key"], () {
      command.send_object(["GET", "key"]).then((String val) {
        int i = int.parse(val);
        i++;
        cas.multiAndExec((Transaction trans) {
          trans.send_object(["SET", "key", i.toString()]);
        });
      });
    });
  });
}

Unicode 支持

默认情况下,字符串使用 UTF8 编码/解码。每个字符串都会被转换为二进制数组,使用 UTF8 编码。

二进制数据支持

import 'package:redis/redis.dart';

void main() async {
  final conn = RedisConnection();
  Command cmd = await conn.connect('localhost', 6379);
  Command cmd_bin = Command.from(cmd).setParser(RedisParserBulkBinary());
  List<int> d = [1, 2, 3, 4, 5, 6, 7, 8, 9];
  await cmd_bin.send_object(["SET", "key", RedisBulk(d)]);
  var r = await cmd_bin.send_object(["GET", "key"]);
  print(r); // 输出: [1, 2, 3, 4, 5, 6, 7, 8, 9]
}

发布/订阅支持

订阅消息

import 'dart:async';
import 'package:redis/redis.dart';

Future<void> rx() async {
  Command cmd = await RedisConnection().connect('localhost', 6379);
  final pubsub = PubSub(cmd);
  pubsub.subscribe(["monkey"]);
  final stream = pubsub.getStream();
  var streamWithoutErrors = stream.handleError((e) => print("error $e"));
  await for (final msg in streamWithoutErrors) {
    var kind = msg[0];
    var food = msg[2];
    if (kind == "message") {
      print("monkey got ${food}");
      if (food == "cucumber") {
        print("monkey does not like cucumber");
        cmd.get_connection().close();
      }
    } else {
      print("received non-message ${msg}");
    }
  }
}

Future<void> tx() async {
  Command cmd = await RedisConnection().connect('localhost', 6379);
  await cmd.send_object(["PUBLISH", "monkey", "banana"]);
  await cmd.send_object(["PUBLISH", "monkey", "apple"]);
  await cmd.send_object(["PUBLISH", "monkey", "peanut"]);
  await cmd.send_object(["PUBLISH", "monkey", "cucumber"]);
  cmd.get_connection().close();
}

void main() async {
  var frx = rx();
  var ftx = tx();
  await ftx;
  await frx;
}

发送消息

import 'package:redis/redis.dart';

void main() async {
  Command cmd = await RedisConnection().connect('localhost', 6379);
  await cmd.send_object(["PUBLISH", "monkey", "banana"]);
}

待办事项

  • 更好的文档
  • 实现所有“通用命令”的命名命令
  • 更好的错误处理能力
  • 代码拼写检查

变更日志

详见 CHANGELOG.md

希望这些示例和说明能帮助你在 Flutter 项目中使用 redis-dart 插件与 Redis 数据库进行交互。如果有任何问题或需要进一步的帮助,请随时提问!


更多关于Flutter Redis数据库交互插件redis的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter Redis数据库交互插件redis的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


在Flutter中与Redis数据库进行交互,你可以使用redis Dart包,不过需要注意的是,直接在Flutter客户端与Redis服务器通信并不常见,因为Flutter主要用于构建跨平台的移动应用,而Redis通常作为后端服务的一部分。因此,更常见的做法是通过一个后端服务(如Node.js、Dart的Isolate、或使用Flutter后端如Dart VM Service)来处理与Redis的交互,然后Flutter应用通过HTTP或WebSocket与这个后端服务通信。

不过,如果你确实需要在Flutter应用中直接与Redis交互(例如,在开发或测试环境中),你可以尝试使用dart_redis这样的包(尽管它可能不是为Flutter设计的,且可能需要一些调整才能在Flutter环境中运行)。然而,到目前为止,dart_redis包并不活跃维护,并且Flutter社区中通常推荐使用更标准的方法,即通过后端服务间接与Redis交互。

下面是一个假设性的例子,展示如何在Dart环境中(注意,不是直接在Flutter UI线程中)使用redis客户端库(如果有一个活跃的库可用)。请注意,这个例子可能需要大量的调整和适配才能在Flutter中运行,因为Flutter有其特定的平台要求和限制。

// 假设存在一个名为 `redis_client` 的包,它提供了Redis客户端的功能。
// 注意:这样的包可能不存在,或者不是为Flutter设计的。
import 'package:redis_client/redis_client.dart';

void main() async {
  // 创建一个Redis客户端实例
  var client = RedisClient(host: 'localhost', port: 6379);

  // 连接到Redis服务器
  await client.connect();

  // 设置一个键值对
  await client.set('myKey', 'myValue');

  // 获取一个键的值
  var value = await client.get('myKey');
  print('The value of myKey is: $value');

  // 关闭连接
  await client.quit();
}

然而,由于直接在Flutter中使用Redis客户端库通常不是最佳实践,下面是一个更实际的例子,展示如何通过Flutter后端服务(例如使用Dart的HTTP服务器)与Redis交互。

后端服务(Dart HTTP服务器)

import 'dart:io';
import 'package:redis/redis.dart';

void main() async {
  // 创建Redis客户端
  var redis = RedisClient(host: 'localhost', port: 6379);
  await redis.connect();

  // 创建HTTP服务器
  var server = await HttpServer.bind(InternetAddress.anyIPv4, 8080);

  server.listen((HttpRequest request) async {
    var response = request.response;

    if (request.uri.path == '/set') {
      var key = request.uri.queryParameters['key'] ?? '';
      var value = request.uri.queryParameters['value'] ?? '';
      await redis.set(key, value);
      response.write('Key set');
    } else if (request.uri.path == '/get') {
      var key = request.uri.queryParameters['key'] ?? '';
      var value = await redis.get(key);
      response.write('Value: $value');
    } else {
      response.statusCode = HttpStatus.notFound;
      response.write('Not Found');
    }

    await response.close();
  });

  print('Server listening at http://localhost:8080');
}

Flutter前端

import 'package:flutter/material.dart';
import 'dart:convert';
import 'package:http/http.dart' as http;

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Flutter Redis Example'),
        ),
        body: RedisExample(),
      ),
    );
  }
}

class RedisExample extends StatefulWidget {
  @override
  _RedisExampleState createState() => _RedisExampleState();
}

class _RedisExampleState extends State<RedisExample> {
  final _keyController = TextEditingController();
  final _valueController = TextEditingController();
  String _response = '';

  void _setKeyValue() async {
    var response = await http.get(
      Uri.parse('http://localhost:8080/set?key=${_keyController.text}&value=${_valueController.text}'),
    );
    setState(() {
      _response = response.body;
    });
  }

  void _getKeyValue() async {
    var response = await http.get(
      Uri.parse('http://localhost:8080/get?key=${_keyController.text}'),
    );
    setState(() {
      _response = 'Value: ${response.body}';
    });
  }

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(16.0),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: <Widget>[
          TextField(
            controller: _keyController,
            decoration: InputDecoration(labelText: 'Key'),
          ),
          SizedBox(height: 8),
          TextField(
            controller: _valueController,
            decoration: InputDecoration(labelText: 'Value'),
          ),
          SizedBox(height: 16),
          ElevatedButton(
            onPressed: _setKeyValue,
            child: Text('Set Key-Value'),
          ),
          SizedBox(height: 8),
          ElevatedButton(
            onPressed: _getKeyValue,
            child: Text('Get Value'),
          ),
          SizedBox(height: 16),
          Text(_response),
        ],
      ),
    );
  }
}

在这个例子中,Flutter应用通过HTTP请求与Dart后端服务通信,后端服务再与Redis交互。这种方法更符合现代移动应用开发的最佳实践,因为它分离了前端和后端的职责,使得应用更加模块化和易于维护。

回到顶部