GreenDao —— 简单快速操作 Android SQLite 数据库

GreenDao —— 简单快速操作 Android SQLite 数据库

GreenDao 是轻量快速的 SQLite 数据库 ORM 解决方案。(greenDAO is a light & fast ORM solution that maps objects to SQLite databases.

GreenDao 层次

ORM(Object-Relationl Mapping)用于在关系型数据库与对象之间做一个映射。可以使数据库操作想对象一样使用,而避开使用复杂的SQL语句交互。

GreenDao 特点:

  • 性能强大。(可能是 Android 平台最快的 ORM 框架)
  • 简易便捷的 API
  • 开销小
  • 依赖体积小
  • 支持数据库加密
  • 强大的社区支持

此前接触 Android 的 SQLite 数据库操作,有感于直接使用 SQLite 繁琐且低效,使用 Android 官方的 Room 也感觉效果不佳。最后选择 GreenDao 总算满足预期。

GreenDao 环境配置

1. Project 下的 build.gradle 增加插件支持


buildscript {
    repositories {
        google()
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.2.1'
        classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2' // 版本建议最新
        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

2. app 下的 build.gradle 增加插件依赖


apply plugin: 'com.android.application'
apply plugin: 'org.greenrobot.greendao'

android {
    ...

    // greendao 配置
    greendao {
        schemaVersion 1                                         // 数据库版本号
        daoPackage      'org.cvte.research.faceapi.greendao'    // greenDao 自动生成的代码保存的包名
        targetGenDir    'src/main/java'                         // 自动生成的代码存储的路径,默认是 build/generated/source/greendao.
    }

    ...
}

dependencies {
    ...

    // GreenDao  数据库ORM
    implementation 'org.greenrobot:greendao:3.2.2'
    // GreenDao 生成dao和model的generator的项目 发布时可以去掉
    implementation 'org.greenrobot:greendao-generator:3.2.2'
}

接下来可以使用 GreenDao 对数据库对象进行操作了。

创建 GreenDao 数据库对象实体

1. 创建数据库实体

创建实体需要了解 GreenDao 的注解:

注解描述其它参数
Entity 对应数据库中的表 nameInDb:表使用别名。默认为类名
active:标记一个实体是否处于活动状态,活动实体有 update、delete、refresh 方法。默认为 false
indexes:定义多列索引
Id 该数据库表的主键,只能是 Long 或 long 类型 autoincrement:设置是否自增,可以通过传入 null 自动分配
Unique 唯一。可以通过设置唯一的属性设为主键
Property 列名 nameInDb:列使用别名。默认为变量名
Index 索引 unique:设置唯一
name:设置索引的别名
NotNull 非空。该字段值不能为空
Transient 忽略。greendao 将不会创建对应的项
ToOne 表格映射关系一对一 joinProperty:外联实体与该实体主键的匹配成员
ToMany 表格映射关系一对多或多对多
Generatedgreendao 产生的部分,手动修改会报错
Keep 替换 Generated,greendao 不再生成和报错
Convert 数据类型转换。实体类型与数据库类型转换,实现存储和修改的便捷 converter:转换方法
columnType:数据库使用的数据类型

文件名为:UserBean.java


@Entity(nameInDb = "user_table")
public class UserBean {
    @Id(autoincrement = true)
    @Unique
    @Property(nameInDb = "user_id")
    private Long userId;

    @NotNull
    @Property(nameInDb = "group_id")
    private Long groupId;

    @NotNull
    @Property(nameInDb = "user_name")
    private String userName;

    @Unique
    @NotNull
    @Property(nameInDb = "user_number")
    private String userNumber;
}

另外增加一个 GroupBean.java 实体,内容如下:


@Entity(nameInDb = "group_table")
public class GroupBean {
    @Id(autoincrement = true)
    @Unique
    @Property(nameInDb = "group_id")
    private Long groupId;

    @Unique
    @NotNull
    @Property(nameInDb = "group_name")
    private String groupName;
}

2. 编译后,生成完善的数据库实体方法

编译后可以看到 UserBean.java 文件增加了不少接口。


@Entity(nameInDb = "user_table")
public class UserBean {
    @Id(autoincrement = true)
    @Unique
    @Property(nameInDb = "user_id")
    private Long userId;

    @NotNull
    @Property(nameInDb = "group_id")
    private Long groupId;

    @NotNull
    @Property(nameInDb = "user_name")
    private String userName;

    @Unique
    @NotNull
    @Property(nameInDb = "user_number")
    private String userNumber;

    @Generated(hash = 1853997691)
    public UserBean(Long userId, @NotNull Long groupId, @NotNull String userName,
            @NotNull String userNumber) {
        this.userId = userId;
        this.groupId = groupId;
        this.userName = userName;
        this.userNumber = userNumber;
    }

    @Generated(hash = 1203313951)
    public UserBean() {
    }

    public Long getUserId() {
        return this.userId;
    }

    public void setUserId(Long userId) {
        this.userId = userId;
    }

    public Long getGroupId() {
        return this.groupId;
    }

    public void setGroupId(Long groupId) {
        this.groupId = groupId;
    }

    public String getUserName() {
        return this.userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getUserNumber() {
        return this.userNumber;
    }

    public void setUserNumber(String userNumber) {
        this.userNumber = userNumber;
    }
}

自动生成的方法:

  1. 无参构造函数
  2. 有参构造函数
  3. getter / setter 方法

除此之外,还生成了 DaoMaster,DaoSession,UserBeanDao (GroupBean 对应生成 GroupBeanDao ) 等文件。
下面来介绍各自的功能。

3. DaoMaster,DaoSession,Dao 文件

文件描述相应文件
DaoMaster 保存数据库对象(SQLiteDatabase)DaoMaster
DaoSession 管理所有的 Dao 对象 DaoSession
Dao 数据访问对象(Data Access Object),可以通过 Dao 操作数据实体 UserBeanDao、GroupBeanDao
Entity 数据实体(每个实体对应数据库内的一个表)UserBean、GroupBean

通过 GreenDao 操作数据库。

1. 初始化数据库


private static DaoSession mDaoSession;

public initDatabase(Context context, String databaseFileName) {
    DaoMaster.DevOpenHelper helper = new DaoMaster.DevOpenHelper(context, databaseFileName, null);
    SQLiteDatabase db = helper.getWritableDatabase();
    DaoMaster daoMaster = new DaoMaster(db);
    mDaoSession = daoMaster.newSession();

    // 打开查询的LOG
    // QueryBuilder.LOG_SQL = true;
    // QueryBuilder.LOG_VALUES = true;
}

public static DaoSession getDaoSession() {
    return mDaoSession;
}

执行 initDatabase 初始化数据库后,可以通过 getDaoSession 拿到 DaoSession 对每个数据库实体进行处理。

2. 插入数据

以以下数据为例:

组织(GroupName)名字(UserName)编号(UserNumber)
CHNLiTianYu1-0090
USALiBill10-8082
XYZMiXue2-720

public void insertData(String groupName, String userName, String userNumber) {
    GroupBean groupBean = new GroupBean(null, groupName);                       // Group 主键(groupId)是自动增加的,使用 null 就可以自增了。
    long keyGroupBean = getDaoSession().getGroupBeanDao().insert(groupBean);    // 返回值是插入库后的 Group 实体的 key
    groupBean = getDaoSession().getGroupBeanDao().load(keyGroupBean);           // 通过 key 可以获取到插入的 Group 数据
    
    UserBean userBean = new UserBean(null, groupBean.getGroupId(), userName, userNumber);  // User 主键(userId)也是自动增加的,但是 groupId 需要通过关联的 Group 获取。
    getDaoSession().getUserBeanDao().insert(userBean);
}

3. 删除数据


// 删除单个数据
getDaoSession().getUserBeanDao().delete(userBean);

// 删除多个数据 (userBeanList 类型为 List<UserBean>)
getDaoSession().getUserBeanDao().deleteInTx(userBeanList);

// 删除所有数据
getDaoSession().getUserBeanDao().deleteAll();

4. 查找数据


// 查询 userNumber 为 "1-0090" 的 user
getDaoSession().getUserBeanDao().queryBuilder().where(UserBeanDao.Properties.UserNumber.eq("1-0090")).unique();

// 查询 userName 形如 "Lixxx" 的 user ( 类似于 SQLite 的 like 模糊查询语法 )
getDaoSession().getUserBeanDao().queryBuilder().where(UserBeanDao.Properties.UserNumber.eq("Li%")).unique();

// 查询 groupName 为 "CHN" 的 user ( 关联表查询 )
QueryBuilder<UserBean> qb = getDaoSession().getUserBeanDao().queryBuilder();    // 需要获取 User 数据,所以 qb 为 User
Join join_UserBean = qb.join(UserBean.class, UserBeanDao.Properties.UserId);    // 设置 User 的关联规则(根据 UserBean.userId == UserBean.userId)
Join join_GroupBean = qb.join(join_UserBean, UserBeanDao.Properties.GroupId, GroupBean.class, GroupBeanDao.Properties.GroupId);     // 设置 Group 的关联规则(根据 UserBean.groupId == GroupBean.groupId)
join_GroupBean.where(GroupBeanDao.Properties.GroupName.eq("CHN"));      // 其它查找条件(User和Group已经关联起来了)
qb.list();      // 返回查找结果

使用 .unique() 为获取查询满足要求的第一个数据。
使用 .list() 为获取所有满足要求的数据(返回结果为 List<> 类型)

多表关联查询稍显复杂,可以通过 ToOne、ToMany 设置表与表之间的关系进行直接访问的查询。
但是大数据量时效率没有使用以上方法快。

5. 更改数据


// 更改单个数据
getDaoSession().getUserBeanDao().update(userBean);

// 更改多个数据 (userBeanList 类型为 List<UserBean>)
getDaoSession().getUserBeanDao().updateInTx(userBeanList);

其它

1. 类型转换

SQLite 数据库的数据类型有限(甚至不支持float),而作为对象则允许所有java的类型(数组、各种类等)。
因此在 GreenDao 中支持类型转换(从数据库数据类型转换为实体的数据类型),方便对实体进行修改查询。

请在对应的成员中加入 @Convert ,如:


// 以实体的 float[] 与 数据库的 TEXT 类型转换为例
@Convert(converter = ConvertFloatArrayToString.class, columnType = String.class)
private float[] featureData;

转换方法:


public class ConvertFloatArrayToString implements PropertyConverter<float[], String> {
    // 数据库类型 -> 实体类型
    public float[] convertToEntityProperty(String databaseValue) {
        String[] strList = databaseValue.split(",");
        float[] floatList = new float[strList.length];
        for (int i = 0, len = strList.length; i < len; ++ i) {
            floatList[i] = Float.parseFloat(strList[i]);
        }
        return floatList;
    }

    // 实体类型 -> 数据库类型
    public String convertToDatabaseValue(float[] entityProperty) {
        String str = "" + entityProperty[0];
        for (int i = 1, len = entityProperty.length; i < len; ++ i) {
            str += "," + entityProperty[i];
        }
        return str;
    }
}

这样就可以读取直接操作 float[] 进行读写,不需要每次都手动转为 TEXT(对应 Java 中的 String)或者解析 TEXT 了。

2. 其它的其它

比如加密,比如缓存,比如懒加载。。。有空再补吧

评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值