Flutter Cassandra数据库连接插件cassandart的使用

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

Flutter Cassandra数据库连接插件cassandart的使用

本文将详细介绍如何在Flutter项目中使用cassandart插件来连接和操作Cassandra数据库。cassandart是一个用于Dart语言的Cassandra客户端库,支持基本的数据类型,并且能够自动检测和连接到性能最佳的节点。

功能简介

  • 该插件可以与Cassandra(包括Elassandra)一起使用。
  • 它能够处理基本的数据类型(目前不支持map类型)。
  • 自动检测并连接到Cassandra集群中的节点。
  • 根据延迟自动选择最佳节点。
  • 使用hint来选择最有可能包含数据的节点。

注意:这是一个实验性的库和协议,请谨慎使用。

如何贡献

在提交PR之前,请先检查并遵循Cassandra的v4版本的线协议规范

示例代码

以下是一个完整的示例代码,展示了如何使用cassandart插件来创建一个Cassandra表、插入数据并进行查询。

import 'dart:convert';

import 'package:cassandart/cassandart.dart';
import 'package:http/http.dart' as http;

void main() async {
  // 创建HTTP客户端
  final hc = http.Client();

  // 连接到Cassandra集群
  final client = await Cluster.connect(
    ['localhost:9042'], // Cassandra集群地址
    authenticator: PasswordAuthenticator('cassandra', 'cassandra'), // 认证信息
  );

  // 创建Keyspace
  await client.execute('CREATE KEYSPACE IF NOT EXISTS foo '
      'WITH REPLICATION = { '
      "'class' : 'NetworkTopologyStrategy', 'DC1' : 2 }");

  // 创建表
  await client.execute(
      'CREATE TABLE IF NOT EXISTS foo.tbl (id text PRIMARY KEY, content TEXT, category TEXT, rankz INT)');

  // 插入数据
  await client.execute(
    'INSERT INTO foo.tbl (id, content, category, rankz) VALUES (:id, :content, :category, :rankz)',
    values: {
      'id': 'cake',
      'category': 'food',
      'rankz': Value.int32(1202),
      'content':
          'Cake is a form of sweet food made from flour, sugar, and other ingredients, that is usually baked.',
    },
    consistency: Consistency.one,
  );

  await client.execute(
    'INSERT INTO foo.tbl (id, content, category, rankz) VALUES (:id, :content, :category, :rankz)',
    values: {
      'id': 'soup',
      'category': 'food',
      'rankz': Value.int32(2011),
      'content':
          'Soup is a primarily liquid food, generally served warm or hot (but may be cool or cold), '
              'that is made by combining ingredients of meat or vegetables with stock, or water. It is not baked.',
    },
    consistency: Consistency.one,
  );

  // 创建Elasticsearch索引
  final rscreate = await hc.put(
    Uri.parse('http://localhost:9200/foo'),
    headers: {
      'content-type': 'application/json',
    },
    body: json.encode({
      'settings': {
        'index': {
          'sort.field': 'rankz',
          'sort.order': 'desc',
          'analysis': {
            'filter': {},
            'analyzer': {
              'ngram_analyzer': {
                'filter': ['lowercase'],
                'tokenizer': 'ngram_tokenizer'
              },
            },
            'tokenizer': {
              'ngram_tokenizer': {
                'type': 'ngram',
                'min_gram': 2,
                'max_gram': 3,
              }
            }
          }
        }
      },
      'mappings': {
        'tbl': {
          // 'discover': '.*',
          'properties': {
            'rankz': {
              'type': 'integer',
              'cql_collection': 'singleton',
            },
            'content': {
              'type': 'text',
              'cql_collection': 'singleton',
              'fields': {
                'keyword': {'type': 'keyword'},
                'ngram': {
                  'type': 'text',
                  'analyzer': 'ngram_analyzer',
//                  'search_analyzer': 'edge_ngram_search_analyzer'
                }
              }
            },
          },
        },
      },
    }),
  );
  print(rscreate.body);

  // 等待1秒
  await Future.delayed(Duration(seconds: 1));

  // 查询Elasticsearch
  final rs =
      await hc.get(Uri.parse('http://localhost:9200/foo/_search?pretty'));
  print(rs.body);

  // 关闭Cassandra客户端
  await client.close();
  // 关闭HTTP客户端
  hc.close();
}

