Flutter链接MySQL

1. 前言

Flutter官方对两种数据库更加推荐,且为它们提供了更好的支持,分别是
SQLite:一种本地数据库,优点顾名思义,更加轻量化,且对移动设备的支持更好;缺点是无法云上部署并通过IP链接
FireBase:由Google官方提供的NoSQL数据库,向用户提供了非常丰富的API接口,且为多用户聊天提供了很好的原生支持,是制作聊天功能的首选

这里仍然选择MySQL的原因:

  1. 没学过数据库,用老牌数据库学一下常规操作先
  2. 可以云上部署,在自己的服务器上部署特别方便
  3. 在腾讯云服务器上部署规避Google科学上网的限制

2. MySQL 安装 简单配置

Ubuntu 服务器

打开终端用ssh命令行安装还是太麻烦了
直接用宝塔的数据库功能,点添加数据库,填写config就好
更细致的操作,如创建用户、编辑权限、创建表等,点击phpMyAdmin进入php管理页面操作

Windows

在MySQL官网下载安装包后安装

SQL 可视化管理工具

推荐DBeaver,官网下载安装即可
配置简单,界面直观,功能丰富
可以管理云端数据库
支持多种SQL

常用命令

启动:net start mysql 尽量用管理员权限
关闭:net stop mysql
本地链接 mysql -u your_username -p root用户可能不用输入密码
列出所有数据库 SHOW DATABASES;
选择要使用的数据库(进入数据库) USE your_database;
列出此数据库中的所有表 SHOW TABLES;
创建数据库 CREATE DATABASE 数据库名;
创建数据表

1
2
3
4
5
CREATE TABLE table_name (
column1 datatype,
column2 datatype,
...
);

插入数据

1
2
INSERT INTO table_name (column1, column2, column3, ...)
VALUES (value1, value2, value3, ...);

3. Flutter链接MySQL

在pub.dev中,有三种第三方编写的MySQL插件,这里使用的是mysql_client
mysql_client | Dart package (pub.dev)
根据官方页面介绍,这个插件的功能有

  1. 创建链接池
  2. 创建单链接
  3. CRUD操作(插入、删除、查询、修改)
    我们首先编写一个最最简单的Flutter界面,包含两个按钮:尝试链接、插入数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('MySQL Insert Example'),
        ),
        body: Center(
          child: FutureBuilder<void>(
            future: _insertData(),
            builder: (context, snapshot) {
              if (snapshot.connectionState == ConnectionState.done) {
                if (snapshot.hasError) {
                  return Text('Error: ${snapshot.error}');
                } else {
                  return Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: <Widget>[
                      ElevatedButton(
                        onPressed: (),
                        child: Text('Connect to MySQL'),
                      ),
                      SizedBox(height: 20),
                      ElevatedButton(
                        onPressed: (),
                        child: Text('Insert Data'),
                      ),
                    ],
                  );
                }
              } else {
                return CircularProgressIndicator();
              }
            },
          ),
        ),
      ),
    );
  }

}

显而易见,后续的SQL操作需要编写独立的函数放在类里,并在ElevatedButton中的onPressed()里使用,这样点击按钮后执行我们编写的MySQL操作函数

安装包

1
flutter pub add mysql_client

引用包

1
import 'package:mysql_client/mysql_client.dart';

这里给出链接的函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
Future<void> _insertData() async {    //async是异步操作
    try {
      print("Connecting to mysql server...");
      // create connection
      final conn = await MySQLConnection.createConnection( //链接MySQL服务器
        host: "127.0.0.1", //这里链接云端服务器直接改IP就够了
        port: 3306,
        userName: "root",
        password: "",
        databaseName: "test1", // optional
      );
     
      await conn.connect();

      // insert some rows
      var res = await conn.execute(
        "INSERT INTO tabletest1 (name, email, age) VALUES (:name, :email, :age )",
        { //上面这句其实就是MySQL命令行操作语句
          "name": "aaaaa", //这一部分根据表的格式和自己想插入的数据写
          "email": "aaaaa.com",
          "age": 20,
        },
      );

      print(res.affectedRows);

      // close all connections 操作结束后要关闭链接
      await conn.close();
    } catch (e) {

      print('Error: $e');

    }

  }

4. 完整程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
// main.dart
import 'package:flutter/material.dart';
import 'package:mysql_client/mysql_client.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('MySQL Insert Example'),
        ),
        body: Center(
          child: FutureBuilder<void>(
            future: _insertData(),
            builder: (context, snapshot) {
              if (snapshot.connectionState == ConnectionState.done) {
                if (snapshot.hasError) {
                  return Text('Error: ${snapshot.error}');
                } else {
                  return Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: <Widget>[
                      ElevatedButton(
                        onPressed: () => _showSnackbar(context, 'Connected'),
                        child: Text('Connect to MySQL'),
                      ),
                      SizedBox(height: 20),
                      ElevatedButton(
                        onPressed: () => _showSnackbar(context, 'Inserted Data'),
                        child: Text('Insert Data'),
                      ),
                    ],
                  );
                }
              } else {
                return CircularProgressIndicator();
              }
            },
          ),
        ),
      ),
    );
  }

  Future<void> _insertData() async {
    try {
      print("Connecting to mysql server...");
      // create connection
      final conn = await MySQLConnection.createConnection(
        host: "127.0.0.1",
        port: 3306,
        userName: "root",
        password: "",
        databaseName: "test1", // optional
      );
      await conn.connect();
      // insert some rows
      var res = await conn.execute(
        "INSERT INTO tabletest1 (name, email, age) VALUES (:name, :email, :age )",
        {
          "name": "aaaaa",
          "email": "aaaaa.com",
          "age": 20,
        },
      );
     
      print(res.affectedRows);
     
      // close all connections
      await conn.close();
    } catch (e) {
      print('Error: $e');
    }
  }

  void _showSnackbar(BuildContext context, String message) { //APP底部的提示信息
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(content: Text(message)),
    );
  }
}