数据库学习之 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

相关文章

网页解析 lxml 库--实战

lxml库使用流程 lxml 是 Python 的第三方解析库,完全使用 Python 语言编写,它对 XPath表达式提供了良好的支 持,因此能够了高效地解析 HTML/XML 文档。本节讲解如何通过 lxml 库解析 HTML 文档。 pip install lxml lxm| 库提供了一个 etree 模块,该模块专门用来解析 HTML/XML 文档,下面来介绍一下 lxml 库

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

性能分析之MySQL索引实战案例

文章目录 一、前言二、准备三、MySQL索引优化四、MySQL 索引知识回顾五、总结 一、前言 在上一讲性能工具之 JProfiler 简单登录案例分析实战中已经发现SQL没有建立索引问题,本文将一起从代码层去分析为什么没有建立索引? 开源ERP项目地址:https://gitee.com/jishenghua/JSH_ERP 二、准备 打开IDEA找到登录请求资源路径位置

MySQL数据库宕机,启动不起来,教你一招搞定!

作者介绍:老苏,10余年DBA工作运维经验,擅长Oracle、MySQL、PG、Mongodb数据库运维(如安装迁移,性能优化、故障应急处理等)公众号:老苏畅谈运维欢迎关注本人公众号,更多精彩与您分享。 MySQL数据库宕机,数据页损坏问题,启动不起来,该如何排查和解决,本文将为你说明具体的排查过程。 查看MySQL error日志 查看 MySQL error日志,排查哪个表(表空间

C#实战|大乐透选号器[6]:实现实时显示已选择的红蓝球数量

哈喽,你好啊,我是雷工。 关于大乐透选号器在前面已经记录了5篇笔记,这是第6篇; 接下来实现实时显示当前选中红球数量,蓝球数量; 以下为练习笔记。 01 效果演示 当选择和取消选择红球或蓝球时,在对应的位置显示实时已选择的红球、蓝球的数量; 02 标签名称 分别设置Label标签名称为:lblRedCount、lblBlueCount

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]