现在市面上主流的框架有 OrmLite、SugarORM、Active Android、Realm 与 GreenDAO。

官网上的介绍,greenDAO 是一个将对象映射到 SQLite 数据库中的轻量且快速的 ORM 解决方案。

GreenDao特点

性能最大化,可能是Android平台上最快的ORM框架 
易于使用的API 
最小的内存开销 
依赖体积小 
支持数据库加密 
强大的社区支持

GreenDao配置

// In your root build.gradle file:
buildscript {repositories {google()jcenter()}dependencies {classpath 'com.android.tools.build:gradle:3.2.0'classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2' // add plugin}
}// In your app projects build.gradle file:
apply plugin: 'com.android.application'
apply plugin: 'org.greenrobot.greendao' // apply plugindependencies {implementation 'org.greenrobot:greendao:3.2.2' // add library
}

实体类:

实体类,不需要自己写get和set方法,在生成表的时候会自动生成。不要忘了在类名上标记@Entity注解

/***  * Created by zhanke on 2019/3/1 0009.* <p>*/
@Entity //@Entity 将我们的java普通类变为一个能够被greenDAO识别的数据库类型的实体类
public class User {//@Id:主键,通过这个注解标记的字段必须是Long类型的,这个字段在数据库中表示它就是主键,并且它默认就是自增的@Id(autoincrement = true)private Long id;@NotNull// @NotNull 设置数据库表当前列不能为空@Unique//唯一private String name;//@Property:设置一个非默认关系映射所对应的列名,默认是使用字段名,例如:@Property(nameInDb = "name")@Property(nameInDb = "userage")private int age;//@Transient:表明这个字段不会被写入数据库,只是作为一个普通的java类字段,用来临时存储数据的,不会被持久化@Transientprivate String like;
}

@Entity:告诉GreenDao该对象为实体,只有被@Entity注释的Bean类才能被dao类操作

@Id:对象的Id,使用Long类型作为EntityId,否则会报错。(autoincrement = true)表示主键会自增,如果false就会使用旧值 。

@Property:可以自定义字段名,注意外键不能使用该属性

@NotNull:属性不能为空 @Transient:使用该注释的属性不会被存入数据库的字段中

@Unique:该属性值必须在数据库中是唯一值

@Generated:编译后自动生成的构造函数、方法等的注释,提示构造函数、方法等不能被修改

写好实体类之后Make Project 重新编译

初始化GreenDao

public class CustomApplication extends Application {public static final String DB_NAME = "app.db";private static DaoSession mDaoSession;@Overridepublic void onCreate() {super.onCreate();initGreenDao();}private void initGreenDao() {DaoMaster.DevOpenHelper helper = new DaoMaster.DevOpenHelper(this, DB_NAME);SQLiteDatabase db = helper.getWritableDatabase();DaoMaster daoMaster = new DaoMaster(db);mDaoSession = daoMaster.newSession();}public static DaoSession getmDaoSession() {return mDaoSession;}
}

添加数据

注意:Long型id,如果传入null,则GreenDao会默认设置自增长的值。

insert(User entity):插入一条记录, 当指定主键在表中存在时会发生异常

添加一条数据

CustomApplication.getmDaoSession().getUserDao().insert(user);

insertOrReplace(User entity) :当指定主键在表中存在时会覆盖数据,有该数据时则更新

save(User entity):

使用数据库插入数据时,使用insert会因为key值(通常是id)重复的异常。我们当然想通过一个简单的方法:有该数据时则更新,没有该数据时则插入的“有更无插”的方法,在GreenDao有两个方insertOrReplace和save,可两者时有区别的:

结论

insertOrReplace : 传入的对象在数据库中,有则更新无则插入。推荐同步数据库时使用该方法。

save 类似于insertOrReplace,区别在于save会判断传入对象的key,有key的对象执行更新,无key的执行插入。当对象有key但并不在数据库时会执行失败.适用于保存本地列表。

//key为null,插入
User user = new User(null, "xyh" , 120, "篮球");

//key不为null,在数据库中有该key执行更新,在数据无无该key,不插入不更新
User user = new User(21l, "xyh333" , 120, "篮球");

save源码

public void save(T entity) {
        if (hasKey(entity)) {
            update(entity);
        } else {
            insert(entity);
        }
    }

在确保插入数据有key时必须存在于数据库的情况下,适用save更高效。其他情况一律适用insertOrReplace

其他一些插入方法

insertInTx(T... entities):使用事务在数据库中插入给定的实体。
insertInTx(Iterable<T> entities):使用事务操作,将给定的实体集合插入数据库。
insertInTx(Iterable<T> entities, boolean setPrimaryKey):使用事务操作,将给定的实体集合插入数据库,并设置是否设定主键 。

