APP本地数据库简单操作和升级(Android/Flutter)

Android

项目中用到本地数据库存储数据,数据量以及类型比较多而且繁杂,于是乎,就用GreenDao插件来存储了。
先说一下配置情况:
1、工程build.gradle中添加如下:
这里写图片描述

说明:dependencies节点下添加

classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2'

2、Moudle下的build.gradle添加如下:
这里写图片描述

说明:顶部最外层添加:

apply plugin: 'org.greenrobot.greendao'

android节点下添加:

greendao {
        schemaVersion 1//数据库版本号,数据库升级会用到,如果不需要升级,一直为1就好
        daoPackage 'com.thtj.demo.dao'//DaoMaster、DaoSession以及各种实体Dao的生成路径
        targetGenDir 'src/main/java'
    }

dependencies节点下添加:

compile 'org.greenrobot:greendao:3.2.2'

最后Aysnc一下就算完成了。

3、创建实体类表,比如:

import org.greenrobot.greendao.annotation.Entity;
import org.greenrobot.greendao.annotation.Id;
import org.greenrobot.greendao.annotation.Unique;
import org.greenrobot.greendao.annotation.Generated;


@Entity
public class Person {
    @Id
    private Long id;
    @Unique
    private String name;
    private int age;
    private String sex;
    private int salary;
    @Generated(hash = 72938267)
    public Person(Long id, String name, int age, String sex, int salary) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.sex = sex;
        this.salary = salary;
    }
    @Generated(hash = 1024547259)
    public Person() {
    }
    public Long getId() {
        return this.id;
    }
    public void setId(Long id) {
        this.id = id;
    }
    public String getName() {
        return this.name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return this.age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getSex() {
        return this.sex;
    }
    public void setSex(String sex) {
        this.sex = sex;
    }
    public int getSalary() {
        return this.salary;
    }
    public void setSalary(int salary) {
        this.salary = salary;
    }
    
}

声明完属性以后,rebuild一下工程,会自动生成上面的那些get、set等方法,对应的dao包路径下也会生成相应的Dao文件。这些都不需要手动添加,全是rebuild工程之后自动生成的,而且不建议修改。你只需要声明属性(也就是表中的字段)就好。

4、创建MyApplication:

public class MyApplication extends Application {
    private MySQLiteOpenHelper mHelper;
    public static MyApplication instance;

    @Override
    public void onCreate() {
        super.onCreate();
        instance = this;
        setDatabase();
    }

    public static MyApplication getInstances() {
        return instance;
    }

    private void setDatabase() {
        // 注意:默认的 DaoMaster.DevOpenHelper 会在数据库升级时,删除所有的表,意味着这将导致数据的丢失。
        // 在正式的项目中,还应该做一层封装,来实现数据库的安全升级。
        mHelper = new MySQLiteOpenHelper(this, "notes-db", null);
    }

    public DaoSession getDaoSession() {
        return new DaoMaster(mHelper.getWritableDatabase()).newSession();
    }
}

里面有这么一句话:“在正式的项目中,还应该做一层封装,来实现数据库的安全升级”。网上的很多Demo是未封装的。如果你的数据库不需要升级的话,可以直接使用,但是如果你的数据库需要升级的话,显然就不可取了。
因为数据库版本升级的话,会默认先删除所有的表,再重新创建,意味着如果用户之前数据库里已经保存了数据,你这样不作处理,直接修改为schemaVersion2然后打包给用户安装的话,会导致用户之前手机数据库里存的数据全部丢失。下面DaoMater里那两行代码也意味着:删除、重建。
这里写图片描述
所以在升级的时候需要对用户已经保存的数据进行一下处理。
借助于:

compile 'com.github.yuweiguocn:GreenDaoUpgradeHelper:v2.0.1'

工程build.gradle中allprojects节点下的repositories下添加

maven { url "https://jitpack.io" }

github上搜一下就行,当然网上也有很多使用教程。