代码解释

  1. 导入依赖

    import 'dart:convert';
    import 'package:cassandart/cassandart.dart';
    import 'package:http/http.dart' as http;
    
  2. 创建HTTP客户端

    final hc = http.Client();
    
  3. 连接到Cassandra集群

    final client = await Cluster.connect(
      ['localhost:9042'],
      authenticator: PasswordAuthenticator('cassandra', 'cassandra'),
    );
    
  4. 创建Keyspace

    await client.execute('CREATE KEYSPACE IF NOT EXISTS foo '
        'WITH REPLICATION = { '
        "'class' : 'NetworkTopologyStrategy', 'DC1' : 2 }");
    
  5. 创建表

    await client.execute(
        'CREATE TABLE IF NOT EXISTS foo.tbl (id text PRIMARY KEY, content TEXT, category TEXT, rankz INT)');
    
  6. 插入数据

    await client.execute(
      'INSERT INTO foo.tbl (id, content, category, rankz) VALUES (:id, :content, :category, :rankz)',
      values: {
        'id': 'cake',
        'category': 'food',
        'rankz': Value.int32(1202),
        'content':
            'Cake is a form of sweet food made from flour, sugar, and other ingredients, that is usually baked.',
      },
      consistency: Consistency.one,
    );
    
  7. 创建Elasticsearch索引

    final rscreate = await hc.put(
      Uri.parse('http://localhost:9200/foo'),
      headers: {
        'content-type': 'application/json',
      },
      body: json.encode({
        'settings': {
          'index': {
            'sort.field': 'rankz',
            'sort.order': 'desc',
            'analysis': {
              'filter': {},
              'analyzer': {
                'ngram_analyzer': {
                  'filter': ['lowercase'],
                  'tokenizer': 'ngram_tokenizer'
                },
              },
              'tokenizer': {
                'ngram_tokenizer': {
                  'type': 'ngram',
                  'min_gram': 2,
                  'max_gram': 3,
                }
              }
            }
          }
        },
        'mappings': {
          'tbl': {
            'properties': {
              'rankz': {
                'type': 'integer',
                'cql_collection': 'singleton',
              },
              'content': {
                'type': 'text',
                'cql_collection': 'singleton',
                'fields': {
                  'keyword': {'type': 'keyword'},
                  'ngram': {
                    'type': 'text',
                    'analyzer': 'ngram_analyzer',
                  }
                }
              },
            },
          },
        },
      }),
    );
    print(rscreate.body);
    
  8. 查询Elasticsearch

    final rs =
        await hc.get(Uri.parse('http://localhost:9200/foo/_search?pretty'));
    print(rs.body);
    
  9. 关闭客户端

    await client.close();
    hc.close();
    

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

1 回复

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


当然,以下是如何在Flutter应用中使用cassandart库与Cassandra数据库进行连接的示例代码。cassandart是一个Dart语言编写的Cassandra客户端库,尽管它主要用于Dart VM环境,但在Flutter应用中通过Isolates进行后台操作也是可以实现的。

请注意,由于Flutter运行在Dart VM的一个子集(Dart 2.x的Flutter引擎)上,直接操作网络或执行阻塞操作(如数据库连接)需要在后台线程(Isolate)中完成。

步骤1:添加依赖

首先,在你的pubspec.yaml文件中添加cassandart依赖。由于cassandart可能不是专门为Flutter设计的,确保你的Flutter项目支持Dart VM功能。

dependencies:
  flutter:
    sdk: flutter
  cassandart: ^x.y.z  # 替换为最新版本号

然后运行flutter pub get来获取依赖。

步骤2:创建一个Isolate与Cassandra连接

由于Flutter UI线程不应该执行阻塞操作,我们将使用Dart的Isolate来执行Cassandra连接和操作。

import 'dart:async';
import 'dart:isolate';
import 'package:cassandart/cassandart.dart';

Future<void> main() async {
  // Flutter应用入口点通常不直接使用main,这里仅作示例
  runZonedGuarded(() {
    runApp(MyApp());
  }, (error, stackTrace) {
    // 错误处理
  });

  // 在后台Isolate中初始化Cassandra连接
  _initializeCassandra();
}

void _initializeCassandra() async {
  ReceivePort receivePort = ReceivePort();
  Isolate.spawnUri(
    Uri.dataFromString('''
      import 'dart:isolate';
      import 'package:cassandart/cassandart.dart';

      void entryPoint(SendPort sendPort) async {
        try {
          var cluster = Cluster.builder()
            ..addContactPoint('127.0.0.1') // Cassandra服务器地址
            ..withPort(9042)
            ..withCredentials('username', 'password') // 用户名和密码
            .build();
          
          var session = await cluster.connect('keyspace_name'); // 连接指定的keyspace
          
          sendPort.send({'status': 'success', 'session': session});
        } catch (e, s) {
          sendPort.send({'status': 'error', 'message': e.toString(), 'stackTrace': s.toString()});
        }
      }
    '''),
    [],
    entryPoint,
    receivePort.sendPort,
  );

  await receivePort.first.then((message) {
    if (message['status'] == 'success') {
      print('Cassandra connection established');
      // 这里可以通过某种机制将session传递给UI线程使用,但通常不推荐在Flutter中直接持有数据库session
      // 考虑使用事件总线(Event Bus)或状态管理库(如Provider, Riverpod等)来管理状态
    } else {
      print('Cassandra connection error: ${message['message']}\nStack Trace: ${message['stackTrace']}');
    }
  });
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Flutter Cassandra Example'),
        ),
        body: Center(
          child: Text('Connecting to Cassandra...'),
        ),
      ),
    );
  }
}

注意事项

  1. Isolate通信:在上面的示例中,我们简单地打印了连接状态。在实际应用中,你可能需要通过某种机制(如事件总线)将Cassandra session或操作结果传递回UI线程。

  2. 资源管理:确保在Flutter应用生命周期结束时正确关闭Cassandra连接以释放资源。

  3. 错误处理:在实际应用中,应该有更健全的错误处理机制,包括重试逻辑和用户通知。

  4. 性能和安全:在移动设备上直接操作数据库可能不是最佳实践,通常建议通过后端服务(如REST API)与数据库交互。

  5. 插件限制:由于cassandart可能不是为Flutter设计的,某些功能可能无法正常工作或需要额外的适配工作。

这个示例提供了一个基本的框架,你可能需要根据自己的需求进行调整和扩展。

回到顶部