数据库学习之 greenDAO 实战

2024-06-06 11:48

本文主要是介绍数据库学习之 greenDAO 实战,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

上一篇 对 greenDAO 进行了基本的介绍,包括配置、注解含义、基本的操作。本篇主要对 greenDAO 的增删改查的一些高级用法进行介绍,有时可能业务需求,简单的增删改查可能满足不了,比如数据较大、多表联查,这时就需要学一下 greenDAO 的高级用法。

本篇主要内容,就在这个粗略的草图中。

GreenDAO_Structure

1. 建表

对于移动端来说,数据库不会很复杂,毕竟空间和处理能力有限,基本上用到的是一些单独的一张表,或者一对一,一对多这样的表。那我们就来试一下一对多的表。

两张表,一张里面存储班级信息,另一张里面存储学生信息,班级里面有多个学生,这样就建立起一对多的关系。

班级:名字和编号

学生:学号,名字,班级,年龄

班级实体类


@Entity
public class Clazz {@Unique@Id(autoincrement = true)private Long id;private String name;// 一对多 注解,采用 referencedJoinProperty 方式,clazID 为学生的班级号@ToMany(referencedJoinProperty = "clazID")private List<Student> studentList;// hash 值由编译时自动生成,使用时只需要 对构造函数注解  @Generated 即可@Generated(hash = 1166360579)public Clazz() {}@Generated(hash = 582074864)public Clazz(Long id, String name) {this.id = id;this.name = name;}

学生实体类


@Entity(nameInDb = "Student")
public class Student {@Unique@Id(autoincrement = true)private Long id;// 修改字段在数据库中的名字@Property(nameInDb = "studentID")private int studentID;private String name;// 一对多 字段关联 属性private long clazID;private int age;@Generated(hash = 1556870573)public Student() {}@Generated(hash = 435762767)public Student(Long id, int studentID, String name, long clazID, int age) {this.id = id;this.studentID = studentID;this.name = name;this.clazID = clazID;this.age = age;}

造数据

