今天要说的是众所周知的greenddao,之前一直都是手动sql,不仅在操作数据库的时候比较麻烦,而且还容易出错,朋友推荐了greendao这个轻量级的数据库框架。废话不多说,进入正题!

greendao的构建,是参见这篇文章:greenDao构建

还是把这步骤也说一下,方便大家也方便自己。

studio用户添加依赖:

 compile 'de.greenrobot:greendao:1.3.7'
 sourceSets {main {java.srcDirs = ['src/main/java', 'src/main/java-gen']}}

1 .在 .src/main 目录下新建一个与 java 同层级的「java-gen」目录,用于存放由 greenDAO 生成的 Bean、DAO、DaoMaster、DaoSession 等类。

2.新建「GREENDAO GENERATOR」模块 (纯 JAVA 工程)

1)通过 File -> New -> New Module -> Java Library -> 填写相应的包名与类名 -> Finish.(注意此处是javalibrary)

2)在新创建的module的gradle中,配置 daoexamplegenerator 工程的 build.gradle,添加 dependencies.

compile 'de.greenrobot:greendao-generator:1.3.1'

3.编写ExampleDaoGenerator 这个类:

关于这个类的编写,直接上代码,注释详细:

首先贴出main方法:

public static void main(String [] args) throws Exception {//注意导包// 正如你所见的,你创建了一个用于添加实体(Entity)的模式(Schema)对象。// 两个参数分别代表:数据库版本号与自动生成代码的包路径。
//        Schema schema = new Schema(1, "me.itangqi.greendao");
//      当然,如果你愿意,你也可以分别指定生成的 Bean 与 DAO 类所在的目录,只要如下所示:Schema schema = new Schema(2, "me.itangqi.bean"); schema.setDefaultJavaPackageDao("me.itangqi.dao");// 模式(Schema)同时也拥有两个默认的 flags,分别用来标示 entity 是否是 activie 以及是否使用 keep sections。// schema2.enableActiveEntitiesByDefault();// schema2.enableKeepSectionsByDefault();// 一旦你拥有了一个 Schema 对象后,你便可以使用它添加实体(Entities)了。addNote(schema);addPerson(schema);// 最后我们将使用 DAOGenerator 类的 generateAll() 方法自动生成代码,此处你需要根据自己的情况更改输出目录(既之前创建的 java-gen)。// 其实,输出目录的路径可以在 build.gradle 中设置,有兴趣的朋友可以自行搜索,这里就不再详解。new DaoGenerator().generateAll(schema, "D:/StudioProjects/GreenDaoDemo/app/src/main/java-gen");}
private static void addPerson(Schema schema) {Entity person=schema.addEntity("Person");person.addIdProperty();person.addStringProperty("name").notNull();person.addIntProperty("sex");person.addIntProperty("grade");person.addLongProperty("birthTime");person.addIntProperty("age");}
private static void addNote(Schema schema) {// 一个实体(类)就关联到数据库中的一张表,此处表名为「Note」(既类名)Entity note = schema.addEntity("Note");// 你也可以重新给表命名// note.setTableName("NODE");// greenDAO 会自动根据实体类的属性值来创建表字段,并赋予默认值// 接下来你便可以设置表中的字段:note.addIdProperty();note.addStringProperty("text").notNull();// 与在 Java 中使用驼峰命名法不同,默认数据库中的命名是使用大写和下划线来分割单词的。// For example, a property called “creationDate” will become a database column “CREATION_DATE”.note.addStringProperty("comment");note.addDateProperty("date");}

以上方法决定表中字段,以及类型。

在此需要注意的时,在做数据库升级的时候需要修改这里的版本号:

Schema schema = new Schema(2, "me.itangqi.bean"); //数据库这里修改版本号

最后执行此java文件,及可生成对应的xxxDao,xxx实体。

二、CRUD操作:

首先oncreate中初始化:

private void setupDatabase() {// 通过 DaoMaster 的内部类 DevOpenHelper,你可以得到一个便利的 SQLiteOpenHelper 对象。// 可能你已经注意到了,你并不需要去编写「CREATE TABLE」这样的 SQL 语句,因为 greenDAO 已经帮你做了。// 注意:默认的 DaoMaster.DevOpenHelper 会在数据库升级时,删除所有的表,意味着这将导致数据的丢失。// 所以,在正式的项目中,你还应该做一层封装,来实现数据库的安全升级。DaoMaster.DevOpenHelper helper = new DaoMaster.DevOpenHelper(this, "test.db", null);db = helper.getWritableDatabase();// 注意:该数据库连接属于 DaoMaster,所以多个 Session 指的是相同的数据库连接。daoMaster = new DaoMaster(db);daoSession = daoMaster.newSession();}

获取你需要操作的表XXXdao

 daoSession.getPersonDao().insert(person);

下面来说说CRUD方法,以及常用的实现方式:

插入:

private long add(){long age=3000;Person person=new Person(null,"张大",1,age,18);//添加一些对象
//        daoSession.getPersonDao().insertInTx(persons);//添加单个对象
//        daoSession.getPersonDao().insert(person);return daoSession.getPersonDao().insert(person);}

更新:

private void update(){//按照某一条件更新数据Person person = persons.get(persons.size() - 1);person.setName("张大大");daoSession.getPersonDao().update(person);//批量更新/*public void updateBatch(List<Note> notes) throws Exception {daoSession.getNoteDao().updateInTx(notes);}*/}

删除:

private void delete(){//根据条件删除?daoSession.getPersonDao().delete(persons.get(0));Long key = daoSession.getPersonDao().getKey(persons.get(persons.size() - 1));Log.e("key=",""+key);/* //删除全部1daoSession.deleteAll(Person.class);//删除全部2daoSession.getPersonDao().deleteAll();*//*//批量删除public void deleteBatch(List<Person> notes) {daoSession.getNoteDao().deleteInTx(notes);}// 批量按主键删除public void deleteBatchByKey(List<Long> pkIds) {daoSession.getNoteDao().deleteByKeyInTx(pkIds);}*///sql删除
//        daoSession.getDatabase().execSQL(deletesql);}

查询:

 private void query(){//根据条件查询
//        Query<Person> build = daoSession.getPersonDao().queryBuilder()
//                .where(PersonDao.Properties.Sex.eq(1))
//                .build();
//        PersonDao.Properties.Age.gt() 大于  lt小于
//        PersonDao.Properties.Age.ge() 大于等于 le小于等于
//        PersonDao.Properties.Name.eq()
//        PersonDao.Properties.Name.notEq("")//不等于
//        List <Integer> list=new ArrayList<>();
//        list.add(1);
//        list.add(2);
//        PersonDao.Properties.Age.in(list); 查询条件在集合中有
//        PersonDao.Properties.Name.between(1,5);  在某个区间
//        PersonDao.Properties.Name.isNull();  为null
//        PersonDao.Properties.Name.like("%g"); 以g结尾  _g%
//        PersonDao.Properties.Name.primaryKey 判断是否是主键
//        QueryBuilder<Person> builder = daoSession.getPersonDao().queryBuilder();
//        builder.where(PersonDao.Properties.Age.gt(0))
//                .limit(2)//取的条数
//                .offset(0) //开始位置
//                .orderAsc(PersonDao.Properties.Age);//升序
//        List<Person> list = builder.build().list();List<Person> list = daoSession.getPersonDao().queryRaw("where "+PersonDao.Properties.Age.columnName + " >= ? and " + PersonDao.Properties.Sex.columnName + " = ?", new String[]{"2", "0"});
//       daoSession.getDatabase().execSQL();for (Person person:list) {Log.e("条件查询",person.toString());}}

查询全部:

private void queryAll(){//查询全部的第一种方式/*  Query<Person> build = daoSession.getPersonDao().queryBuilder().build();persons.clear();persons.addAll(build.list());for (Person person:persons) {Log.e("查询全部",person.toString());}*///查询全部的第二种方式/*List<Person> p = daoSession.getPersonDao().loadAll();for (Person person:p) {Log.e("查询全部",person.toString());}*///查询全部的第三种方式/*List<Person> p = daoSession.loadAll(Person.class);for (Person person:p) {Log.e("查询全部",person.toString());}*///查询全部的第四种方式List<Person> p = daoSession.queryBuilder(Person.class).build().list();for (Person person:p) {Log.e("查询全部",person.toString());persons.add(person);}}

greendao中没有提供全面的api根据某一条件进行,更新或者删除等,如需要可按照原生的数据库操作方式进行操作:

 daoSession.getDatabase().delete()

三、数据库的升级:

查看DaoMaster中的升级方法,你会发现,在做数据库升级的方法中是删除所有的数据,然后在创建表,那么这样就无疑会导致数据库中的原有数据丢失。

/** * WARNING: Drops all table on Upgrade! Use only during development. */
public static class DevOpenHelper extends OpenHelper {    public DevOpenHelper(Context context, String name, CursorFactory factory) {super(context, name, factory);    }    @Override    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {            Log.i("greenDAO", "Upgrading schema from version " + oldVersion + " to " + newVersion + " by dropping all tables");        dropAllTables(db, true);        onCreate(db);    }
}

在网上查看了一些提供的数据库升级方法,感觉都是很复杂或者不可用,下面介绍一种可用简单的数据库升级方式,此方法也是墙外找的,嘿嘿,还是拿来主义,其思路与一般数据库升级也一样,创建一个临时的表,将原来的数据保存到临时的表中,在删除原来的表,创建新表把临时表中的数据迁移到新的结构表中,删除临时表的过程。下面首先看看一个辅助类MigrationHelper:

package com.choe.greendaodemo.utils;import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.text.TextUtils;
import android.util.Log;import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;import de.greenrobot.dao.AbstractDao;
import de.greenrobot.dao.internal.DaoConfig;
import me.itangqi.dao.DaoMaster;/*** Created by cyk */
public class MigrationHelper {private static final String CONVERSION_CLASS_NOT_FOUND_EXCEPTION = "MIGRATION HELPER - CLASS DOESN'T MATCH WITH THE CURRENT PARAMETERS";private static MigrationHelper instance;public static MigrationHelper getInstance() {if(instance == null) {instance = new MigrationHelper();}return instance;}public void migrate(SQLiteDatabase db, Class<? extends AbstractDao<?, ?>>... daoClasses) {generateTempTables(db, daoClasses);DaoMaster.dropAllTables(db, true);DaoMaster.createAllTables(db, false);restoreData(db, daoClasses);}/*** 生成临时列表* @param db* @param daoClasses*/private void generateTempTables(SQLiteDatabase db, Class<? extends AbstractDao<?, ?>>... daoClasses) {for(int i = 0; i < daoClasses.length; i++) {DaoConfig daoConfig = new DaoConfig(db, daoClasses[i]);String divider = "";String tableName = daoConfig.tablename;String tempTableName = daoConfig.tablename.concat("_TEMP");ArrayList<String> properties = new ArrayList<>();StringBuilder createTableStringBuilder = new StringBuilder();createTableStringBuilder.append("CREATE TABLE ").append(tempTableName).append(" (");for(int j = 0; j < daoConfig.properties.length; j++) {String columnName = daoConfig.properties[j].columnName;if(getColumns(db, tableName).contains(columnName)) {properties.add(columnName);String type = null;try {type = getTypeByClass(daoConfig.properties[j].type);} catch (Exception exception) {exception.printStackTrace();}createTableStringBuilder.append(divider).append(columnName).append(" ").append(type);if(daoConfig.properties[j].primaryKey) {createTableStringBuilder.append(" PRIMARY KEY");}divider = ",";}}createTableStringBuilder.append(");");db.execSQL(createTableStringBuilder.toString());StringBuilder insertTableStringBuilder = new StringBuilder();insertTableStringBuilder.append("INSERT INTO ").append(tempTableName).append(" (");insertTableStringBuilder.append(TextUtils.join(",", properties));insertTableStringBuilder.append(") SELECT ");insertTableStringBuilder.append(TextUtils.join(",", properties));insertTableStringBuilder.append(" FROM ").append(tableName).append(";");db.execSQL(insertTableStringBuilder.toString());}}/*** 存储新的数据库表 以及数据* @param db* @param daoClasses*/private void restoreData(SQLiteDatabase db, Class<? extends AbstractDao<?, ?>>... daoClasses) {for(int i = 0; i < daoClasses.length; i++) {DaoConfig daoConfig = new DaoConfig(db, daoClasses[i]);String tableName = daoConfig.tablename;String tempTableName = daoConfig.tablename.concat("_TEMP");ArrayList<String> properties = new ArrayList();for (int j = 0; j < daoConfig.properties.length; j++) {String columnName = daoConfig.properties[j].columnName;if(getColumns(db, tempTableName).contains(columnName)) {properties.add(columnName);}}StringBuilder insertTableStringBuilder = new StringBuilder();insertTableStringBuilder.append("INSERT INTO ").append(tableName).append(" (");insertTableStringBuilder.append(TextUtils.join(",", properties));insertTableStringBuilder.append(") SELECT ");insertTableStringBuilder.append(TextUtils.join(",", properties));insertTableStringBuilder.append(" FROM ").append(tempTableName).append(";");StringBuilder dropTableStringBuilder = new StringBuilder();dropTableStringBuilder.append("DROP TABLE ").append(tempTableName);db.execSQL(insertTableStringBuilder.toString());db.execSQL(dropTableStringBuilder.toString());}}private String getTypeByClass(Class<?> type) throws Exception {if(type.equals(String.class)) {return "TEXT";}if(type.equals(Long.class) || type.equals(Integer.class) || type.equals(long.class)) {return "INTEGER";}if(type.equals(Boolean.class)) {return "BOOLEAN";}Exception exception = new Exception(CONVERSION_CLASS_NOT_FOUND_EXCEPTION.concat(" - Class: ").concat(type.toString()));exception.printStackTrace();throw exception;}private static List<String> getColumns(SQLiteDatabase db, String tableName) {List<String> columns = new ArrayList<>();Cursor cursor = null;try {cursor = db.rawQuery("SELECT * FROM " + tableName + " limit 1", null);if (cursor != null) {columns = new ArrayList<>(Arrays.asList(cursor.getColumnNames()));}} catch (Exception e) {Log.v(tableName, e.getMessage(), e);e.printStackTrace();} finally {if (cursor != null)cursor.close();}return columns;}
}

然后在DaoMaster中进行调用:

@Overridepublic void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {Log.i("greenDAO", "Upgrading schema from version " + oldVersion + " to " + newVersion + " by migrating all tables data");MigrationHelper.getInstance().migrate(db,UserDao.class,ItemDao.class);}

这样就完成了数据库的升级以及数据的迁移。这种方式是不是很简单粗暴? 但在做数据库升级的时候有几点需要注意,第一点也是上文中提到的需要修改数据库的版本号,然后重新运行gernerator这个java类,重新构建实体、构造方法等。第二因为每次运行gernerator方法,都会删除之前实体和dao文件,因此为了不影响app的使用,还需要自行手动的添加一个之前表格式的构造(如果你之前是按照构造方法创建实体的话)。第三,即使数据库表结构没有变动的表最好也在migrate中传进去,因为有人说会出现一些你想不到的错误,博主也没测试过!虽然理论上不会产生错误,但还是为了保险起见,都做一个变化吧!

最后最重要的一点是,修改onUpgrade方法中的代码,否则之前所做的都会前功尽弃,如果这样上线的话,还会导致数据的丢失。这点切记!!!

忘了说了,此处代码都是写在activity中,但博主建议写在application中!

Demo下载地址:

greendao测试代码

GreenDao使用CRUD及数据库结构升级相关推荐

  1. Code First 下自动更新数据库结构(Automatic Migrations)

    示例 Web.config <?xml version="1.0" encoding="utf-8"?> <configuration> ...

  2. 用 Flask 来写个轻博客 (8) — (M)VC_Alembic 管理数据库结构的升级和降级

    Blog 项目源码:https://github.com/JmilkFan/JmilkFan-s-Blog 目录 目录 前文列表 扩展阅读 Alembic 查看指令 manager db 的可用选项 ...

  3. Android版本升级同时Sqlite数据库的升级及之前数据的保留-转

    http://www.cnblogs.com/wang340/archive/2013/05/06/3063135.html http://www.eoeandroid.com/forum.php?m ...

  4. XTTS,又一个值得你重视的Oracle数据库迁移升级利器

    嘉宾简介 杨志洪 [DBA+社群]上海发起人 数据管理专家.Oracle ACE.OCM. SHOUG/ZJOUG核心成员.DAMA会员/CCF会员,译著<Oracle核心技术>. 在Or ...

  5. Pre-Upgrade Utility---下载并运行Oracle数据库预升级实用程序 (文档 ID 1577379.1)

    如何下载并运行Oracle数据库预升级实用程序 (文档 ID 1577379.1) 文档内容 目标 脚本来源 解决方案 脚本指导 下载并安装说明 请参阅下表以确定您需要的pre-upgrade脚本的版 ...

  6. 1. 设计数据库结构

    这个Golang后端大师班中,我们将学习如何使用Golang.PostgreSQL和Docker从头开始设计.开发和部署一个完整的后端. 课程包括: 设计数据库模式并从中自动生成 SQL 代码 深入了 ...

  7. 数据库结构比对,再初始数据比对方法

    在公司项目中,我有幸负责制作"升级脚本".升级脚本,无疑两步,先结构比对,再初始数据比对. 一.结构比对 结构比对比较简单,使用navicat for mysql 工具," ...

  8. 魔兽私服服务端 MANGOS 数据库结构表中文解释

    MANGOS 数据库结构表 ============================================= achievement_reward              巫妖王的奖励成就 ...

  9. GreenDao3.2.2集成使用以及数据库的升级

    GreenDao3.2.2集成使用以及数据库的升级 一概念      是一个将对象映射到 SQLite 数据库中的轻量且快速的 ORM 解决方案.                            ...

最新文章

  1. 小冰拉开人生第二幕:AI时代的“Office”问世,你的虚拟男友“复活”了
  2. LeSS is More - 大规模敏捷开发框架LeSS实践(一)
  3. MikroTik RouterOS获取在线终端和在线IP总数并自动对IP做限速(转)
  4. 英语影视台词---八、the shawshank redemption
  5. 公众号新上线微信小游戏(疯狂猜图)
  6. 密码学笔记——eval(function(p,a,c,k,e,d) 加密破解
  7. 1. K近邻算法(KNN)
  8. php表格位于页面中央,怎么为表格所在的页面添加编辑限制保护
  9. 华为开发者大会鸿蒙2.0系统,鸿蒙2.0来了!华为开发者大会HDC 2020宣布
  10. 关于微信和微信小程序
  11. Linux虚拟机挂载新的硬盘
  12. scanf的用法大全
  13. 【转载】 mybatis入门系列四之动态SQL
  14. KGB知识图谱深入挖掘金融行业的知识关联
  15. QNX 7.1 交叉编译 boost 1.76
  16. 香港美国CERA机房你怎么选择?
  17. sencha touch 相机,相册调用
  18. 通用计算机的发展历程是巨型机大型机小型机,计组1——计算机系统概述
  19. 汪国真:只要热爱生命,一切都在意料之中
  20. STM32入门笔记——GPIO的初始化

热门文章

  1. 基于springBoot的开源运维监控工具——WGCLOUD
  2. 蓝牙权限管理android,基于蓝牙与Android设备的控制系统设计
  3. 框架学习——带你了解SpringBoot框架
  4. 《AANet: Adaptive Aggregation Network for Efficient Stereo Matching》
  5. SCAU 9502 ARDF
  6. c语言程序设计答案第6章,C语言程序设计答案(黄保和编)第6章
  7. 蒙特利尔大学工学院流程
  8. 无稳态多谐振荡器分析
  9. 2021年量子计算机奖,2021美国天才奖公布获奖名单!
  10. 第一章 信息安全的基本元素