insertOrReplaceInTx(T... entities):使用事务操作,将给定的实体插入数据库,若此实体类存在,则覆盖
insertOrReplaceInTx(Iterable<T> entities):使用事务操作,将给定的实体插入数据库,若此实体类存在,则覆盖 。
insertOrReplaceInTx(Iterable<T> entities, boolean setPrimaryKey):使用事务操作,将给定的实体插入数据库,若此实体类存在,则覆盖,并设置是否设定主键 。
insertWithoutSettingPk(T entity):将给定的实体插入数据库,但不设定主键。

// 新增数据插入相关API
save(T entity):将给定的实体插入数据库
saveInTx(Iterable<T> entities):将给定的实体集合插入数据库
saveInTx(T... entities):使用事务操作,将给定的实体插入数据库

查询

//查询全部

mUserDao.loadAll();

//根据主键获取对象,也就是通过id获取

mUserDao.load(Long key)

//根据行号查找数据

mUserDao.loadByRowId(long rowId)

条件查询

//查询全部
List<User> list = mUserDao.queryBuilder().list();

//查询 name等于xyh8的数据
List<User> list= mUserDao.queryBuilder().where(UserDao.Properties.Name.eq("xyh8")).list();

//查询 name不等于xyh8的数据
List<User> list= mUserDao.queryBuilder().where(UserDao.Properties.Name.notEq("xyh8")).list();

//like  模糊查询
//查询 name以xyh3开头的数据
List<User> list = mUserDao.queryBuilder().where(UserDao.Properties.Name.like("xyh3%")).list();

//between 区间查询 年龄在20到30之间
 List<User> list = mUserDao.queryBuilder().where(UserDao.Properties.Age.between(20,30)).list();

//gt: greater than 半开区间查询,年龄大于18
List<User> list = mUserDao.queryBuilder().where(UserDao.Properties.Age.gt(18)).list();

//ge: greater equal 半封闭区间查询,年龄大于或者等于18
List<User> list = mUserDao.queryBuilder().where(UserDao.Properties.Age.ge(18)).list();

//lt: less than 半开区间查询,年龄小于18
List<User> list = mUserDao.queryBuilder().where(UserDao.Properties.Age.lt(18)).list();

//le: less equal 半封闭区间查询,年龄小于或者等于18
List<User> list = mUserDao.queryBuilder().where(UserDao.Properties.Age.le(18)).list();

//排序

//名字以xyh8开头,年龄升序排序
 List<User> list = mUserDao.queryBuilder()
                .where(UserDao.Properties.Name.like("xyh8%"))
                .orderAsc(UserDao.Properties.Age)
                .list();

//名字以xyh8开头,年龄降序排序
 List<User> list = mUserDao.queryBuilder()
                .where(UserDao.Properties.Name.like("xyh8%"))
                .orderDesc(UserDao.Properties.Age)
                .list();

更新

update(T entity) :更新给定的实体

updateInTx(Iterable<T> entities) :使用事务操作,更新给定的实体

updateInTx(T... entities):使用事务操作,更新给定的实体

案例:
User user = mUserDao.load(2L);

user.setAge(2000);

mUserDao.update(user);

也可以用insertOrReplace()更新数据,但key必须在数据可存在,否则就是插入新数据。

User user = new User(5L, "ty", 250, "qq");

mUserDao.insertOrReplace(user);

删除

//删除全部
 mUserDao.deleteAll();

delete(T entity):从数据库中删除给定的实体

deleteByKey(K key):从数据库中删除给定Key所对应的实体

deleteInTx(T... entities):使用事务操作删除数据库中给定的实体

deleteInTx(<T> entities):使用事务操作删除数据库中给定实体集合中的实体

deleteByKeyInTx(K... keys):使用事务操作删除数据库中给定的所有key所对应的实体

deleteByKeyInTx(Iterable<K> keys):使用事务操作删除数据库中给定的所有key所对应的实体

封装

DaoManager

