简介
greenDAO 是一个将对象映射到 SQLite 数据库中的轻量且快速的 ORM 解决方案。采用编译时注解的方式,对与编译时注解和运行时注解的优缺点可以做一个了解。
greenDAO优点:性能最大化,可能是Android平台上最快的ORM框架;易于使用的API;最小的内存开销;依赖体积小;支持数据库加密;强大的社区支持;
一,配置
1, 在根目录的build.gradle添加
buildscript {
repositories {
jcenter()
//添加仓库
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.3.2'
classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2'
}
}
2, 在app的build.gradle添加
apply plugin: 'com.android.application'
apply plugin: 'org.greenrobot.greendao'
dependencies {
implementaion 'org.greenrobot:greendao:3.2.2'
}
3,配置数据库版本和类生成目录,在app的 build.gradle 添加
greendao {
schemaVersion 1//数据库版本号
daoPackage 'com.xiaoyehai.landsurvey.greendao'//设置DaoMaster、DaoSession、Dao包名
targetGenDir 'src/main/java'//设置DaoMaster、DaoSession、Dao目录
}
二,demo中使用
1,创建实体类
点击build gradle生成相关代码以及类,DaoMaster、DaoSession、XXXDao。
2, 简单封装
1,DBManager数据库管理
public class DBManager {
private static final String DB_NAME = "launcher.db";//数据库名称
private volatile static DBManager mDaoManager;
private OpenHelper mHelper;
private DaoMaster mDaoMaster;
private DaoSession mDaoSession;
private DBManager() {
mHelper = new OpenHelper(LauncherApplication.getApplication(), DB_NAME);
mDaoMaster = new DaoMaster(mHelper.getWritableDb());
mDaoSession = mDaoMaster.newSession();
}
public static DBManager getInstance() {
if (mDaoManager == null) {
synchronized (DBManager.class) {
if (mDaoManager == null) {
mDaoManager = new DBManager();
}
}
}
return mDaoManager;
}
public DaoSession getDaoSession() {
return mDaoSession;
}
}
2,OpenHelper数据库升级管理(数据库升级会删除表数据,重新创建,对于数据库数据恢复需要单独编写OpenHelper去管理)
public class OpenHelper extends DaoMaster.OpenHelper {
public OpenHelper(Context context, String name) {
super(context, name);
}
@Override
public void onUpgrade(Database db, int oldVersion, int newVersion) {
//把需要管理的数据库表DAO作为最后一个参数传入到方法中
Log.e("OpenHelper", "onUpgrade: oldVersion=" + oldVersion + ",newVersion=" + newVersion);
MigrationHelper.getInstance().migrate(db, UserDao.class);
}
}
3,MigrationHelper真正实现数据库升级恢复数据
public class MigrationHelper {
private volatile 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);
}
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());
}
}
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";
}
return "";
}
private static 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;
}
}
4,如何调用增删改查实现数据操作
DBManager.getInstance().getDaoSession().insert(object)
DBManager.getInstance().getDaoSession().delete(object)
DBManager.getInstance().getDaoSession().update(object)
DBManager.getInstance().getDaoSession().loadAll(object)
另外还有一种调用方式,可以通过XXXDao类去调用,这种方式更加灵活,此类中有更多的方式。
5,增删改查操作类可以单独写,更方便管理
首先写个基类,提供最基本的方法
public abstract class BaseImpl<T> {
public DaoSession daoSession;
public BaseImpl() {
if (daoSession == null) {
daoSession = DBManager.getInstance().getDaoSession();
}
}
/**
* 插入一条数据
*/
public abstract void insert(T object);
/**
* 更新一条数据
*/
public abstract void update(T object);
/**
* 查询所有
*
* @return
*/
public abstract List<T> loadAll();
/**
* 删除
*
* @return
*/
public abstract void delete(T object);
}
UserImpl实现基类,在这里可以操作更多方式。
public class UserImpl extends BaseImpl<User> {
public UserImpl () {
super();
}
@Override
public void insert(User object) {
daoSession.insert(object);
}
@Override
public void update(User object) {
daoSession.update(object);
}
@Override
public List<User> loadAll() {
return daoSession.loadAll(User.class);
}
@Override
public void delete(Userobject) {
daoSession.delete(object);
}
/**
* 根据名字查询
*
* @param name
* @return
*/
public List<User> loadAllByName(String name) {
QueryBuilder<User> queryBuilder = daoSession.queryBuilder(User.class);
return queryBuilder.where(UserDao.Properties.Name.eq(name)).list();
}
/**
* 用UserDao插入列表数据
* @param list
*/
public void insert(List<User> list){
daoSession.getUserDao().insertInTx(list);
}
}
三,基本介绍
1, GreenDao 的核心类
GreenDao 的核心类有三个:分别是 DaoMaster,DaoSession,XXXDao,这三个类都会自动创建,无需自己编写创建!
- DaoMaster::DaoMaster 保存数据库对象(SQLiteDatabase)并管理特定模式的 DAO
类(而不是对象)。它有静态方法来创建表或删除它们。它的内部类 OpenHelper 和DevOpenHelper 是
SQLiteOpenHelper 实现,它们在 SQLite 数据库中创建模式。 - DaoSession:管理特定模式的所有可用 DAO 对象,您可以使用其中一个getter方法获取该对象。DaoSession还提供了一些通用的持久性方法,如实体的插入,加载,更新,刷新和删除。
- XXXDao:数据访问对象(DAO)持久存在并查询实体。对于每个实体,greenDAO 生成DAO。它具有比 DaoSession更多的持久性方法,例如:count,loadAll 和 insertInTx。
- Entities :可持久化对象。通常, 实体对象代表一个数据库行使用标准 Java 属性(如一个POJO 或 JavaBean )。
2, 实现增删改查
增:daoSession.insert(bean),daoSession.insertOrReplace(bean)
删:delete和deleteAll();
改:updata()
查:loadAll()查询所有,queryRaw()根据条件查询,queryBuilder()更方便的查询
通过daoSession.getXXXDao().方法,这种有更多用法。
3, QueryBuilder的使用
①,QueryBuilder 的常见方法:
- where(WhereCondition cond, WhereCondition… condMore): 查询条件,参数为查询的条件!
- or(WhereCondition cond1, cond2, WhereCondition…condMore): 嵌套条件或者,用法同 or。
- and(WhereCondition cond1, cond2, WhereCondition… condMore): 嵌套条件且,用法同and。
- join(Property sourceProperty, ClassdestinationEntityClass):多表查询,后面会讲。
- 输出结果有四种方式,选择其中一种最适合的即可,list()返回值是 List,而其他三种返回值均实现
Closeable,需要注意的不使用数据时游标的关闭操作 - list ()所有实体都加载到内存中。结果通常是一个没有魔法的 ArrayList。最容易使用。
- listLazy ()实体按需加载到内存中。首次访问列表中的元素后,将加载并缓存该元素以供将来使用。必须关闭。
- listLazyUncached ()实体的“虚拟”列表:对列表元素的任何访问都会导致从数据库加载其数据。必须关闭。
- listIterator ()让我们通过按需加载数据(懒惰)来迭代结果。数据未缓存。必须关闭。
②,使用QueryBuilder进行查询操作
根据name查询,orderAsc()升序
取10条 Id 大于1的数据,且偏移2条
4, 注解
基础属性注解(@Id,@Property,@NotNull,@Transient)
- @Id:@Id注解选择 long / Long属性作为实体 ID。在数据库方面,它是主键。参数autoincrement = true表示自增,id 不给赋值或者为赋值为 null 即可(这里需要注意,如果要实现自增,id 必须是 Long,为 long 不行!)。
- @Property:允许您定义属性映射到的非默认列名。如果不存在,GreenDAO 将以 SQL-ish 方式使用字段名称(大写,下划线而不是 camel 情况,例如 name 将成为 NAME)。注意:您当前只能使用内联常量来指定列名。
- @NotNull:设置数据库表当前列不能为空 。
- @Transient:添加次标记之后不会生成数据库表的列。标记要从持久性中排除的属性。将它们用于临时状态等。或者,您也可以使用 Java 中的 transient 关键字。
索引注解
@Index:使用@Index 作为一个属性来创建一个索引,通过 name 设置索引别名,也可以通过unique给索引添加约束。
@Unique:向索引添加 UNIQUE 约束,强制所有值都是唯一的。
关系注解
关系型注解 GreenDao 中主要就两个:
@ToOne:定义与另一个实体(一个实体对象)的关系
@ToMany:定义与多个实体对象的关系
五, 关系表的创建
1, 一对一关系,每个用户对应一个用户信息
使用注解@ToOne(joinProperty = “id”)
用户类
用户信息类
插入数据
2, 一对多关系,一个领导对应多名员工
使用注解@ToMany(referencedJoinProperty = “id”)
插入数据
3, 多对多关系,一个老师对应多个学生,一个学生对应多个老师
使用注解@JoinEntity(entity = TeacherJoinStudentBean.class,sourceProperty = “tId”,
targetProperty = “sId”)
插入数据,需要注意这里insertInTx()方法,不能直接用daoSession调用。需要调用getXXXDao,通过Dao调用。另外XXXDao中也有save()的用法
六, 数据库加密
1, 导入加密库文件
implementation ‘net.zetetic:android-database-sqlcipher:3.5.6’
修改 DaoSession 的生成方式