Android GreenDao 3.2.2的详解以及实战(附Demo)

Android GreenDao 3.2.2的详解以及实战(附Demo)_第1张图片

马上过年了,近期不是很忙,总结一篇关于GreenDao的详解文章
greenDAO增删改查在不同情况下的应用,以及模拟离线和线上的数据存储
结尾附有Demo以及下载地址

GreenDao

官网简介:

       greenDAO is an open source library for Android providing an easy-to-use interface to SQLite to help developers handle data efficiently – relieving developers from dealing with low-level database stuff and saving development time. SQLite is an awesome embedded relational database. Still, writing SQL and parsing query results are quite tedious and time-consuming tasks. greenDAO frees you from these by mapping Java objects to database tables (often called ORM). This way you can store, update, delete, and query for Java objects using a simple object oriented API.
————————————————
       greenDAO是一款开放源代码的Android ORM,使SQLite数据库的开发变得有趣。它减轻开发人员处理低级数据库需求,同时节省开发时间。SQLite是一个令人敬畏的嵌入式关系数据库。不过,编写SQL和解析查询结果是相当乏味和耗时的任务。通过将Java对象映射到数据库表(称为ORM “对象/关系映射”),greenDAO可以将它们从这些映射释放出来。这样,您可以使用简单的面向对象的API来存储,更新,删除和查询Java对象。

Android GreenDao 3.2.2的详解以及实战(附Demo)_第2张图片

GreenDao的功能

  • 一个精简的库
  • 性能最大化
  • 内存开销最小化
  • 易于使用的 APIs
  • 对 Android 进行高度优化
  • 2.2版本以上还支持加密数据库
  • 支持protobuf协议存储(protobuf 比json更快,google的优秀产品,因此greendao能很好地与retrofit 2.0结合protobuf网络请求并缓存)

GreenDao的主要特点

  • 性能远胜于ORMLite ActiveAndroid Xutils等
  • greendao是两级数据库,分为持久的内存sqlite数据库与内存数据库,如果频繁操作数据库的话,建议是用内存数据库,然后持久到sqlite中,这样的性能远胜于原生的sqlite,即使不使用内存数据库,也几乎与原生sqlite的效率几乎接近。
  • greenDAO 支持 protocol buffer(protobuf) 协议数据的直接存储,如果你通过 protobuf
    协议与服务器交互,将不需要任何的映射。
  • 与 ORMLite 等使用注解方式的 ORM 框架不同,greenDAO 使用「Code
    generation」的方式,这也是其性能能大幅提升的原因。

GreenDao源码

Android GreenDao 3.2.2的详解以及实战(附Demo)_第3张图片

GreenDao主体结构

Android GreenDao 3.2.2的详解以及实战(附Demo)_第4张图片

GreenDao 3.2.2 配置与使用

  • GreenDao的配置

  1. 在app下的gradle配置相关依赖以及数据库相关信息
apply plugin: 'org.greenrobot.greendao'

