1.概述
ORM(Object Relation Mapping 即 对象关系映射),就是将面向对象编程语言里的对象与数据库关联起来的一种技术,而greenDao就是实现这种技术之一,所以说greenDao其实就是一种将java object 与SQLite Database关联起来的桥梁,它们之间的关系 如下图所示;
2.优点
greenDao可以说是当今最流行,最高效而且还在迭代的关系型数据库。而且greenDao3.0还支持RxJava操作,greenDao如此受欢迎离不开以下几点:
-
存取速度快
每秒中可以操作数千个实体 下图是几种常见关系型数据库性能比较; -
支持数据库加密
支持android原生的数据库SQLite,也支持SQLCipher(在SQLite基础上加密型数据库)。 -
轻量级
greenDao的代码库仅仅100k大小 -
激活实体
处于激活状态下的实体可以有更多操作方法 -
支持缓存
能够将使用的过的实体存在缓存中,下次使用时可以直接从缓存中取,这样可以使性能提高N个数量级 -
代码自动生成
greenDao 会根据modle类自动生成实体类(entities)和Dao对象,并且Dao对象是根据entities类量身定做的并且一 一对应。
3.配置
Project下的build.gradle文件加入
dependencies {
//greenDao生产代码插件 步骤2
classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2' // add plugin
}
Module下的build.gradle文件加入
apply plugin: 'org.greenrobot.greendao' // apply plugin 步骤3
android {
...
//greendao配置 步骤5
greendao {
//数据库版本号,升级时修改
schemaVersion 1
//生成的DAO,DaoMaster和DaoSession的包路径。默认与表实体所在的包路径相同
daoPackage 'com.example.xts.greendaodemo.db'
//生成源文件的路径。默认源文件目录是在build目录中的(build/generated/source/greendao)
targetGenDir 'src/main/java'
}
}
dependencies {
//greenDAO配置 步骤4
implementation 'org.greenrobot:greendao:3.2.2' // add library
implementation 'org.greenrobot:greendao-generator:3.2.2'
}
创建实体对象
@Entity
public class Bean {
@Id
private Long id;
private String date;
@Unique
private String key;
private int step;
....
}
注意:编写完实体类以后在实体类界面下按下Ctrl+F9(Make project),程序会自动编译生成dao文件,生成的文件一共有三个。
4.核心类
- DaoMaster
是GreenDao的入口也是greenDao顶级对象,对于一个指定的表单持有数据库对象(SQLite数据库)并且能够管理DAO类,能够创建表和删除表,其内部类OpenHelper 与DevOpenHelper是创建SQlite数据库的SQLiteOpenHelper的具体实现 - DaoSession
对于一个指定的表单可以管理所有的Dao 对象。也能够对实体类执行 insert ,load,update,refresh.delete操作。DaoSession也能跟踪 identity scope:即session查询后的实体会存在缓存中,并给该实体生成一个flag来追踪该实体,下次再次查询时会直接从缓存中取出来而不是从数据库中取出来 - DAO
能够持久访问和查询实体类,比起DaoSession有更多的持久化方法 count, loadAll,insertInt等等;Entities - 可持久化对象, 通常,实体是使用标准Java属性(如POJO或JavaBean)表示数据库行的对象。
5.注解
@Entity
告诉GreenDao 该Bean类需要持久化。只有使用@Entity注释的Bean类才能被dao类操作; @Entity可以在不使用参数下使用
- schema
指定实体的架构的名称,geenDao可以为每个架构生成独立的类集。多个实体属于不同的架构时,他们之间应该没有关联性。注意:gradle插件不适合多架构模式.
详见:https://greenrobot.org/greendao/documentation/modelling-entities/
/**
* Specifies schema name for the entity: greenDAO can generate independent sets of classes for each schema.
* Entities which belong to different schemas should <strong>not</strong> have relations.
*/
String schema() default "default";
-
active = true,
该实体属于激活状态,激活状态的实体有更新,删除,刷新方法; -
nameInDb = “AWESOME_USERS”
给这个表指定一个名字,默认情况下是名字是类名 -
indexes = { @Index(value = “name DESC”, unique = true) },
// 可以给多个属性定义索引和其他属性. -
createInDb = false,
是否使用GreenDao创建该表,默认为true,false时不创建 -
generateConstructors = true
是否所有的属性构造器都应该被生成,无参构造器总是被要求 -
generateGettersSetters = true
如果该类中没有set get方法是否自动生成 -
protobuf
把对象转换成protobuf形式的数据
@Id
一般会选择Long
属性作为Entity ID(即数据库中的主键)
autoincrement (默认 false) 表示主键会自增如果false就会使用旧值
@Index
官方解释用于两个地方:
* Can be used to:
* - specifies that the property should be indexed
* - define multi-column index through {@link Entity#indexes()}
1.定义索引的属性
2.定义多列索引在indexes()
name :不使用默认名称,自定义索引名称
value:指定字段的名称
unique : 给索引增加一个唯一约束,迫使该值唯一
@Covert
数据类型的转换
@Convert(converter = NoteTypeConverter.class, columnType = String.class)
private NoteType type;
public enum NoteType {
TEXT, LIST, PICTURE
}
public class NoteTypeConverter implements PropertyConverter<NoteType, String> {
@Override
public NoteType convertToEntityProperty(String databaseValue) {
return NoteType.valueOf(databaseValue);
}
@Override
public String convertToDatabaseValue(NoteType entityProperty) {
return entityProperty.name();
}
}
@NotNUll
不能为null
@OrderBy
排序行为 “propertyA DESC, propertyB ASC”
@Propertry
定义属性名称 String nameInDb() default “”;
@Transient
禁止修饰的字段生成表里得列
@Unique
修改对象的数据唯一性
@ToOne
建立一对一 ( 1 : 1) 关系
@Entity
public class Order {
@Id
private Long id;
private long customerId;
@ToOne(joinProperty = "customerId")
private Customer customer;
}
@Entity
public class Customer {
@Id
private Long id;
}
@ToMany
建立一对多 (1:N ) 关系
@Entity
public class Customer {
@Id
private Long id;
@ToMany(referencedJoinProperty = "customerId")
@OrderBy("date ASC")
private List orders;
}
@Entity
public class Order {
@Id private Long id;
private Date date;
private long customerId;
}
@JoinEntity
建立多对多(N : M)关系
@Entity
public class Product {
@Id private Long id;
@ToMany
@JoinEntity(
entity = JoinProductsWithOrders.class,
sourceProperty = "productId",
targetProperty = "orderId"
)
private List ordersWithThisProduct;
}
@Entity
public class JoinProductsWithOrders {
@Id private Long id;
private Long productId;
private Long orderId;
}
@Entity
public class Order {
@Id private Long id;
}
@JoinProperty
主要适用与ToMany
@Entity
public class User {
@Id private Long id;
@Unique private String authorTag;
@ToMany(joinProperties = { @JoinProperty(name = "authorTag", referencedName = "ownerTag")
})
private List<Site> ownedSites;
}
@Entity
public class Site {
@Id private Long id;
@NotNull private String ownerTag;
}
@Keep
修饰字段和方法,类型在重新运行生成对象的时候保持不变
6.数据库初始化及操作
6.1初始化
创建一个application类,在application中完成DaoSession的初始化,避免以后重复初始化,便于使用。
public class BaseApp extends Application {
private static BaseApp sInstance;
private DaoMaster.DevOpenHelper mHelper;
private DaoMaster mDaoMaster;
private DaoSession mDaoSession;
@Override
public void onCreate() {
super.onCreate();
sInstance = this;
setDatabase();
}
/**
* 设置greenDao
*/
private void setDatabase() {
//通过DaoMaster内部类DevOpenHelper可以获取一个SQLiteOpenHelper 对象
// 可能你已经注意到了,你并不需要去编写「CREATE TABLE」这样的 SQL 语句,因为 greenDAO 已经帮你做了。
// 注意:默认的 DaoMaster.DevOpenHelper 会在数据库升级时,删除所有的表,意味着这将导致数据的丢失。
// 所以,在正式的项目中,你还应该做一层封装,来实现数据库的安全升级。
// 此处MyDb表示数据库名称 可以任意填写
mHelper = new DaoMaster.DevOpenHelper(this, "MyDb", null);
SQLiteDatabase db = mHelper.getWritableDatabase();
mDaoMaster = new DaoMaster(db);
mDaoSession = mDaoMaster.newSession();
}
public static BaseApp getInstance(){
return sInstance;
}
public DaoSession getDaoSession(){
return mDaoSession;
}
}
//获取xxxDao对象
private BeanDao mBeanDao = BaseApp.getInstance().getDaoSession().getBeanDao();
6.1 插入数据
//插入一条数据
//mBeanDao.insert(new Bean(...));
//插入多条数据
//mBeanDao.insertInTx();
//插入或者替换,如果不存在就插入,存在就修改(insert+update)
//mBeanDao.insertOrReplace(new Bean(...));
//插入或替换多条数据
//mBeanDao.insertOrReplaceInTx(beans);
6.2 删除数据
//删除一条数据
mBeanDao.delete(new Bean(100l, date, 12+"",10));
//删除一条数据,根据key也就是id
//mBeanDao.deleteByKey();
//删除所有数据
// mBeanDao.deleteAll();
//删除一组数据(对象)
//mBeanDao.deleteInTx();
//删除一组数据(根据id)
//mBeanDao.deleteByKeyInTx();
6.3 修改数据
//更新一条数据
//mBeanDao.update(new Bean(1l, date, 1800));
//更新一组数据,没有对应id的不做处理
ArrayList beans = new ArrayList<>();
for (int i = 0; i < 5; i++) {
beans.add(new Bean((long)i,new Date().toString(),i+10+"",i+100));
}
mBeanDao.updateInTx(beans);
6.4 查询数据
//查询所有
//List<Bean> list = mBeanDao.queryBuilder().list();
List<Bean> list = mBeanDao.loadAll();
//精确查找
Bean unique = mBeanDao.queryBuilder().where(BeanDao.Properties.Key.eq("2")).unique();
//精确查找
/*List<Bean> list2 = mBeanDao.queryBuilder().where(BeanDao.Properties.Step.eq(100)).list();
*/
//模糊查找,查找以1打头的key
/*List<Bean> list2 = mBeanDao.queryBuilder().where(BeanDao.Properties.Key.like("1%")).list();
*/
//区间查询
//大于gt()
List<Bean> list2 = mBeanDao.queryBuilder().where(BeanDao.Properties.Step.gt(102)).list();
//大于等于ge()
//小于 lt()
//小于等于le()
//介于中间between(100,102)
//查询大于step 大于102 的数据,并按照id升序排列
List<Bean> list2 = mBeanDao.queryBuilder().where(BeanDao.Properties.Step.
gt(102))
.orderAsc(BeanDao.Properties.Id).list();
//orderDesc降序排列
- eq():==
- noteq():!=
- gt(): >
- lt():<
- ge:>=
- le:<=
- like():包含
- between:俩者之间
- in:在某个值内
- notIn:不在某个值内
6.5 分页查询
limit(int): 限制查询的数量;
offset(int): 每次返回的数量; offset不能单独使用;
6.6 查询与LazyList类:
list() 缓存查询结果;list()类型一般为ArrayList
listLazy() 懒查询,只有当调用list()中的实体对象时才会执行查询操作并且只缓存第一次被查询的结果,需要关闭
listlazyUncached() 懒查询,只有当调用list()中的实体对象时才会执行查询操作并且不缓存;
listIterator() 对查询结果进行遍历,不缓存,需要关闭;
后面三个方法是LazyList类中的方法,LazyList为了执行不同的缓存策略其内部持有数据库的cursor对象;一般情况下这三个方法执行完毕后会自动关闭cursor;但是防止在还没有执行完查询结果时,对象被终结cursor还是无法被关闭的情况发生,需要手动关闭close();