/***  * Created by zhanke on 2019/3/1 0010.*  */public class DaoManager {private Context mContext;//创建数据库的名字private static final String DB_NAME = "MyGreenDb.db";//多线程中要被共享的使用volatile关键字修饰  GreenDao管理类private volatile static DaoManager mInstance;//它里边实际上是保存数据库的对象private static DaoMaster mDaoMaster;//创建数据库的工具private static DaoMaster.DevOpenHelper mHelper;//管理gen里生成的所有的Dao对象里边带有基本的增删改查的方法private static DaoSession mDaoSession;private DaoManager() {}/***  单例模式获得操作数据库对象*  @return   */public static DaoManager getInstance() {if (mInstance == null) {synchronized (DaoManager.class) {if (mInstance == null) {mInstance = new DaoManager();}}}return mInstance;}/***  初始化上下文创建数据库的时候使用   */public void init(Context context) {this.mContext = context;}/*** 判断是否有存在数据库,如果没有则创建** @return      */public DaoMaster getDaoMaster() {if (mDaoMaster == null) {mHelper = new DaoMaster.DevOpenHelper(mContext, DB_NAME, null);mDaoMaster = new DaoMaster(mHelper.getWritableDatabase());}return mDaoMaster;}/*** 完成对数据库的添加、删除、修改、查询操作,** @return      */public DaoSession getDaoSession() {if (mDaoSession == null) {if (mDaoMaster == null) {mDaoMaster = getDaoMaster();}mDaoSession = mDaoMaster.newSession();}return mDaoSession;}/*** 关闭所有的操作,数据库开启后,使用完毕要关闭 */public void closeConnection() {closeHelper();closeDaoSession();}public void closeHelper() {if (mHelper != null) {mHelper.close();mHelper = null;}}public void closeDaoSession() {if (mDaoSession != null) {mDaoSession.clear();mDaoSession = null;}}
}

AbstractDao

所有的自动生成的XXDao都是继承于AbstractDao,此类中基本上封装了所有的增删改操作,包括数据库的事务操作。

QueryBuilder

GreenDao中,使用QueryBuilder自定义查询实体,而不是再写繁琐的SQL语句,避免了SQL语句的出错率。大家都知道写SQL语句时,非常容易出错,出错后又十分的难查。QueryBuilder真是帮忙解决了一个大麻烦。具体该如何使用呢?

数据库升级

比如需要在实体类加一个字段 或者 改变字段属性等 就需要版本更新来保存以前的数据了;

思路

创建临时表–>删除原表–>创建新表–>复制临时表数据到新表并删除临时表;这样数据库表的更新就完成了

MigrationHelper:国外大神写的数据库升级帮助类