compile完成之后,创建一个MySQLiteOpenHelper,也就是上面MyApplication中用到的。

public class MySQLiteOpenHelper extends DaoMaster.OpenHelper {
    public MySQLiteOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory) {
        super(context, name, factory);
    }
    @Override
    public void onUpgrade(Database db, int oldVersion, int newVersion) {
        MigrationHelper.migrate(db, new MigrationHelper.ReCreateAllTableListener() {
                    @Override
                    public void onCreateAllTables(Database db, boolean ifNotExists) {
                        DaoMaster.createAllTables(db, ifNotExists);
                    }
                    @Override
                    public void onDropAllTables(Database db, boolean ifExists) {
                        DaoMaster.dropAllTables(db, ifExists);
                    }
                }, PersonDao.class);
    }
}

重写了升级里面的方法,这样就保证了即使数据库添加字段升级了,数据也不会丢失。
上面的PersonDao就是Person这个表新增字段有改动的dao,可以添加多个,比如:

PersonDao.class,MoneyDao.class...

然后就可以使用了,Demo如下:

public class MainActivity extends Activity {
    private TextView tv;
    private String s = "";
    private PersonDao dao = MyApplication.getInstances().getDaoSession().getPersonDao();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv = findViewById(R.id.tv);

        List<Person> personList = dao.loadAll();
        if (personList.size() == 0) {
            for (int i = 0; i < 2; i++) {
                Person p = new Person();
                p.setName("挨踢" + i);
                p.setAge(i);
                p.setSex("男");
                dao.insertOrReplace(p);
            }
            queryData();
        } else {
            queryData();
        }
        tv.setText(s.substring(0, s.length() - 1));

        tv.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Person p = dao.queryBuilder()
                        .where(PersonDao.Properties.Name.eq("挨踢0")).unique();
                if (p != null) {
                    p.setSex("女");
                    dao.insertOrReplace(p);
//                    dao.update(p);//也可以这样,检测到存在都会更新
                }
                queryData();
                tv.setText(s.substring(0, s.length() - 1));
            }
        });
    }

    public void queryData(){
        s = "";
        List<Person> pl = dao.loadAll();
        if (pl != null && pl.size() > 0) {
            for (Person p : pl) {
                s += new GsonBuilder().serializeNulls().create().toJson(p) + ",";
            }
        }
    }
}

插入一条数据常用方法:insert或者insertOrReplace,后者也起到了更新的功能,跟update功能一样,只不过在数据库里的顺序会改变,直接update更新的话,顺序不会改变。关于查询和删除的方法就不多说了,网上很多。

Flutter

flutter借助插件sqflite: ^1.1.6+3来实现。
以模拟创建简单的用户表为例:

import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';

final String tableName = "user"; //表名
final String columnId = "id"; //主键
final String columnUserId = "userId"; //用户唯一标识
final String columnName = "name"; //用户名
final String columnAge = "age"; //年龄
final String columnSex = "sex"; //version:2 新增的性别字段

class User {
  int id;
  int userId;
  String name;
  int age;
  String sex; //version:2 新增的性别字段

  User();

  Map<String, dynamic> toMap() {
    return <String, dynamic>{
      columnId: id,
      columnUserId: userId,
      columnName: name,
      columnAge: age,
      columnSex: sex, //version:2 新增的性别字段
    };
  }

  User.fromMap(Map<String, dynamic> map) {
    id = map[columnId];
    userId = map[columnUserId];
    name = map[columnName];
    age = map[columnAge];
    sex = map[columnSex]; //version:2 新增的性别字段
  }

  @override
  String toString() {
    return 'User{id: $id, userId: $userId, name: $name, age: $age, sex: $sex}';
  }
}

class SqlLite {
  Database db;

  ///创建数据库
  openSqlLite() async {
    var databasesPath = await getDatabasesPath();
    String path = join(databasesPath, "test.db");
    db = await openDatabase(
      path,
      version: 2,
      onCreate: _onCreate,
      onUpgrade: _onUpgrade,
    );
  }

