现如今数据库的发展很快,犹如百花齐放
关系型数据库、NoSQL、图数据库、嵌入式数据库……层出不穷
虽然各自应用的场景不同
但无论如何,关系型数据库使用面最广,NoSQL人气最高
Dart SDK中并没有原生的数据库驱动
但是无论是PostgreSQL还是SQLite还是MongoDB,都能找到对于的包
看了一下Pub和Github
不得不说,对数据库支持最好还是PostgreSQL和MongoDB
接下来的几篇帖子会对常用数据库作简单演示
这里说一下MySQL
MySQL应用广泛,资料也很全
MySQL驱动做得比较好的应该是sqljocky
但是Pub中READMI.md的一句话着实让人、、、汗颜
It isn’t finished, but should work for most normal use.
好吧!只能说,正式应用需谨慎
注:
sqljocky只能运行在虚拟机中
不能在浏览器端运行
pubspec.yaml
name: Note19
dependencies:
sqljocky: "^0.14.1"
一般情况下我们并不会在程序中创建数据库
因为大多时候虚拟主机提供的都是固定的数据库
用户并没有创建的权限
另外,删除和新建数据库、表
可以用Drop、Create if not exists命令
如果要查询数据库或表是否存在,可以通过以下sql语句
//查询数据库TempDB是否存在
select count(*) from information_schema.tables where table_schema='tempdb';
//查询数据库TempDB中是否存在Users表
select count(*) from information_schema.tables where table_schema='tempdb' and table_name='users';
main.dart
import 'package:sqljocky/sqljocky.dart';
import 'package:sqljocky/utils.dart';
main() async {
/**
* 连接服务器,host默认'localhost',port默认3306
* 密码为空时,不设置password,数据库名称db可以省略
* 如果权限足够,连接服务器可以新建数据库
*/
print("Opening connection");
var pool = new ConnectionPool(host: 'localhost', port:3306, user:'root');
await pool.query('drop database if exists TempDB');
await pool.query('create database TempDB');
/**
* 新建连接的时候,之前的连接资源并不会自动释放
* 需要调用closeConnectionsWhenNotInUse
* 或closeConnectionsNow
* 如果程序运行结束的时候,进程并没有退出
* 说明资源未及时释放
*/
pool.closeConnectionsNow();
/**
* 新连接刚建的数据库
* 赋值给之前的pool变量
*/
pool = new ConnectionPool(
host: 'localhost', port: 3306, user: 'root', db: 'TempDB');
/**
* 除了ConnectionPool.query
* 在'package:sqljocky/utils.dart'中
* utils提供了两个实用的类用来删除表和执行多条sql语句
*/
print("Drop tables");
await new TableDropper(pool, ['users']).dropTables();
/**
* 也许是出于安全考虑,为了预防SQL攻击
* sqljocky并不支持单个字符串执行多条分号分隔的sql语句
* 如:"'insert into ...; insert into ..."
* 有可能你习惯拼接sql语句,但是
* 程序员不应该执行“删除地球”这样的SQL语句
* 而是写“删除一个行星”,然后将“地球”当作参数传入
* 也就是预处理
* 下面的代码仅仅是演示QueryRunner(ConnectionPool, List)的用法
* 适用于初始化数据库
*/
print("Create tables");
await new QueryRunner(pool, [
'CREATE TABLE users ('
'name varchar(100) NOT NULL,'
'email varchar(100) NOT NULL)',
'INSERT INTO users(name, email) VALUES ("Wang","[email protected]")',
'INSERT INTO users(name, email) VALUES ("Li","[email protected]")'
]).executeQueries();
/**
* 预处理
* 如果仅执行一次sql语句,可使用prepareExecute(sql, list)
* 如果需要执行多次sql语句,可使用executeMulti函数
* 再通过executeMulti(List<List>)传入参数
* 如果sql语句有返回值,可遍历Future<List<Results>>
*/
print('Prepare insert multiLine sql');
var preSql = await pool.prepare(
"insert into users(name, email) values(?, ?)");
await preSql.executeMulti([
['Chen', '[email protected]'],
['Yu', '[email protected]']
]);
/**
* ConnectionPool也提供了执行sql语句的函数
* 如果sql语句有返回值,可遍历Future<Results>
*/
print('Select users');
var results = await pool.query('select * from users');
results.forEach((row) {
print('Name: ${row[0]}, email: ${row[1]}');
});
/**
* 事务处理
* 下面的代码综合了事务处理和预处理
* 代码风格上,并没有用之前的await关键字
* 而是在then中注册回调函数,浓浓的Dart味道
* 这样省了不少临时变量的声明过程
*
* 需要说明的是
* sqljocky中不能通过query('start transaction')开启事务
* 同时,事务处理会保持连接,直到调用commit或者rollback
* 在提交或回滚事务的之后,不能再查询数据,否则会抛出错误
*
* commit和rollback并不会直接释放资源
* 需要在then函数中注册回调函数,调用close函数
* 否则,会进入阻塞状态
*/
print('Transaction start');
pool.startTransaction().then((Transaction trans) {
trans.prepareExecute(
'update users set email=? where name=?',
['[email protected]', 'Yu']).then((_) {
trans.commit().then((_) {
print("Transaction end");
pool.closeConnectionsNow();
});
});
});
/**
* 释放资源
* 由于在上面事务处理的代码中,commit已经释放了资源
* 因此本句代码可以省略
*/
pool.closeConnectionsWhenNotInUse();
}
运行结果:
本文图片资料来源出自“Dart语言中文社区”,允许转载,转载时请务必以超链接形式标明文章原始出处