    List<Clazz> clazzList = new ArrayList<>();List<Student> studentList = new ArrayList<>();...
private void initData() {int studenId = 10;long id = 0;for (int i = 1; i < 4; i++) {Clazz clazz = new Clazz();clazz.setId(new Long(i));clazz.setName(i + "班");for (int j = 0; j < 5; j++) {Student student = new Student();student.setAge(18 + j);student.setId(id++);student.setStudentID(studenId++);student.setName("Ralf");student.setClazID(clazz.getId());studentList.add(student);}clazzList.add(clazz);}
}

建表和准备好数据之后,就可以将数据插入到数据库中。可以使用 insertInTx 这个方法,将数据批量插入到数据库中,后面会讲到封装

/*** 插入多条数据** @param entities*/public <T> void inster(List<T> entities) {isDaoNull();mAbstractDao.insertInTx(entities);}

2. 调试

之前调试使用 adb 命令调试,使用原生的查询数据,“select * from table” ,类似于这样的语句。有点麻烦。这里推荐的一个工具 **Android-Debug-Database **

使用这个开源库调试数据库非常方便。

特色:

可视化查看数据库

能够直接对数据库增删改查

可以查看你的应用中所有的shared preferences

使用

在你的build.gradle添加如下:

debugCompile 'com.amitshekhar.android:debug-db:1.0.0'

debugCompile的作用:只在你debug编译时起作用,当你release的时候就没必要使用它了。
下面当你在App启动的时候,你要注意查看下你的logcat,会有这么一行:
D/DebugDB: Open http://XXX.XXX.X.XXX:8080
点击打开浏览器,你就可以看到你的App中的数据库,和 shared preferences

3. 增删改查

3.1 增
// 单条数插入
public long insert(T entity) {}// 批量插入数据
public void insertInTx(T... entities) {}public void insertInTx(Iterable<T> entities) {}public void insertInTx(Iterable<T> entities, boolean setPrimaryKey) {}
// 插入单条数据,如果存在,则替换
public long insertOrReplace(T entity) {}// 批量插入数据,如果存在,则替换
public void insertOrReplaceInTx(T... entities) {}public void insertOrReplaceInTx(Iterable<T> entities) {}public void insertOrReplaceInTx(Iterable<T> entities, boolean setPrimaryKey) {}
// 类似于insertOrReplace()方法,但比它更有效率,因为当key已经存在时,不需要查询直接更新
public void save(T entity) {}
3.2 删
// 删除相应表的全部数据
public void deleteAll() {}// 删除给定PK的实体。目前,仅支持惟一PK实体。
public void deleteByKey(K key) {}// 使用事务删除数据库中给定键的所有实体。批量删除。
public void deleteByKeyInTx(K... keys) {}
public void deleteByKeyInTx(Iterable<K> keys) {}// 删除给定的实体
public void delete(T entity) {}//使用事务删除数据库中给定的实体。批量删除。每个entity的id属性必须有值,否则报错。其实就是删除与entity主键值相同的数据,entity的其他数据值与表中数据值不一致时,也会删除。
public void deleteInTx(T... entities) {}
public void deleteInTx(Iterable<T> entities) {}
3.3 改
// 更新一条实体数据,entity的id属性必须有值,否则报错。若entity的id值表中不存在时,不会报错。
public void update(T entity) {}// 更新多条数据,每个entity的id属性必须有值,否则报错。若entity的id值表中不存在时,不会报错。
public void updateInTx(T... entities) {}public void updateInTx(Iterable<T> entities) {}
3.4 查

普通查询

// 删除指定主键实体
public T load(K key) {}// 加载给定RowId的实体。传入:key or null。返回:该实体 或 null。
public T loadByRowId(long rowId) {}// 从数据库加载所有可用的实体
public List<T> loadAll() {}

高级查询

// 原始查询语句
public List<T> queryRaw(String where, String... selectionArg) {}

QueryBuilder

图片

构建 QueryBuilder

QueryBuilder<T> queryBuilder = mDaoSession.queryBuilder(claz);

QueryBuilder 有一系列的方法,其中注意 build() 和 list()方法

QueryBuilder

其中,如果使用 build 方法,则可以将得到的 Query 对象作为参数传递给查询方法

// 异步查询,后面详细讲
public AsyncOperation queryList(Query<?> query) {}

另外,也可以使用 QueryBuilder 对象直接查询,使用 list 方法

// 执行查询并将返回一个包含所有entity的list为结果,直接加载在内存中。
public List<T> list() {}

例子

List<Student> list = dbUtil.queryBuilder(Student.class).limit(3).distinct().build().list();

WhereCondition
WhereCondition 对象可以使用下面的对象构建,然后作为参数,WhereCondition 相当于使用原始的查询语句。

between(Object value1, Object value2): BETWEEN … AND …
eq(Object value): equal (‘=’)
notEq(Object value): not equal (‘<>’)
gt(Object value): than (‘>’)
lt(Object value): less than (‘<’)
ge(Object value): greater or equal (‘>=’)
le(Object value): less or equal (‘<=’)
like(String value): LIKE
isNotNull(): IS NOT NULL
isNull(): IS NULL
in(Object… inValues): IN (…, …, …)
notIn(Object… notInValues): NOT IN (…, …, …)
in(Collection< ?> inValues): IN (…, …, …)
notIn(Collection< ?> notInValues): NOT IN (…, …, …)

例子

List<Student> list = dbUtil.queryBuilder(Student.class).limit(3).distinct().where(StudentDao.Properties.Id.eq(1)).list();

join 多表联查

join 方法很多,下面针对给出的join方法逐个分析,使用时根据查询的需求来决定。

// 通过联合另一个表扩展查询,sourceProperty 和需要联合的表中的 destinationEntityClass 的主键匹配
public <J> Join<T, J> join(Property sourceProperty, Class<J> destinationEntityClass) {}

例子

// 构建 QueryBuilder
QueryBuilder<Student> queryBuilder = dbUtil.create(Student.class).queryBuilder(Student.class);
//Properties.ClazID和Clazz.class的主键匹配
queryBuilder.join(StudentDao.Properties.ClazID, Clazz.class).where(ClazzDao.Properties.Id.eq(1));List<Student> studentList1 = queryBuilder.list();
// 和上面的 join 方法类似,多了一个参数 destinationProperty,这个属性相当于自己指定主键;也就是说 sourceProperty 和 destinationEntityClass表中的 destinationProperty 字段匹配;但不限与destinationEntityClass的主键,也可以是其他字段
public <J> Join<T, J> join(Property sourceProperty, Class<J> destinationEntityClass, Property destinationProperty) {}

例子

// 构建 QueryBuilder
QueryBuilder<Student> queryBuilder = dbUtil.create(Student.class).queryBuilder(Student.class);
// 指定主键 ClazzDao.Properties.Id
queryBuilder.join(StudentDao.Properties.ClazID, Clazz.class,ClazzDao.Properties.Id).where(ClazzDao.Properties.Id.eq(1));List<Student> studentList1 = queryBuilder.list();
// 需要查询的表中的主键和联合表中字段匹配,即 destinationProperty
public <J> Join<T, J> join(Class<J> destinationEntityClass, Property destinationProperty) {

例子

QueryBuilder<Clazz> queryBuilder1 = dbUtil.create(Clazz.class).queryBuilder(Clazz.class);
// Clazz 班级的主键是学生 Student 表中的外键,即 StudentDao.Properties.ClazID
queryBuilder1.join(Student.class,StudentDao.Properties.ClazID).where(StudentDao.Properties.StudentID.eq(11));List<Clazz> clazzList = queryBuilder1.list();

多表联查

public <J> Join<T, J> join(Join<?, T> sourceJoin, Property sourceProperty, Class<J> destinationEntityClass,Property destinationProperty) {}

例子

//查询在欧洲人口超过100000的城市
QueryBuilder qb = cityDao.queryBuilder().where(Properties.Population.ge(1000000));
Join country = qb.join(Properties.CountryId, Country.class);
Join continent = qb.join(country, CountryDao.Properties.ContinentId,
Continent.class, ContinentDao.Properties.Id);
continent.where(ContinentDao.Properties.Name.eq("Europe"));
List bigEuropeanCities = qb.list();
3.5 异步的增删改查

当数据量很大时 ,需要考虑使用异步方式,这样不至于导致线程堵塞等问题。

异步操作相对也比较简单 ,主要使用 有这么几步:

1. 获取 AsyncSession
AsyncSession asyncSession = mDaoSession.startAsyncSession();
2. 设置回调

回调方法是在主线程,查询是在子线程

asyncSession.setListenerMainThread(new AsyncOperationListener() {@Overridepublic void onAsyncOperationCompleted(AsyncOperation operation) {...}});
3. 执行

asyncSession 也有一系列的增删改查

asyncSession.loadAll(object);

下面看一个完成的异步查询的例子

public <T> void queryAsyncAll(Class<T> object, Query<T> query) {AsyncSession asyncSession = mDaoSession.startAsyncSession();asyncSession.setListenerMainThread(new AsyncOperationListener() {@Overridepublic void onAsyncOperationCompleted(AsyncOperation operation) {if (operation.isCompleted() && mCallBack != null) {List<T> result = (List<T>) operation.getResult();mCallBack.onSuccess(result);} else if (operation.isFailed() && mCallBack != null) {mCallBack.onFailed();}}});if (query == null) {asyncSession.loadAll(object);} else {asyncSession.queryList(query);}
}

4 封装

4.1 构造单例

下面这部分不难理解,构造 DbUtil 的单例,三个重载函数,可以指定名字,可以设置数据库密码,或者直接使用默认的名字,不加密。

主要是创建 DaoMaster 和 DaoSession 对象,然后使用 DaoSession 对象来获得每个 Entity 对应的 EntityDao 对象,常用的增删改查都是使用 EntityDao 对象来完成的。DaoSession 也具有增删改查功能,而且具有缓存功能,当查询一个对象2次时,取出来的对象是同一个,即使 Entity 的数据有变动,所以这时需要清除一下缓存 DaoSession.clear(),上文提到的异步操作,也是需要 DaoSession 来完成。

private static final String DEFAULT_DATABASE_NAME = "Database.db";
private static final String DEFAULT_DATABASE_PASSWORD = "hahaha";
private DaoSession mDaoSession;
private DaoMaster mDaoMaster;
private AbstractDao mAbstractDao;
private static DbUtil mDbUtils;
private DaoMaster.DevOpenHelper mHelper;
private DbCallBack mCallBack;private DbUtil(Application application, String dbName, String passWord) {if (mHelper == null) {mHelper = new DaoMaster.DevOpenHelper(application, dbName);}if (passWord == null || passWord.isEmpty()) {mDaoMaster = new DaoMaster(mHelper.getWritableDb());} else {mDaoMaster = new DaoMaster(mHelper.getEncryptedReadableDb(passWord));}mDaoSession = mDaoMaster.newSession();}public static DbUtil getInstance(Application application) {return getInstance(application, DEFAULT_DATABASE_NAME);
}public static DbUtil getInstance(Application application, String dbName) {return getInstance(application, dbName, "");
}public static DbUtil getInstance(Application application, String dbName, String passWord) {if (mDbUtils == null) {synchronized (DbUtil.class) {if (mDbUtils == null) {mDbUtils = new DbUtil(application, dbName, passWord);}}}return mDbUtils;
}
4.2 AbstractDao

这里封装的工具类里面没有使用具体的 EntityDao对象,因为EntityDao对象 是在编译后自动生成的,所以使用基类 AbstractDao,这样就可以不用做类型判断。

/*** 插入一条数据** @param dbEntity*/public <T> void insert(T dbEntity) {setCurrentDao(dbEntity.getClass());mAbstractDao.insert(dbEntity);}private<T> void setCurrentDao(Class<T> entityClass) {if (mHelper == null) {throw new NullPointerException("You need to init mHelper first!");}mAbstractDao = mDaoSession.getDao(entityClass);}
4.3 增删改查(主线程)

下面的增删改查方法,是在主线程运行的,在数据量较小时,影响很小,不会造成线程堵塞或者 ANR。

    /*** 获取数据库Item的数量** @return*/public <T> Long count(Class<T> entityClaz) {setCurrentDao(entityClaz);return mAbstractDao.count();}/*** 插入一条数据** @param dbEntity*/public <T> void insert(T dbEntity) {setCurrentDao(dbEntity.getClass());mAbstractDao.insert(dbEntity);}/*** 插入一条数据** @param dbEntity*/public <T> void insertOrReplace(T dbEntity) {setCurrentDao(dbEntity.getClass());mAbstractDao.insertOrReplace(dbEntity);}/*** 插入多条数据** @param entities*/public <T> void insertTx(List<T> entities) {if (entities == null || entities.size() < 1) {return;}setCurrentDaoOfList(entities);mAbstractDao.insertInTx(entities);}public <T> void insertOrReplaceInTx(List<T> entities) {if (entities == null || entities.size() < 1) {return;}setCurrentDaoOfList(entities);mAbstractDao.insertOrReplaceInTx(entities);}/*** 删除单条数据** @param entity*/public <T> void delete(T entity) {setCurrentDao(entity.getClass());mAbstractDao.delete(entity);}/*** 删除特定ID的数据** @param id*/public <T> void deleteById(Class<T> entityClaz, long id) {setCurrentDao(entityClaz);mAbstractDao.deleteByKey(id);}/*** 删除多条数据** @param entities*/public <T> void deleteList(List<T> entities) {setCurrentDaoOfList(entities);mAbstractDao.deleteInTx(entities);}/*** 全部删除*/public<T> void deleteAll(Class<T> claz) {setCurrentDao(claz);mAbstractDao.deleteAll();}/*** 更新单条数据** @param entity*/public <T> void updateData(final T entity) {setCurrentDao(entity.getClass());mAbstractDao.update(entity);}/*** 更新多条数据** @param entities*/public <T> void updateListData(Collection<T> entities) {setCurrentDaoOfList(entities);mAbstractDao.updateInTx(entities);}/*** 查询特定ID的数据** @param id* @return*/public <T> T queryById(Class<T> claz,long id) {setCurrentDao(claz);return (T) mAbstractDao.load(id);}/*** 查询全部数据** @return*/public <T> List<T> queryAll(Class<T> claz) {setCurrentDao(claz);return mAbstractDao.loadAll();}/***  原生查询* @param claz* @param whereString* @param params* @param <T>* @return*/public <T> List<T> queryRaw(Class<T> claz,String whereString, String[] params) {setCurrentDao(claz);return mAbstractDao.queryRaw(whereString, params);}
4.4 异步查询

异步操作需要设置回调,回调中可以将结果返回来,比如查询时,拿到查询的结果。

/*** 异步操作的回调设置* @param callBack* @param <T>* @return*/public <T> DbUtil setDbCallBack(DbCallBack<T> callBack) {mCallBack = callBack;return this;}/*** 条件查询数据** @param cls* @return*/public <T> void queryAsync(Class<T> cls, WhereCondition whereCondition) {setCurrentDao(cls);AsyncSession asyncSession = mDaoSession.startAsyncSession();asyncSession.setListenerMainThread(new AsyncOperationListener() {@Overridepublic void onAsyncOperationCompleted(AsyncOperation operation) {if (operation.isCompletedSucessfully() && mCallBack != null) {List<T> list = new ArrayList<>();list.add(((T) operation.getResult()));mCallBack.onSuccess(list);} else if (operation.isFailed()) {mCallBack.onFailed();}}});Query query = mDaoSession.queryBuilder(cls).where(whereCondition).build();asyncSession.queryUnique(query);}/*** @param claz* @param query 可使用 getQuery 方法获取 Query* @param <T>*/public <T> void queryAsyncAll(Class<T> claz, Query<T> query) {setCurrentDao(claz);AsyncSession asyncSession = mDaoSession.startAsyncSession();asyncSession.setListenerMainThread(new AsyncOperationListener() {@Overridepublic void onAsyncOperationCompleted(AsyncOperation operation) {if (operation.isCompleted() && mCallBack != null) {List<T> result = (List<T>) operation.getResult();mCallBack.onSuccess(result);} else if (operation.isFailed() && mCallBack != null) {mCallBack.onFailed();}}});if (query == null) {asyncSession.loadAll(claz);} else {asyncSession.queryList(query);}}/*** 删除*/public <T> void deleteAsyncSingle(T entry) {setCurrentDao(entry.getClass());AsyncSession asyncSession = mDaoSession.startAsyncSession();asyncSession.setListenerMainThread(new AsyncOperationListener() {@Overridepublic void onAsyncOperationCompleted(AsyncOperation operation) {if (operation.isCompletedSucessfully() && mCallBack != null) {mCallBack.onNotification(true);} else if (operation.isFailed() && mCallBack != null) {mCallBack.onNotification(false);}}});asyncSession.delete(entry);}/*** 批量删除*/public <T> void deleteAsyncBatch(Class<T> cls, final List<T> list) {setCurrentDao(cls);AsyncSession asyncSession = mDaoSession.startAsyncSession();asyncSession.setListenerMainThread(new AsyncOperationListener() {@Overridepublic void onAsyncOperationCompleted(AsyncOperation operation) {if (operation.isCompletedSucessfully() && mCallBack != null) {mCallBack.onNotification(true);} else if (operation.isFailed() && mCallBack != null) {mCallBack.onNotification(false);}}});asyncSession.deleteInTx(cls, list);}/*** 根据Id批量删除*/public<T> void deleteByIdBatch(Class<T> claz,List<Long> longList) {setCurrentDao(claz);mAbstractDao.deleteByKeyInTx(longList);}/*** 删除所有数据*/public <T> void deleteAsyncAll(Class<T> cls) {setCurrentDao(cls);final AsyncSession asyncSession = mDaoSession.startAsyncSession();asyncSession.setListenerMainThread(new AsyncOperationListener() {@Overridepublic void onAsyncOperationCompleted(AsyncOperation operation) {if (operation.isCompletedSucessfully() && mCallBack != null) {mCallBack.onNotification(true);} else if (operation.isFailed() && mCallBack != null) {mCallBack.onNotification(false);}}});asyncSession.deleteAll(cls);}/*** 插入一条数据*/public <T> void insertAsyncSingle(final T entity) {setCurrentDao(entity.getClass());AsyncSession asyncSession = mDaoSession.startAsyncSession();asyncSession.setListenerMainThread(new AsyncOperationListener() {@Overridepublic void onAsyncOperationCompleted(AsyncOperation operation) {if (operation.isCompletedSucessfully() && mCallBack != null) {mCallBack.onNotification(true);} else if (operation.isFailed() && mCallBack != null) {mCallBack.onNotification(false);}}});asyncSession.runInTx(new Runnable() {@Overridepublic void run() {mDaoSession.insert(entity);}});}/*** 批量插入*/public <T> void insertAsyncBatch(final Class<T> cls, final List<T> userList) {setCurrentDao(cls);AsyncSession asyncSession = mDaoSession.startAsyncSession();asyncSession.setListenerMainThread(new AsyncOperationListener() {@Overridepublic void onAsyncOperationCompleted(AsyncOperation operation) {if (operation.isCompletedSucessfully() && mCallBack != null) {mCallBack.onNotification(true);} else if (operation.isFailed() && mCallBack != null) {mCallBack.onNotification(false);}}});asyncSession.runInTx(new Runnable() {@Overridepublic void run() {for (T object : userList) {mDaoSession.insertOrReplace(object);}}});}/*** 更新一个数据*/public <T> void updateAsyncSingle(Class<T> cls, T entry) {setCurrentDao(cls);AsyncSession asyncSession = mDaoSession.startAsyncSession();asyncSession.setListenerMainThread(new AsyncOperationListener() {@Overridepublic void onAsyncOperationCompleted(AsyncOperation operation) {if (operation.isCompletedSucessfully() && mCallBack != null) {mCallBack.onNotification(true);} else if (operation.isFailed() && mCallBack != null) {mCallBack.onNotification(false);}}});asyncSession.update(entry);}/*** 批量更新数据*/public <T> void updateAsyncBatch(final Class<T> cls, final List<T> tList) {setCurrentDao(cls);AsyncSession asyncSession = mDaoSession.startAsyncSession();asyncSession.setListenerMainThread(new AsyncOperationListener() {@Overridepublic void onAsyncOperationCompleted(AsyncOperation operation) {if (operation.isCompletedSucessfully() && mCallBack != null) {mCallBack.onNotification(true);} else if (operation.isFailed() && mCallBack != null) {mCallBack.onNotification(false);}}});asyncSession.updateInTx(cls, tList);}

上面的方法异步操作没什么可说的,只是看到异步查询的方法中有些参数是 WhereCondition ,有些是 Query。上面提到过 mDaoSession.queryBuilder(claz); 来获取 QueryBuilder,通过 QueryBuilder 再获取 Query。WhereCondition 是查询条件,下面看这样一个使用,你就明白了。

// 把 WhereCondition 附加到 QueryBuilder 上,作为 where 的查询条件设置,最终得到 Query
Query query = mDaoSession.queryBuilder(cls).where(whereCondition).build();

这里重点强调一下,WhereCondition,QueryBuilder,Query 都是 greenDAO 中的类,我们在依赖时有两种方式:
(Android Studio 3.0 以后用法)

  • api
  • implementation
implementation 只能在内部使用此模块,比如一个 libiary 中使用 implementation 依赖了 greenDAO,然后主项目依赖了 libiary,那么,我的主项目就无法访问 greenDAO 中的方法。这样的好处是编译速度会加快,推荐使用 implementation 的方式去依赖,如果你需要提供给外部访问,那么就使用 api 依赖即可。

所以:

(1)如果使用这个工具类时,放在你的主工程下,直接使用 WhereCondition,QueryBuilder,Query 这个几个类是没有问题的。

(2)如果你是将该工具类放在 libiary 中,采用 api 方式依赖,同样也没有问题,直接使用这几个类的方法,因为能够引入这几个类。

(3)关键是这点,将该工具类放在 libiary 中,采用 implementation 方式依赖,这时,你的主工程中将看不到 WhereCondition,QueryBuilder,Query 这个几个类,这时候该怎么办呢?这一点目前么有好的办法,想把 WhereCondition,QueryBuilder,Query再封装一层,有些麻烦,干脆还是采用 (2)中的方式来得简单。

5. greenDAO 工具类封装

5.1 设置

对于 Entity 可以放在 数据库模块中,同时将生成的 DAO 也放在该模块下, 这样能够减少主模块中类的数量,如果有多个模块引用数据库模块,Entity 可以增加包来区分属于不同的模块。以下是数据模块目录结构的示例(Entity 未细分包)

gradle设置DAO生成的路径,以及应用数据的方式,采用 api 方式

5.2 数据路工具类

上面已经提到增删改查的封装,下面给出完整的代码。
工具类代码

    public class DbUtil {private static final String DEFAULT_DATABASE_NAME = "Database.db";private static final String DEFAULT_DATABASE_PASSWORD = "hahaha";private DaoSession mDaoSession;private DaoMaster mDaoMaster;private AbstractDao mAbstractDao;private static DbUtil mDbUtils;private DaoMaster.DevOpenHelper mHelper;private DbCallBack mCallBack;private DbUtil(Application application, String dbName, String passWord) {if (mHelper == null) {mHelper = new DaoMaster.DevOpenHelper(application, dbName);}if (passWord == null || passWord.isEmpty()) {mDaoMaster = new DaoMaster(mHelper.getWritableDb());} else {mDaoMaster = new DaoMaster(mHelper.getEncryptedReadableDb(passWord));}mDaoSession = mDaoMaster.newSession();}public static DbUtil getInstance(Application application) {return getInstance(application, DEFAULT_DATABASE_NAME);}public static DbUtil getInstance(Application application, String dbName) {return getInstance(application, dbName, "");}public static DbUtil getInstance(Application application, String dbName, String passWord) {if (mDbUtils == null) {synchronized (DbUtil.class) {if (mDbUtils == null) {mDbUtils = new DbUtil(application, dbName, passWord);}}}return mDbUtils;}public <T> Query<T> getQuery(Class<T> claz){return getQueryBuilder(claz).build();}public <T> QueryBuilder<T> getQueryBuilder(Class<T> claz){return mDaoSession.queryBuilder(claz);}/*** 获取数据库Item的数量** @return*/public <T> Long count(Class<T> entityClaz) {setCurrentDao(entityClaz);return mAbstractDao.count();}/*** 插入一条数据** @param dbEntity*/public <T> void insert(T dbEntity) {setCurrentDao(dbEntity.getClass());mAbstractDao.insert(dbEntity);}/*** 插入一条数据** @param dbEntity*/public <T> void insertOrReplace(T dbEntity) {setCurrentDao(dbEntity.getClass());mAbstractDao.insertOrReplace(dbEntity);}/*** 插入多条数据** @param entities*/public <T> void insertTx(List<T> entities) {if (entities == null || entities.size() < 1) {return;}setCurrentDaoOfList(entities);mAbstractDao.insertInTx(entities);}public <T> void insertOrReplaceInTx(List<T> entities) {if (entities == null || entities.size() < 1) {return;}setCurrentDaoOfList(entities);mAbstractDao.insertOrReplaceInTx(entities);}/*** 删除单条数据** @param entity*/public <T> void delete(T entity) {setCurrentDao(entity.getClass());mAbstractDao.delete(entity);}/*** 删除特定ID的数据** @param id*/public <T> void deleteById(Class<T> entityClaz, long id) {setCurrentDao(entityClaz);mAbstractDao.deleteByKey(id);}/*** 删除多条数据** @param entities*/public <T> void deleteList(List<T> entities) {setCurrentDaoOfList(entities);mAbstractDao.deleteInTx(entities);}/*** 全部删除*/public <T> void deleteAll(Class<T> claz) {setCurrentDao(claz);mAbstractDao.deleteAll();}/*** 更新单条数据** @param entity*/public <T> void updateData(final T entity) {setCurrentDao(entity.getClass());mAbstractDao.update(entity);}/*** 更新多条数据** @param entities*/public <T> void updateListData(Collection<T> entities) {setCurrentDaoOfList(entities);mAbstractDao.updateInTx(entities);}/*** 查询特定ID的数据** @param id* @return*/public <T> T queryById(Class<T> claz, long id) {setCurrentDao(claz);return (T) mAbstractDao.load(id);}/*** 查询全部数据** @return*/public <T> List<T> queryAll(Class<T> claz) {setCurrentDao(claz);return mAbstractDao.loadAll();}public <T> List<T> queryAll(Class<T> claz,WhereCondition whereCondition) {setCurrentDao(claz);return mDaoSession.queryBuilder(claz).where(whereCondition).list();}public <T> List<T> queryAll(Class<T> claz,QueryBuilder<T> queryBuilder) {setCurrentDao(claz);return mDaoSession.queryBuilder(claz).list();}public <T> List<T> queryAll(Class<T> claz,Query<T> query) {setCurrentDao(claz);return query.list();}/*** 原生查询** @param claz* @param whereString* @param params* @param <T>* @return*/public <T> List<T> queryRaw(Class<T> claz, String whereString, String[] params) {setCurrentDao(claz);return mAbstractDao.queryRaw(whereString, params);}/*** 异步操作的回调设置** @param callBack* @param <T>* @return*/public <T> DbUtil setDbCallBack(DbCallBack<T> callBack) {mCallBack = callBack;return this;}/*** 条件查询数据** @param cls* @return*/public <T> void queryAsync(Class<T> cls, WhereCondition whereCondition) {setCurrentDao(cls);AsyncSession asyncSession = mDaoSession.startAsyncSession();asyncSession.setListenerMainThread(new AsyncOperationListener() {@Overridepublic void onAsyncOperationCompleted(AsyncOperation operation) {if (operation.isCompletedSucessfully() && mCallBack != null) {List<T> list = new ArrayList<>();list.add(((T) operation.getResult()));mCallBack.onSuccess(list);} else if (operation.isFailed()) {mCallBack.onFailed();}}});Query query = mDaoSession.queryBuilder(cls).where(whereCondition).build();asyncSession.queryUnique(query);}/*** 异步条件查询,通过使用 QueryBuilder 构造 Query* @param claz* @param builder* @param <T>*/public <T> void queryAsyncAll(Class<T> claz, QueryBuilder<T> builder) {setCurrentDao(claz);AsyncSession asyncSession = mDaoSession.startAsyncSession();asyncSession.setListenerMainThread(new AsyncOperationListener() {@Overridepublic void onAsyncOperationCompleted(AsyncOperation operation) {if (operation.isCompleted() && mCallBack != null) {List<T> result = (List<T>) operation.getResult();mCallBack.onSuccess(result);} else if (operation.isFailed() && mCallBack != null) {mCallBack.onFailed();}}});if (builder == null || builder.build() == null) {asyncSession.loadAll(claz);} else {asyncSession.queryList(builder.build());}}/*** 删除*/public <T> void deleteAsyncSingle(T entry) {setCurrentDao(entry.getClass());AsyncSession asyncSession = mDaoSession.startAsyncSession();asyncSession.setListenerMainThread(new AsyncOperationListener() {@Overridepublic void onAsyncOperationCompleted(AsyncOperation operation) {if (operation.isCompletedSucessfully() && mCallBack != null) {mCallBack.onNotification(true);} else if (operation.isFailed() && mCallBack != null) {mCallBack.onNotification(false);}}});asyncSession.delete(entry);}/*** 批量删除*/public <T> void deleteAsyncBatch(Class<T> cls, final List<T> list) {setCurrentDao(cls);AsyncSession asyncSession = mDaoSession.startAsyncSession();asyncSession.setListenerMainThread(new AsyncOperationListener() {@Overridepublic void onAsyncOperationCompleted(AsyncOperation operation) {if (operation.isCompletedSucessfully() && mCallBack != null) {mCallBack.onNotification(true);} else if (operation.isFailed() && mCallBack != null) {mCallBack.onNotification(false);}}});asyncSession.deleteInTx(cls, list);}/*** 根据Id批量删除*/public <T> void deleteByIdBatch(Class<T> claz, List<Long> longList) {setCurrentDao(claz);mAbstractDao.deleteByKeyInTx(longList);}/*** 删除所有数据*/public <T> void deleteAsyncAll(Class<T> cls) {setCurrentDao(cls);final AsyncSession asyncSession = mDaoSession.startAsyncSession();asyncSession.setListenerMainThread(new AsyncOperationListener() {@Overridepublic void onAsyncOperationCompleted(AsyncOperation operation) {if (operation.isCompletedSucessfully() && mCallBack != null) {mCallBack.onNotification(true);} else if (operation.isFailed() && mCallBack != null) {mCallBack.onNotification(false);}}});asyncSession.deleteAll(cls);}/*** 插入一条数据*/public <T> void insertAsyncSingle(final T entity) {setCurrentDao(entity.getClass());AsyncSession asyncSession = mDaoSession.startAsyncSession();asyncSession.setListenerMainThread(new AsyncOperationListener() {@Overridepublic void onAsyncOperationCompleted(AsyncOperation operation) {if (operation.isCompletedSucessfully() && mCallBack != null) {mCallBack.onNotification(true);} else if (operation.isFailed() && mCallBack != null) {mCallBack.onNotification(false);}}});asyncSession.runInTx(new Runnable() {@Overridepublic void run() {mDaoSession.insert(entity);}});}/*** 批量插入*/public <T> void insertAsyncBatch(final Class<T> cls, final List<T> userList) {setCurrentDao(cls);AsyncSession asyncSession = mDaoSession.startAsyncSession();asyncSession.setListenerMainThread(new AsyncOperationListener() {@Overridepublic void onAsyncOperationCompleted(AsyncOperation operation) {if (operation.isCompletedSucessfully() && mCallBack != null) {mCallBack.onNotification(true);} else if (operation.isFailed() && mCallBack != null) {mCallBack.onNotification(false);}}});asyncSession.runInTx(new Runnable() {@Overridepublic void run() {for (T object : userList) {mDaoSession.insertOrReplace(object);}}});}/*** 更新一个数据*/public <T> void updateAsyncSingle(Class<T> cls, T entry) {setCurrentDao(cls);AsyncSession asyncSession = mDaoSession.startAsyncSession();asyncSession.setListenerMainThread(new AsyncOperationListener() {@Overridepublic void onAsyncOperationCompleted(AsyncOperation operation) {if (operation.isCompletedSucessfully() && mCallBack != null) {mCallBack.onNotification(true);} else if (operation.isFailed() && mCallBack != null) {mCallBack.onNotification(false);}}});asyncSession.update(entry);}/*** 批量更新数据*/public <T> void updateAsyncBatch(final Class<T> cls, final List<T> tList) {setCurrentDao(cls);AsyncSession asyncSession = mDaoSession.startAsyncSession();asyncSession.setListenerMainThread(new AsyncOperationListener() {@Overridepublic void onAsyncOperationCompleted(AsyncOperation operation) {if (operation.isCompletedSucessfully() && mCallBack != null) {mCallBack.onNotification(true);} else if (operation.isFailed() && mCallBack != null) {mCallBack.onNotification(false);}}});asyncSession.updateInTx(cls, tList);}/*** 关闭DaoSession*/private void closeDaoSession() {if (mDaoSession != null) {mDaoSession.clear();mDaoSession = null;}}/*** 关闭Helper*/private void closeHelper() {if (mHelper != null) {mHelper.close();mHelper = null;}}/*** 关闭所有的操作*/public void closeConnection() {closeDaoSession();closeHelper();}/*** 数据库不加密** @param entityClass 根据 entityClass 获取相应的 xxDao* @return mDbUtils*/@Deprecatedpublic DbUtil create(Class<?> entityClass) {if (mHelper == null) {throw new NullPointerException("You need to init mHelper first!");}mAbstractDao = mDaoSession.getDao(entityClass);return mDbUtils;}private <T> void setCurrentDao(Class<T> entityClass) {if (mHelper == null) {throw new NullPointerException("You need to init mHelper first!");}mAbstractDao = mDaoSession.getDao(entityClass);}private <T> void setCurrentDaoOfList(Collection<T> entities) {if (entities != null && entities.size() > 1) {Iterator<T> iterator = entities.iterator();T next = iterator.next();setCurrentDao(next.getClass());}}
}

回调接口

public interface DbCallBack<T> {void onSuccess(List<T> result);void onFailed();void onNotification(boolean result);
}
5.3 使用示例

下面看一个示例:

public class MainActivity extends AppCompatActivity implements View.OnClickListener {private DbUtil dbUtil;...// 异步查询回调DbCallBack<Student> studentDbCallBack = new DbCallBack<Student>() {@Overridepublic void onSuccess(List<Student> result) {if (result.size() > 0) {for (Student student1 : result) {Log.e(TAG, "[4] " + student1.toString());}}}@Overridepublic void onFailed() {}@Overridepublic void onNotification(boolean result) {}};@Overridepublic void onClick(View v) {int id = v.getId();switch (id) {case R.id.delete_btn:// 删除if (dbUtil.count(Clazz.class) > 0) {dbUtil.deleteAll(Clazz.class);}break;case R.id.insert_btn:// 批量插入dbUtil.insertOrReplaceInTx(clazzList);dbUtil.insertOrReplaceInTx(studentList);break;case R.id.query_btn:// 单条查询Clazz cls = dbUtil.queryById(Clazz.class,1);// 查询所有的班级List<Clazz> clazList = dbUtil.queryAll(Clazz.class);for (Clazz clazz : clazList) {Log.e(TAG, "[1] " + clazz.toString());}// 查询所有学生List<Student> studentList = dbUtil.queryAll(Student.class);for (Student student : studentList) {Log.e(TAG, "[2] " + student.toString());}//条件查询final List<Student> student = dbUtil.queryRaw(Student.class, "where studentID = ?", new String[]{"12"});Log.e(TAG, "[3] " + student.get(0).toString());// 异步查询DbCallBack<Student> studentDbCallBack = new DbCallBack<Student>() {@Overridepublic void onSuccess(List<Student> result) {if (result.size() > 0) {for (Student student1 : result) {Log.e(TAG, "[4] " + student1.toString());}}}@Overridepublic void onFailed() {}@Overridepublic void onNotification(boolean result) {}};dbUtil.setDbCallBack(studentDbCallBack).queryAsync(Student.class, StudentDao.Properties.StudentID.eq(19));// 批量异步条件查询QueryBuilder<Student> builder = dbUtil.getQueryBuilder(Student.class).where(StudentDao.Properties.StudentID.between(12, 16));dbUtil.setDbCallBack(studentDbCallBack).queryAsyncAll(Student.class, builder);// 批量同步条件查询QueryBuilder<Student> builder1 = dbUtil.getQueryBuilder(Student.class).limit(3).distinct().offset(2);List<Student> list = dbUtil.queryAll(Student.class, builder1);for (Student student1 : list) {Log.e(TAG, "[4] " + student1.toString());}break;case R.id.join_btn:// 多表查询QueryBuilder<Student> builder2 = dbUtil.getQueryBuilder(Student.class);builder2.join(StudentDao.Properties.ClazID, Clazz.class).where(ClazzDao.Properties.Id.eq(1));List<Student> studentList1 = builder2.list();for (Student student2 : studentList1) {Log.e(TAG, "" + student2.toString());}break;}

注意

对于 WhereCondition,一般使用 DAO 来构造

    StudentDao.Properties.StudentID.eq(19)

5 总结

greenDAO 使用起来稍微有一点麻烦,但是效率高,这个我也是看其他文章这么写的,没有亲自试过,有兴趣的小伙伴可以尝试测试测试。至于它的封装,目前我也没有想到更好的方式,如果有更好的方式可以拿出来分享,或者对的上面的封装有改进的地方,也可以提出优化的意见!

代码地址

参考:

greenDAO 官网

greendao 3.0集成和使用封装

GreenDao3.0 高级用法

数据库调试工具

这篇关于数据库学习之 greenDAO 实战的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


原文地址:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.chinasem.cn/article/1036030

相关文章

Go学习记录之runtime包深入解析

《Go学习记录之runtime包深入解析》Go语言runtime包管理运行时环境,涵盖goroutine调度、内存分配、垃圾回收、类型信息等核心功能,:本文主要介绍Go学习记录之runtime包的... 目录前言:一、runtime包内容学习1、作用:① Goroutine和并发控制:② 垃圾回收:③ 栈和

Android学习总结之Java和kotlin区别超详细分析

《Android学习总结之Java和kotlin区别超详细分析》Java和Kotlin都是用于Android开发的编程语言,它们各自具有独特的特点和优势,:本文主要介绍Android学习总结之Ja... 目录一、空安全机制真题 1:Kotlin 如何解决 Java 的 NullPointerExceptio

Java Spring 中的监听器Listener详解与实战教程

《JavaSpring中的监听器Listener详解与实战教程》Spring提供了多种监听器机制,可以用于监听应用生命周期、会话生命周期和请求处理过程中的事件,:本文主要介绍JavaSprin... 目录一、监听器的作用1.1 应用生命周期管理1.2 会话管理1.3 请求处理监控二、创建监听器2.1 Ser

Apache 高级配置实战之从连接保持到日志分析的完整指南

《Apache高级配置实战之从连接保持到日志分析的完整指南》本文带你从连接保持优化开始,一路走到访问控制和日志管理,最后用AWStats来分析网站数据,对Apache配置日志分析相关知识感兴趣的朋友... 目录Apache 高级配置实战:从连接保持到日志分析的完整指南前言 一、Apache 连接保持 - 性

Druid连接池实现自定义数据库密码加解密功能

《Druid连接池实现自定义数据库密码加解密功能》在现代应用开发中,数据安全是至关重要的,本文将介绍如何在​​Druid​​连接池中实现自定义的数据库密码加解密功能,有需要的小伙伴可以参考一下... 目录1. 环境准备2. 密码加密算法的选择3. 自定义 ​​DruidDataSource​​ 的密码解密3

Maven项目中集成数据库文档生成工具的操作步骤

《Maven项目中集成数据库文档生成工具的操作步骤》在Maven项目中,可以通过集成数据库文档生成工具来自动生成数据库文档,本文为大家整理了使用screw-maven-plugin(推荐)的完... 目录1. 添加插件配置到 pom.XML2. 配置数据库信息3. 执行生成命令4. 高级配置选项5. 注意事

MQTT SpringBoot整合实战教程

《MQTTSpringBoot整合实战教程》:本文主要介绍MQTTSpringBoot整合实战教程,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考... 目录MQTT-SpringBoot创建简单 SpringBoot 项目导入必须依赖增加MQTT相关配置编写

在Java中基于Geotools对PostGIS数据库的空间查询实践教程

《在Java中基于Geotools对PostGIS数据库的空间查询实践教程》本文将深入探讨这一实践,从连接配置到复杂空间查询操作,包括点查询、区域范围查询以及空间关系判断等,全方位展示如何在Java环... 目录前言一、相关技术背景介绍1、评价对象AOI2、数据处理流程二、对AOI空间范围查询实践1、空间查

Python+PyQt5实现MySQL数据库备份神器

《Python+PyQt5实现MySQL数据库备份神器》在数据库管理工作中,定期备份是确保数据安全的重要措施,本文将介绍如何使用Python+PyQt5开发一个高颜值,多功能的MySQL数据库备份工具... 目录概述功能特性核心功能矩阵特色功能界面展示主界面设计动态效果演示使用教程环境准备操作流程代码深度解

JavaScript实战:智能密码生成器开发指南

本文通过JavaScript实战开发智能密码生成器,详解如何运用crypto.getRandomValues实现加密级随机密码生成,包含多字符组合、安全强度可视化、易混淆字符排除等企业级功能。学习密码强度检测算法与信息熵计算原理,获取可直接嵌入项目的完整代码,提升Web应用的安全开发能力 目录