  void _onCreate(db, version) async {
    var batch = db.batch();
    _createTableUser(batch); //可在此创建多个表
    await batch.commit();
  }

  ///创建用户表
  void _createTableUser(batch) {
    batch.execute('''
          create table $tableName (
            $columnId integer primary key,
            $columnUserId integer,
            $columnName text,
            $columnAge integer )
          ''');
  }

  ///升级
  void _onUpgrade(db, oldVersion, newVersion) async {
    print("升级");
    var batch = db.batch();
    if (oldVersion == 1) {
      _updateTableUser(batch); //升级过程中也可以在此创建新表
    }
    await batch.commit();
  }

  ///user表增加性别字段
  void _updateTableUser(batch) {
    batch.execute('alter table $tableName add $columnSex text');
  }

  /// 插入数据
  Future<int> insert(user) async {
    return await db.insert(tableName, user.toMap());
  }

  /// 查询所有数据
  Future<List<User>> queryAll() async {
    List<Map> maps = await db.query(tableName, columns: null);
    if (maps == null || maps.length == 0) {
      return null;
    }
    List<User> users = List();
    for (int i = 0; i < maps.length; i++) {
      users.add(User.fromMap(maps[i]));
    }
    return users;
  }

  ///根据userId查询数据
  Future<User> getUser(userId) async {
    List<Map> maps = await db.query(tableName,
        columns: null, where: '$columnUserId = ?', whereArgs: [userId]);
    if (maps.length > 0) {
      return User.fromMap(maps.first);
    }
    return null;
  }

  /// 删除数据
  Future<int> delete(userId) async {
    return await db
        .delete(tableName, where: '$columnUserId = ?', whereArgs: [userId]);
  }

  /// 更新数据
  Future<int> update(user) async {
    return await db.update(tableName, user.toMap(),
        where: '$columnUserId = ?', whereArgs: [user.userId]);
  }

  /// 关闭数据库
  close() async {
    await db.close();
  }
}

测试用例:

import 'package:flutter/material.dart';

import 'bean/User.dart';
import 'header.dart';

class Home extends StatefulWidget {
  @override
  _HomeState createState() => _HomeState();
}

class _HomeState extends State<Home> with TickerProviderStateMixin {
  SqlLite sqlLite = SqlLite();
  TextEditingController controller = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.white,
      appBar: Header(
        title: "首页",
        backgroundColor: Colors.grey,
      ),
      body: ListView(
        children: <Widget>[
          RaisedButton(
            onPressed: _insertData,
            child: Text("增加数据"),
          ),
          RaisedButton(
            onPressed: _deleteData,
            child: Text("删除数据"),
          ),
          RaisedButton(
            onPressed: _queryData,
            child: Text("修改数据"),
          ),
          RaisedButton(
            onPressed: _queryAll,
            child: Text("查询数据"),
          ),
        ],
      ),
    );
  }

  ///插入数据
  void _insertData() async {
    await sqlLite.openSqlLite();
    User u1 = User();
    u1.userId = 101;
    u1.name = "镜花水月1";
    u1.age = 31;
    await sqlLite.insert(u1);
    User u2 = User();
    u2.userId = 102;
    u2.name = "镜花水月2";
    u2.age = 32;
    await sqlLite.insert(u2);
    await sqlLite.close();
  }

  ///删除数据
  void _deleteData() async {
    await sqlLite.openSqlLite();
    await sqlLite.delete(102);
    await sqlLite.close();
  }

  ///修改数据
  Future _queryData() async {
    await sqlLite.openSqlLite();
    User user = await sqlLite.getUser(101);
    if (user != null) {
      user.name = "flutter";
      await sqlLite.update(user);
    }
    await sqlLite.close();
  }

  ///查询数据
  void _queryAll() async {
    await sqlLite.openSqlLite();
    List<User> users = await sqlLite.queryAll();
    if (users != null) {
      print(users);
    }
    await sqlLite.close();
  }
}
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

尘彦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值