android {

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

dependencies {

    //GreenDao
    implementation 'org.greenrobot:greendao:3.2.2'
}
  1. 在app同级的gradle中导入插件
// 在 Project的build.gradle 文件中添加:
buildscript {
    repositories {
    
        mavenCentral() // add repository
    }
    dependencies {
    
        classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2' // add plugin
    }
}

GreenDao的使用

  1. 全局初始化
 /**
 * @author 拉莫帅
 * @date 2022/1/5
 * @address
 * @Desc 全局初始化
 */
public class MyApp extends Application {

    private DaoSession mDaoSession;
    public static MyApp instances;
    public static Context context;

    @Override
    public void onCreate() {
        super.onCreate();
        instances = this;
        context = getApplicationContext();
        setDatabase();
    }

    public static MyApp getInstances() {
        return instances;
    }

    public static Context getAppContext() {
        return context;
    }

    /**
     * 设置greenDao
     */
    private void setDatabase() {
        DaoMaster.DevOpenHelper mHelper = new DaoMaster.DevOpenHelper(this, "harry-db", null);
        SQLiteDatabase db = mHelper.getWritableDatabase();
        DaoMaster mDaoMaster = new DaoMaster(db);
        mDaoSession = mDaoMaster.newSession();
    }

    public DaoSession getDaoSession() {
        return mDaoSession;
    }
}

  1. 创建一个实体类
     /**
 	  * @author 拉莫帅
 	  * @date 2022/1/5
      * @address
      * @Desc 人物
      *
      * 创建数据库实体类
      *
      *      @Entity 表示这个实体类一会会在数据库中生成对应的表
      *
      *      @Id 表示该字段是id,注意该字段的数据类型为包装类型Long
      *
      *      @Property 则表示该属性将作为表的一个字段,其中nameInDb看名字就知道这个属性在数据库中对应的数据名称
      *
      *       @Transient 该注解表示这个属性将不会作为数据表中的一个字段
      *
      *       @NotNull 表示该字段不可以为空
      *
      *       @Unique 表示该字段唯一
      */

Android GreenDao 3.2.2的详解以及实战(附Demo)_第5张图片

  1. buid一下项目

    Android GreenDao 3.2.2的详解以及实战(附Demo)_第6张图片

  2. greendao.gen目录下会自动生成greenDAO三个类文件!这时候证明数据连接成功了

    Android GreenDao 3.2.2的详解以及实战(附Demo)_第7张图片

  3. Activity初始化数据库

  @Override
    protected void initData() {
        /**
         * 初始化数据库
         */
        DaoSession daoSession = MyApp.getInstances().getDaoSession();
        userDao = daoSession.getUserDao();
    }

  1. 增删改查
  • 增加

Android GreenDao 3.2.2的详解以及实战(附Demo)_第8张图片

  • 删除
        /**
         * <条件删除>
         *     根据ID删除单条数据
         * 
         */
        long l = userDao.count() - 1;
        userDao.deleteByKey(l);

        /**
         * <条件删除>
         *      用户名 Username
         *      单个条件删除 eq
         * 
         */
        userDao.queryBuilder()
                .where(
                        UserDao.Properties.Username.eq(name)
                ).buildDelete()
                .executeDeleteWithoutDetachingEntities();

        /**
         * <条件删除>
         *      用户名 Username
         *      密码 Password
         *      多条件删除 eq
         * 
         */
        userDao.queryBuilder()
                .where(
                        UserDao.Properties.Username.eq(name),
                        UserDao.Properties.Password.eq(passWord)
                ).buildDelete()
                .executeDeleteWithoutDetachingEntities();

        /**
         * 删除全部数据
         */
        userDao.deleteAll();

关于GreenDao 数据去重

  1. 定义实体类Bean的时候,找到唯一数据值,设置注解 @Unique
    设置unique属性,在GreenDao创建数据库表时会自动为此字段创建唯一索引

Android GreenDao 3.2.2的详解以及实战(附Demo)_第9张图片

  1. 在插入数据时如果违反唯一性会抛出异常。

Android GreenDao 3.2.2的详解以及实战(附Demo)_第10张图片

解决方法:
(1)我们需要捕获异常并忽略。

try {
        dao.insert(user);
    } catch (SQLiteConstraintException e) {
      	// 主键或unique唯一索引冲突,忽略
        Log.e("数据去重 >>", "数据重复,忽略");
    }

(2)把insert替换为insertOrReplace
(3)查询后插入,在插入之前先查询是否已存在,存在则不插入,从而达到去重效果。

User queryUser = dao.queryBuilder().where(UserDao.Properties.Name.eq("张三")).unique();
if (queryUser == null) {
    dao.insert(user);  
} else {
    Log.d(TAG, "数据重复,忽略"); 
}

(4)插入后删除重复,先将所有数据插入,然后通过查询找出重复数据并删除。

dao.insert(user);   

List<User> repeatUsers = dao.queryBuilder().where(UserDao.Properties.Name.eq("张三")).list();
if (repeatUsers.size() > 1) {  
    dao.delete(repeatUsers.get(1));   // 删除第二条重复数据
}

- 修改

在使用修改的操作的时候,这里总结了一个使用时候的bug
对单条数据进行修改的话,是不会出现问题的
但是如果出现多条重名的数据,进行修改的话,会报一个错,如下:

        /**
         * <条件修改>
         *      用户名 Username
         *      修改单条用户数据 eq
         * </条件修改>
         */
        User user = userDao.queryBuilder()
                .where(
                        UserDao.Properties.Username.eq(name)
                ).build()
                .unique();

        Toast.makeText(MainActivity.this, "" + name, Toast.LENGTH_SHORT).show();
        if (user != null) {
            user.setUsername(updateMsg);

            userDao.update(user);
        }

Android GreenDao 3.2.2的详解以及实战(附Demo)_第11张图片

这时候就不能用unique了,修改为list,就可以解决以上问题,修改如下:

         /**
         * <条件修改>
         *      用户名 Username
         *      修改多条用户重复数据 eq
         * </条件修改>
         */
        List<User> list = userDao.queryBuilder()
                .where(
                        UserDao.Properties.Username.eq(name)
                ).build()
                .list();

        Log.e("数据", "updateUser: " + list.size());
        if (list.size() > 0) {
            for (int i = 0; i < list.size(); i++) {
                list.get(i).setUsername(updateMsg);
                userDao.update(list.get(i));
            }
        }

  • 查询

QueryBuilder的使用

QueryBuilder的常见方法: where(WhereCondition cond, WhereCondition…
condMore): 查询条件,参数为查询的条件! or(WhereCondition cond1, WhereCondition
cond2, WhereCondition… condMore): 嵌套条件或者,用法同or。 and(WhereCondition
cond1, WhereCondition cond2, WhereCondition… condMore):
嵌套条件且,用法同and。 join(Property sourceProperty, Class
destinationEntityClass):多表查询
输出结果有四种方式,选择其中一种最适合的即可,list()返回值是List,而其他三种返回值均实现Closeable,需要注意的不使用数据时游标的关闭操作:
list ()所有实体都加载到内存中。结果通常是一个没有魔法的 ArrayList。最容易使用。 listLazy
()实体按需加载到内存中。首次访问列表中的元素后,将加载并缓存该元素以供将来使用。必须关闭。 listLazyUncached
()实体的“虚拟”列表:对列表元素的任何访问都会导致从数据库加载其数据。必须关闭。 listIterator
()让我们通过按需加载数据(懒惰)来迭代结果。数据未缓存。必须关闭。 orderAsc() 按某个属性升序排; orderDesc()
按某个属性降序排;


GreenDao中SQL语句的缩写,我们也了解下,源码在Property中,使用的时候可以自己点进去查询即可:
eq():"equal ('=?')" 等于;
notEq() :"not equal ('<>?')" 不等于;
like():" LIKE ?" 值等于;
between():" BETWEEN ? AND ?" 取中间范围;
in():" IN (" in命令;
notIn():" NOTIN (" not in 命令;
gt():">?" 大于;
lt():" ge():">=?" 大于等于;
le():"<=? " 小于等于;
isNull():" IS NULL" 为空;
isNotNull():" IS NOT NULL" 不为空;
        /**
         * 查询全部用户数据
         */
        List<User> list = userDao.loadAll();

        /**
         * <条件查询>
         *      用户名 Username
         *      模糊查询 like
         * 
         */
        List<User> list = userDao.queryBuilder()
                .where(
                        UserDao.Properties.Username.like("%" + name + "%")
                ).build()
                .list();

        /**
         * <条件查询>
         *      用户名 Username
         *      密码 Password
         *      多条件查询 eq
         * 
         */
        List<User> list = userDao.queryBuilder()
                .where(
                        UserDao.Properties.Username.eq(name),
                        UserDao.Properties.Password.eq(pwd)
                ).build()
                .list();

        /**
         * <条件查询>
         *      用户名 Username
         *      单条件查询 eq
         * 
         */
        List<User> list = userDao.queryBuilder()
                .where(
                        UserDao.Properties.Username.eq(name)
                ).build()
                .list();

        /**
         * <条件查询>
         *     自增ID
         *     orderAsc 以字段升序排序
         *     orderDesc 以字段降序
         * 
         */
        List<User> list = userDao.queryBuilder()
                .orderAsc(UserDao.Properties.Id)
                .build()
                .list();

  • 模拟有网/无网数据处理问题

总结

如果想了解完整功能,可以扫码下载
Android GreenDao 3.2.2的详解以及实战(附Demo)_第12张图片

项目下载地址:GreenDaoMaster

你可能感兴趣的:(Android,依赖-与-权限,android,database,sqlite)