/*** 数据库升级帮助类* Created by zhanke on 2019/3/1 0010.*  */
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(Database 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(Database 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(Database 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 List<String> getColumns(Database 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;}
}

1.由于升级数据库需要在DevOpenHelper类的onUpgrade()方法里面继续,因此我们需要自定义一个类继承DevOpenHelper重写onUpgrade()方法

/*** 自定义  MySQLiteOpenHelper继承DaoMaster.OpenHelper 重写更新数据库的方法* 当app下的build.gradle  的schemaVersion数据库的版本号改变时,创建数据库会调用onUpgrade更细数据库的方法* Created by zhanke on 2019/3/1 0010.*  */public class MyDevOpenHelper extends DaoMaster.DevOpenHelper {public MyDevOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory) {super(context, name, factory);}/*** 数据库升级** @param db* @param oldVersion* @param newVersion      */@Overridepublic void onUpgrade(Database db, int oldVersion, int newVersion) {//super.onUpgrade(db, oldVersion, newVersion);//操作数据库的更新 有几个表升级都可以传入到下面MigrationHelper.getInstance().migrate(db, UserDao.class);}
}

2.修改在项目根目录build.gradle文件中配置的数据库版本号(新版本号一定要比老版本大)

greendao {
        schemaVersion 2//数据库版本号
        daoPackage 'com.xiaoyehai.landsurvey.greendao'//设置DaoMaster、DaoSession、Dao包名
        targetGenDir 'src/main/java'//设置DaoMaster、DaoSession、Dao目录
        //targetGenDirTest:设置生成单元测试目录
        //generateTests:设置自动生成单元测试用例
    }

3.初始化GreenDao

private void initGreenDao() {MyDevOpenHelper helper = new MyDevOpenHelper(this, DB_NAME, null);SQLiteDatabase db = helper.getWritableDatabase();DaoMaster daoMaster = new DaoMaster(db);mDaoSession = daoMaster.newSession();
}

4.bean类新增加一个address字段

/***  * Created by zhanke on 2018/8/9 0009.* <p>*  */
@Entity //@Entity 将我们的java普通类变为一个能够被greenDAO识别的数据库类型的实体类
public class User {//@Id:主键,通过这个注解标记的字段必须是Long类型的,这个字段在数据库中表示它就是主键,并且它默认就是自增的@Id(autoincrement = true)private Long id;@NotNull// @NotNull 设置数据库表当前列不能为空@Unique//唯一private String name;//@Property:设置一个非默认关系映射所对应的列名,默认是使用字段名,例如:@Property(nameInDb = "name")@Property(nameInDb = "userage")private int age;//@Transient:表明这个字段不会被写入数据库,只是作为一个普通的java类字段,用来临时存储数据的,不会被持久化@Transientprivate String like;@Property(nameInDb = "address")private String address;  //新增字段
}

新增的字段不能为空

我们新增加的和修改的字段做好为String类型,避免字段不能为null的情况发生

对数据库进行加密

添加依赖

implementation "net.zetetic:android-database-sqlcipher:3.5.2"

DaoMaster.DevOpenHelper a = new DaoMaster.DevOpenHelper(this,"database_name",null);
try {
       daoSession = new DaoMaster(a.getEncryptedWritableDb(MY_PWD)).newSession();
       daoSession.getUserDao().insert(man1);

}catch (Exception e){
      Log.d("e", String.valueOf(e));
}

Android GreenDao简单使用相关推荐

  1. Android GreenDao框架使用 基础篇

    参考 官方文档 Github 一.准备工作 在工程的build.gradle文件中添加 repositories {...mavenCentral()}dependencies {...classpa ...

  2. Android Studio简单设置

    2019独角兽企业重金招聘Python工程师标准>>> Android Studio 简单设置 界面设置 默认的 Android Studio 为灰色界面,可以选择使用炫酷的黑色界面 ...

  3. 简单Android手机APP地图,android最简单手机地图APP(只需5分钟)

    android最简单手机地图APP--只有三部分. 第一部分 首先建立一个MapActivity在setContentView(R.layout.activity_map);中创建一个代码如下. [h ...

  4. android仿微信的activity平滑水平切换动画,Android实现简单底部导航栏 Android仿微信滑动切换效果...

    Android实现简单底部导航栏 Android仿微信滑动切换效果 发布时间:2020-10-09 19:48:00 来源:脚本之家 阅读:96 作者:丶白泽 Android仿微信滑动切换最终实现效果 ...

  5. 【转】Android Studio简单设置

    原文网址:http://ask.android-studio.org/?/article/14 Android Studio 简单设置 界面设置 默认的 Android Studio 为灰色界面,可以 ...

  6. Android JNI简单实例(android 调用C/C++代码)

    转载自 xiechengfa 最终编辑 xiechengfa Android JNI简单实例关键字: android.jni Android的jni实例 android 的应用程序(Dalvik VM ...

  7. android Glide简单使用

    今天,简单讲讲Android里Glide的简单使用. Android框架系列: 一.android EventBus的简单使用 二.android Glide简单使用 对于Glide这个加载图片的框架 ...

  8. android加法服务类,iOS越来越像Android:苹果简单做加法远离精致

    原标题:iOS越来越像Android:苹果简单做加法远离精致 刚刚结束的WWDC2016的主题演讲中,苹果为我们带来了最新的iOS 10系统,官方称本次iOS 10的推出有着多大10项的重要更新,在用 ...

  9. android平台的计时功能,Android实现简单计时器功能

    本文实例为大家分享了Android实现简单计时器的具体代码,供大家参考,具体内容如下 布局 在res/layout 下进行布局 xmlns:android="http://schemas.a ...

最新文章

  1. 记一次MySQL AUTO_INCREMENT的故障
  2. linux系统取消自检,[转载]取消Linux启动自检
  3. 教你使用百度深度学习框架PaddlePaddle完成波士顿房价预测(新手向)
  4. php去除数组中的第一个元素,php如何删除数组的第一个元素和最后一个元素
  5. 绿盟科技发布OpenSSL高危漏洞技术分析与防护方案 G20成员国美国、中国、德国受影响较大...
  6. Java Spring DI之旅
  7. winform datagridview 打印
  8. 【GitLab】CentOS安装GitLab最佳实践
  9. python第四课知识点总结
  10. Python中使用tarfile压缩、解压tar归档文件
  11. Python 学习第一周
  12. 怎么判断间隙过渡过盈配合_什么是间隙配合、过盈配合、过渡配合?它们在汽车上有哪些应用?...
  13. 404终结者——IPFS新引擎Filenet
  14. WPS加载项部署运行问题排查方法
  15. 快速合并所有txt文档
  16. 计算机软件企业的税收,2018年软件企业增值税税收政策梳理
  17. 基于JAVA汽车客运站票务管理系统计算机毕业设计源码+数据库+lw文档+系统+部署
  18. 简单工厂、工厂方法、抽象工厂区别
  19. 市面所有机器人框架开源啦(含VX框架源码)
  20. matlab解韩信点兵问题,2019事业单位:巧解“韩信点兵”问题

热门文章

  1. CPU,核心,线程,超线程技术以及它们之间的关系
  2. App获取android分辨率,Android 获取手机及APP信息实例详解
  3. 航电oj:18岁生日
  4. 苹果电脑MacOS连接使用移动硬盘
  5. 假日管理功能和放假通知
  6. 讯鸟启通宝业务的考虑
  7. 使用驱动器中J:的光盘之前需要将其格式化
  8. 第五课: 图像的 BLOB 分析处理几何变换(union_adjacent_contours_xld)--find_pads.hdev,count_pellets.hdev
  9. 在单链表上实现插入排序
  10. Python 局部变量global,全局变量local ,非局部变量nonlocal ,Enclosing function locals作用域