目录索引
1.依赖添加
在根目录下的build.gradle添加配置:
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.0.1'
//greendao配置
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
}
}
接着在app下的build.gradle文件添加配置:
apply plugin: 'com.android.application'
//1.添加插件
apply plugin: 'org.greenrobot.greendao'
android {
compileSdkVersion 26
defaultConfig {
applicationId "com.test.demo"
minSdkVersion 19
targetSdkVersion 26
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
multiDexEnabled true
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
greendao {
//2.指定数据库版本号,迁移等操作会用到
schemaVersion 3
}
}
dependencies {
//添加依赖
implementation 'org.greenrobot:greendao:3.2.2'
}
2.数据库创建与升级
依赖已经添加到我们的项目中了,接下来是使用。首先要初始化几个参数:
private MyDateBaseHelper mHelper= new MyDateBaseHelper(new GreenDaoContext(instance), "数据库名称");
private SQLiteDatabase mDatabase = mHelper.getWritableDatabase();
private DaoSession mDaoSession = mDaoMaster.newSession();
private DaoMaster mDaoMaster= new DaoMaster(mDatabase);
MyDateBaseHelper呢是一个继承至 DaoMaster.DevOpenHelper的一个类,当然也可以直接使用DaoMaster.DevOpenHelper对象代替MyDateBaseHelper类:
DaoMaster.DevOpenHelper mHelper = new DaoMaster.DevOpenHelper(new GreenDaoContext(instance), "数据库名称");
说明一下作为Context 类型的实例的 GreenDaoContext(instance)类。这个类继承了ContextWrapper,主要自定义数据库创建路径。默认情况下我们的数据库是在data/data/....路径下,而使用自定义路径的数据库会方便管理。这个方法也是来源于其他前辈,博主的。(感谢前辈,大佬铺路QAQ)
public class GreenDaoContext extends ContextWrapper {
private static String TAG = "GreenDaoContext";
/**
* SD卡下文件目录名称
* 一般用来针对一个用户一个数据库,以免数据混乱问题
*/
private String currentUserId = "数据库所在文件夹名称";
private Context mContext;
public GreenDaoContext(Context context) {
super(context);
this.mContext = context;
}
/**
* 获得数据库路径,如果不存在,则创建对象
* @param dbName
*/
@Override
public File getDatabasePath(String dbName) {
//选择sdcard作为数据库存放路径
String dbDir = Environment.getExternalStorageDirectory().getPath();
if (TextUtils.isEmpty(dbDir)) {
return null;
}
File baseFile = new File(dbDir);
if (!baseFile.exists()) {
baseFile.mkdirs();
}
StringBuffer buffer = new StringBuffer();
buffer.append(baseFile.getPath());
buffer.append(File.separator);
buffer.append(currentUserId);
dbDir = buffer.toString();// 数据库所在目录
buffer.append(File.separator);
buffer.append(dbName);
String dbPath = buffer.toString();// 数据库路径
Log.d(TAG, dbPath);
File dirFile = new File(dbDir);
if (!dirFile.exists()) {
dirFile.mkdirs();
}
boolean isFileCreateSuccess = false;
File dbFile = new File(dbPath);
if (!dbFile.exists()) {
try {
isFileCreateSuccess = dbFile.createNewFile();// 创建文件
} catch (IOException e) {
e.printStackTrace();
}
} else
isFileCreateSuccess = true;
// 返回数据库文件对象
if (isFileCreateSuccess)
return dbFile;
else
return super.getDatabasePath(dbName);
}
/**
* 重载这个方法,是用来打开SD卡上的数据库的,android 2.3及以下会调用这个方法。 *
* @param name
* @param mode
* @param factory
*/
@Override
public SQLiteDatabase openOrCreateDatabase(String name, int mode, SQLiteDatabase.CursorFactory factory) {
SQLiteDatabase result = SQLiteDatabase.openOrCreateDatabase(getDatabasePath(name), factory);
return result;
}
/**
* Android 4.0会调用此方法获取数据库。 *
* @param name
* @param mode
* @param factory
* @param errorHandler
* @see android.content.ContextWrapper#openOrCreateDatabase(java.lang.String, int,
* android.database.sqlite.SQLiteDatabase.CursorFactory,
* android.database.DatabaseErrorHandler)
*/
@Override
public SQLiteDatabase openOrCreateDatabase(String name, int mode, SQLiteDatabase.CursorFactory factory, DatabaseErrorHandler errorHandler) {
SQLiteDatabase result = SQLiteDatabase.openOrCreateDatabase(getDatabasePath(name), factory);
return result;
}
}
MyDateBaseHelper:
public class MyDateBaseHelper extends DaoMaster.DevOpenHelper {
public MyDateBaseHelper(Context context, String name) {
super(context, name, null);
}
@Override
public void onUpgrade(Database db, int oldVersion, int newVersion) {
//数据库升级
MigrationHelper.migrate(db, new MigrationHelper.ReCreateAllTableListener() {
@Override
public void onCreateAllTables(Database db, boolean ifNotExists) {
DaoMaster.createAllTables(db, ifNotExists);
}
@Override
public void onDropAllTables(Database db, boolean ifExists) {
DaoMaster.dropAllTables(db, ifExists);
}
}, xxxxDao.class,yyyyDao.class,.....);
}
}
MigrationHelper是数据库升级处理方法,因为这个工具类篇幅太长,另开一篇记录MigrationHelper数据升级库迁移类。
3.实体类编写
实体类跟自己写的普通数据类是一样的,只是多了一些数据的注解,如下例子:
@Entity(nameInDb = "goods")
public class Goods{
@Id(autoincrement = true)
private Long id;
private Long goodsId;
}
其中@Entity(nameInDb = "goods")就是标识这个数据类在数据库里的表名称为 goods。@ID则是作为表中的主键,后面的autoincrement = true则表示为自动增长。其他的注解:
- @Convert :指定该字段为PropertyConverter支持的自定义类型。要在实体中使用自定义类型,要实现PropertyConverter接口,将db值转换为实体值并返回。
- @Entity(nameInDb = "goods") : 声明为这是一个表,只有被这个注解的实体类才能进行dao操作。可设置8个参数;参数 nameInDb 表示表名,默认为类名;还有其他参数:createInDb-是否创建表在数据库,默认为true;generateConstructors-是否自动生成构造方法,默认为true;indexes-实体类的索引;generateGettersSetters-是否自动创建getset方法,默认true等等,只列举几个比较容易用到的。
- @Generated :表示为自动生成的代码,不能被修改。
- @Id(autoincrement = true) :声明为数据库主键。只有一个参数:autoincrement- 为是否自动增长,默认为false
- @Index :指定这个属性可以被索引,有3个参数:value-编入索引的属性列表,只有当@Entity设置了indexes参数时才应该设置这个值;name-索引的别名;unique-是否以此属性创建唯一约束,默认false。
- @JoinEntity :用于连接表定义表关系(多数用于多对多关系,需要定义中间表的时候)。有3个参数:entity-两个关系表的中间表(类),sourceProperty-持有源(当前实体)的属性(字段),多定义为当前实体主键;targetProperty-对应目标的属性(字段)。
- @JoinProperty :为表关系定义name和referencedName关联属性。
- @Keep :使用此注解的目标在greenDAO生成的下一次运行期间保存,不会发生修改。在实体类本身上使用此注释将禁用任何类修改,用户负责编写和支持greenDAO所需的任何代码。通常情况下不要在类成员上使用此注释,因为发生模型变更时,greenDAO将无法对目标代码进行相应的变更。
- @NotNull :该字段不能为null。
- @OrderBy :排序。注意指定为ToMany下关系的排列顺序,使用如@OrderBy("name DESC"),字段名称,排序顺序
- @Property(nameInDb = "") :声明为数据库中字段名称。默认为类属性名称。
- @ToMany :表关系,一对多或多对多。
- @ToOne :表关系,一对一。
- @Transient : 表示该属性不会在数据库中生成对应的字段
- @Unique :是否以此属性创建唯一约束,默认false
实体类也编写好了,需要使用AS 工具make project(绿色的锤子)就会自动生成相关的dao,配置等代码。
4.使用数据库:
为了方便使用,会有一个专门的类去定义所有的操作数据方法,也就是crud。
插入数据:
public boolean insert(Goods goods) {
Long row = goodsDao.insert(goods);
return row > 0;
}
以上代码,传入Goods对象(Goods就是前面定义的实体类了),通过对应的dao来操作。***Dao是所有greendao数据库操作的直接发起对象。获取这个***Dao
private GoodsDao goodsDao = mDaoSession.getGoodsDao();
mDaoSession就是第二步骤里实例化的DaoSession 对象。
删除数据:
public boolean delete(Goods goods) {
goodsDao.delete(goods);
}
//删除所有数据
public boolean deleteAll() {
goodsDao.deleteAll();
}
更新数据:
public boolean update(Goods goods) {
goodsDao.update(goods);
}
查询数据:
//查询所有
public List<Goods> queryAll() {
goodsDao.detachAll();
return goodsDao.loadAll();
}
//查询所有商品的价格属性等于price的商品,以list形式返回
public List<Goods> queryByGoodsId(String price) {
goodsDao.detachAll();
return goodsDao.queryBuilder().where(goodsDao.Properties.Price.eq(price))
.list();
}
//查询商品goodsid等于id的商品。因为goodsid为主键,只会存在一条,所以可以直接返回goods对象
public Goods queryByGoodsId(Long id) {
goodsDao.detachAll();
return goodsDao.queryBuilder().where(goodsDao.Properties.GoodsId.eq(id))
.unique();
}
以上查询代码说明:
- goodsDao.detachAll():这是作为清除greendao的查询缓存。因为使用特殊的查询方式会产生缓存,可能会影响查询结果。看情况使用。
- queryBuilder().where(.....):Greendao快捷查询,可以不使用原始的sql语句构建查询语句。queryBuilder().Where()的作用等同于创建原始的sql语句,并且会在编译时加入错误检查。
- goodsDao.Properties.Price.eq(price):很好理解,就是一个条件语句,*****等于*****。
使用queryBuilder来查询的方式称作为自定义实体查询。
5.QueryBuilder 自定义实体查询Api:
or :或者。连接多个条件查询, WhereCondition类型,不能独立使用,配合where或者whereOr使用。
and:并且。连接多个条件查询, WhereCondition类型,不能独立使用,配合where或者whereOr使用。
where :添加查询条件。QueryBuilder类型,使用逻辑和向where子句添加给定的条件。
unique :执行查询并返回唯一的结果或null,返回实体对象或null。如果结果不是唯一的,则抛出dao异常。
build :构建一个可重用的查询对象,查询对象可以比创建QueryBuilder更有效地执行。说简单了就是提供缓存,如果查询参数有变化,需要对每一个改变的parameter调用setParameter方法。可以通过下标index访问parameter。unique()li里面就有使用到。
例子:
//用Query 查询出生在1970年并且first name为“Joe”的人: Query query = userDao.queryBuilder().where( Properties.FirstName.eq("Joe"), Properties.YearOfBirth.eq(1970)) .build(); List joesOf1970 = query.list(); //使用上面的查询对象,通过修改参数,不需要重新创建query,查询1977年之后出生的 Marias query.setParameter(0, "Maria"); query.setParameter(1, 1977); List mariasOf1977 = query.list();
buildCount:构建一个可重用的查询对象来计数行,类似build,只是buildCount更多用来返回一个符合条件的数量。
buildCursor:为低层android.database构建一个可重用的查询对象,为指针访问。最终数据会以游标形式返回。
buildDelete:创建一个符合条件的删除DeleteQuery类型对象。执行时,删除所有匹配的实体,但是不会将它们从缓存中分离出来。这方法可能导致会话缓存中的过期实体对象。加载时,可以返回陈旧的实体
count :作用等同于buildCount。
distinct :QueryBuilder类型。避免返回重复的实体,例如如在进行连表连接时
join:连表查询。
limit :限制查询返回的结果数量。
list :将所有的查询返回以一个list形式返回。所有的实体被加载到内存中。该结果通常是一个没有magic involved的ArrayList。使用起来最简单。
listLazy:同list。实体按照需求加载进入内存。一旦列表中的一个元素被第一次访问,它将被加载同时缓存以便以后使用。必须close。
listIterator:遍历通过需要的时候加载(lazily)获得的结果,数据没有缓存,必须close。
listLazyUncached :一个“虚拟”的实体列表:任何对列表元素的访问都会导致从数据库中加载,必须close。
offset:偏移量,跳过前几个数据。配合limit使用。
orderAsc:根据字段属性升序排序返回。需要传入排序字段参数。
orderDesc :根据字段属性降序排序返回。需要传入排序字段参数。
orderRaw:只将给定的原始SQL字符串添加到order by后面部分,为string类型参数。最终结果等同于orderAsc或者orderDesc。
orderCustom:根据给定的字段属性依照添加到order by后面的部分SQL字符串来排序。传入字段属性,排序条件两个参数。
preferLocalizedStringOrder:使用Android的嵌入式SQLite,也就是混合语句,这将支持对字符串进行本地化排序。配合orderAsc跟orderDesc一起使用的吧,
rx:build()的另一种缩写形式。可以使用RX的Observables来返回结果,使用的是io调度。(参考Rxjava下的调度器)。
rxPlain:同rx。不使用任何调度器。
uniqueOrThrow:同unique(),返回唯一实体对象,不能为null。如果返回不是唯一的或者为null了,则抛出dao异常。
stringOrderCollation:自定义使用排序字符串的使用顺序,类似 preferLocalizedStringOrder(),需要传入一个String参数。
whereOr:使用or逻辑添加查询条件,类似where。内部使用了or()逻辑。
条件逻辑api
- eq:等于逻辑,equal缩写。等价SQL语句的 =?。
- notEq:不等于。等价SQL语句的 <>。
- like:模糊查询。等价SQL语句 like ?。
- between:两者之间。等价SQL语句 between... and ... 。
- in:范围查询。等价SQL语句 in (..,...)。可传入多个参数。
- notIn:不在范围内。等价SQL语句 not in (...,...)。
- gt:大于条件,greater than的缩写。等价SQL语句 >?。
- lt:小于条件,less than的缩写。等价SQL语句 <?。
- ge:大于等于条件,greater equal的缩写。等价SQL语句 >=?。
- le:小于等于条件,less equal的缩写。等价SQL语句 <=?。
- isNull:空条件。等价SQL语句 is null 。
- isNotNull:不为空条件。等价SQL语句 is not null。